def eval_infix_expression(operator: str, lhs: monkey_obj.Object, rhs: monkey_obj.Object) -> monkey_obj.Object: if isinstance(lhs, monkey_obj.Integer) and isinstance( rhs, monkey_obj.Integer): return eval_integer_infix_expression(operator, lhs, rhs) elif type(lhs) != type(rhs): return monkey_obj.Error( f"type mismatch: {lhs.object_type()} {operator} {rhs.object_type()}" ) elif isinstance(lhs, monkey_obj.String) and isinstance( rhs, monkey_obj.String): if operator != "+": return monkey_obj.Error( f"unknown operator: {lhs.object_type()} {operator} {rhs.object_type()}" ) return monkey_obj.String(value=lhs.value + rhs.value) elif operator == "==": return native_bool_to_boolean_object(lhs == rhs) elif operator == "!=": return native_bool_to_boolean_object(lhs != rhs) return monkey_obj.Error( f"unknown operator: {lhs.object_type()} {operator} {rhs.object_type()}" )
def len_builtin(*args): if len(args) != 1: return object.Error( 'wrong number of arguments, got= {}, want = 1'.format(len(args))) if type(args[0]) is object.String: return object.Integer(value=len(args[0].value)) else: return object.Error("argument to 'len' not supported, got {}".format( args[0].object_type))
def _builtin_push(args: List[monkey_obj.Object]) -> monkey_obj.Object: if len(args) != 2: return monkey_obj.Error( f"wrong number of arguments. got={len(args)}, want=2") arr, obj = args if not isinstance(arr, monkey_obj.Array): return monkey_obj.Error( f"argumetn to `push` must be ARRAY, got {type(arr)}") return monkey_obj.Array(arr.elements + [obj])
def _builtin_len(args: List[monkey_obj.Object]) -> monkey_obj.Object: if len(args) != 1: return monkey_obj.Error( f"wrong number of arguments. got={len(args)}, want=1") item = next(iter(args)) if isinstance(item, monkey_obj.String): return monkey_obj.Integer(value=len(item.value)) elif isinstance(item, monkey_obj.Array): return monkey_obj.Integer(value=len(item.elements)) else: return monkey_obj.Error( f"argument to `len` not supported, got {item.object_type()}")
def eval_infix_expression(operator, left, right): if type(left) is object.Integer and type(right) is object.Integer: return eval_integer_infix_expression(operator, left, right) if type(left) is object.String and type(right) is object.String: return eval_string_infix_expression(operator, left, right) elif operator == '==': return native_bool_to_boolean_object(left == right) elif operator == '!=': return native_bool_to_boolean_object(left != right) elif type(left) != type(right): return object.Error("type mismatch: {} {} {}".format(left.object_type, operator, right.object_type)) else: return object.Error(message="unknown operator: {} {} {}".format(left.object_type, operator, right.object_type))
def _builtin_rest(args: List[monkey_obj.Object]) -> monkey_obj.Object: if len(args) != 1: return monkey_obj.Error( f"wrong number of arguments. got={len(args)}, want=1") item = next(iter(args)) if not isinstance(item, monkey_obj.Array): return monkey_obj.Error( f"argumetn to `rest` must be ARRAY, got {type(item)}") if len(item.elements) > 0: return monkey_obj.Array(item.elements[1:]) return monkey_obj.NULL
def eval_prefix_expression(operator: str, rhs=monkey_obj.Object) -> monkey_obj.Object: if operator == "!": return eval_bang_operator(rhs) elif operator == "-": return eval_minus_prefix_operator(rhs) else: return monkey_obj.Error( f"unknown operator: {operator}{rhs.object_type()}")
def eval_identifier(node: ast.Identifier, env: object.Environment): val = env.get(node.value) if val is not None: return val if node.value in builtins: return builtins[node.value] return object.Error("identifier not found: {}".format(node.token.literal))
def eval_identifier(node: ast.Identifier, env): val = env.get(node.value) if val is not None: return val builtin = builtins.get(node.value) if builtin is not None: return builtin return monkey_obj.Error(f"identifier not found: {node.value}")
def apply_function(fun, arguments): if type(fun) is object.Function: extended_env = extend_function_env(fun, arguments) evaluated = eval(fun.body, extended_env) if type(evaluated) is object.ReturnValue: return evaluated.value return evaluated elif type(fun) is object.Builtin: return fun.fn(*arguments) return object.Error("not a function")
def eval_index_expression(left: monkey_obj.Object, index: monkey_obj.Object) -> monkey_obj.Object: if isinstance(left, monkey_obj.Array) and isinstance( index, monkey_obj.Integer): return eval_array_index_expression(left, index) elif isinstance(left, monkey_obj.Hash): return eval_hash_index_expression(left, index) else: return monkey_obj.Error(f"index operator not supported: {type(left)}")
def apply_function(fn: monkey_obj.Object, args: List[monkey_obj.Object]) -> monkey_obj.Object: if isinstance(fn, monkey_obj.Function): func_environment = { param.value: args[index] for index, param in enumerate(fn.params) } evaluated = Eval(fn.body, ChainMap(func_environment, fn.env)) return unwrap_return_value(evaluated) elif isinstance(fn, monkey_obj.Builtin): return fn.fn(args) else: return monkey_obj.Error(f"not a function: {type(fn)}")
def eval_integer_infix_expression( operator: str, lhs: monkey_obj.Integer, rhs: monkey_obj.Integer) -> monkey_obj.Object: if operator == "+": return monkey_obj.Integer(value=lhs.value + rhs.value) elif operator == "-": return monkey_obj.Integer(value=lhs.value - rhs.value) elif operator == "*": return monkey_obj.Integer(value=lhs.value * rhs.value) elif operator == "/": return monkey_obj.Integer(value=lhs.value // rhs.value) elif operator == "<": return native_bool_to_boolean_object(lhs.value < rhs.value) elif operator == ">": return native_bool_to_boolean_object(lhs.value > rhs.value) elif operator == "==": return native_bool_to_boolean_object(lhs.value == rhs.value) elif operator == "!=": return native_bool_to_boolean_object(lhs.value != rhs.value) else: return monkey_obj.Error( f"unknown operator: {lhs.object_type()} {operator} {rhs.object_type()}" )
def eval_minus_prefix_operator(rhs: monkey_obj.Object) -> monkey_obj.Object: if not isinstance(rhs, monkey_obj.Integer): return monkey_obj.Error(f"unknown operator: -{rhs.object_type()}") return monkey_obj.Integer(value=-(rhs.value))
def eval_minus_prefix_operator_expression(right): if type(right) is not object.Integer: return object.Error(message="unknown operator: {}{}".format("-", right.object_type)) else: return object.Integer(value=-right.value)
def eval_string_infix_expression(operator, left, right): if operator is not "+": return object.Error("unknown operator: {} {} {}".format(left.object_type, operator, right.object_type)) # use python string concat underneath return object.String(value=left.value + right.value)
def newError(template: str, a: Tuple[Any, ...]) -> object.Error: return object.Error(Message=template % a)
def new_error(format: str, *a) -> object.Error: return object.Error(format.format(*a))