def eval_char_string_infix(op, left, right): l = left.value r = right.value if op == "+": return obj.String(l + r) if op == "-": return obj.String([ch for ch in l if ch != r]) return err("unknown operator: %s %s %s" % (left.type, op, right.type))
def eval_infix(op, left, right, ctx): if isinstance(left, obj.Collection) and isinstance(right, obj.Collection): return eval_collection_infix(op, left, right, ctx) # Boolean operators if op == "&&": return bool_obj(is_truthy(left) and is_truthy(right)) if op == "||": return bool_obj(is_truthy(left) or is_truthy(right)) if op == "==": return bool_obj(left == right) if op == "!=": return bool_obj(left != right) if op == "?": return right if left == NULL else left if type(left) == obj.Number and type(right) == obj.Number: return eval_number_infix(op, left, right) if (type(left) == obj.Char and type(right) == obj.Char or type(left) == obj.String and type(right) == obj.Char or type(left) == obj.Char and type(right) == obj.String): return eval_char_string_infix(op, left, right) if (type(left) == obj.Char and type(right) == obj.Number): return obj.String(left.value * math.floor(right.value)) if isinstance(left, obj.Collection) and type(right) == obj.Number: result = [] elems = left.get_elements() n = math.floor(right.value) for _ in range(n): result += elems[:] return type(left)(result) return err("unknown operator: %s %s %s" % (left.type, op, right.type))
def format_string_with_args(args, context): fmt = args["format"].value items = tuple(args["args"].get_elements()) try: return obj.String(fmt % items) except TypeError: return err("Wrong number of arguments to format `%s`" % fmt)
def printf_format_with_args(args, context): fmt = args["format"].value items = tuple(args["args"].get_elements()) try: print(obj.String(fmt % items)) except TypeError: return err("Wrong number of arguments to format `%s`" % fmt, "TypeError") return NULL
def evaluate(node, ctx): t = type(node) # Constructs if t == ast.Program: return eval_program(node, ctx) if t == ast.BlockStatement: return eval_block_stmt(node, ctx) if t == ast.ExpressionStatement: return evaluate(node.expr, ctx) if t == ast.IfExpression: return eval_if(node, ctx) if t == ast.WhileLoop: return eval_while_loop(node, ctx) if t == ast.ForLoop: return eval_for_loop(node, ctx) # Literals if t == ast.Null: return NULL if t == ast.Number: return obj.Number(node.value) if t == ast.String: return obj.String(node.value) if t == ast.Char: return obj.Char(node.value) if t == ast.Boolean: return bool_obj(node.value) if t == ast.Identifier: return eval_id(node, ctx) if t == ast.BlockLiteral: return eval_block(node, ctx) if t == ast.NextStatement: return NEXT if t == ast.BreakStatement: return BREAK # Functions if t == ast.FunctionDefinition: return eval_function_def(node, ctx) if t == ast.FunctionCall: return eval_function_call(node, ctx) if t == ast.Array: elements = eval_exprs(node.elements, ctx) if len(elements) == 1 and is_err(elements[0]): return elements[0] return obj.Array(elements) if t == ast.Object: keys = eval_exprs(node.pairs.keys(), ctx) if len(keys) == 1 and is_err(keys[0]): return keys[0] values = eval_exprs(node.pairs.values(), ctx) if len(values) == 1 and is_err(values[0]): return values[0] return obj.Object(list(zip(keys, values))) if t == ast.Tuple: elements = eval_exprs(node.value, ctx) if len(elements) == 1 and is_err(elements[0]): return elements[0] return obj.Tuple(elements) # More complex nodes if t == ast.ReturnStatement: if node.value == None: return obj.ReturnValue(NULL) val = evaluate(node.value, ctx) return val if is_err(val) else obj.ReturnValue(val) if t == ast.PrefixExpression: right = evaluate(node.right, ctx) return right if is_err(right) else eval_prefix(node.operator, right) if t == ast.InfixExpression: left = evaluate(node.left, ctx) if is_err(left): return left right = evaluate(node.right, ctx) if is_err(right): return right return eval_infix(node.operator, left, right, ctx) if t == ast.AssignExpression: right = evaluate(node.value, ctx) return right if is_err(right) else eval_assign(node.name, right, ctx) if t == ast.DeclareExpression: right = evaluate(node.value, ctx) return right if is_err(right) else eval_declare(node.name, right, ctx) return err("evaluation for %s not yet implemented" % t)
def input_with_prompt_prompt(args, context): try: return obj.String(input(args["prompt"])) except (KeyboardInterrupt, EOFError): return NULL
def _input(args, context): try: return obj.String(input()) except (KeyboardInterrupt, EOFError): return NULL