def visit_InfixExpression(self, node, env): left = self.visit(node.left, env) if is_error(left): return left right = self.visit(node.right, env) if is_error(right): return right if isinstance(left, Integer) and isinstance(right, Integer): return eval_integer_infix_expression(node.operator, left, right) elif isinstance(left, String) and isinstance(right, String): return eval_string_infix_expression(node.operator, left, right) elif node.operator == "==": return to_bool(left.value == right.value) elif node.operator == "!=": return to_bool(left.value != right.value) elif left.type() != right.type(): return Error( f"type mismatch: {left.type().value} {node.operator} {right.type().value}" ) else: return Error( f"unknown operator: {left.type().value} {node.operator} {right.type().value}" )
def push_fn(args): if len(args) != 2: return Error(f"wrong number of arguments. got={len(args)}, want=2") if not isinstance(args[0], Array): return Error( f"argument to 'push' must be ARRAY, got {args[0].type().value}") new_arr = list(args[0].elements) new_arr.append(args[1]) return Array(new_arr)
def rest_fn(args): if len(args) != 1: return Error(f"wrong number of arguments. got={len(args)}, want=1") if not isinstance(args[0], Array): return Error( f"argument to 'rest' must be ARRAY, got {args[0].type().value}") arr = args[0].elements return Array(list(arr[1:])) if len(arr) > 0 else NULL
def first_fn(args): if len(args) != 1: return Error(f"wrong number of arguments. got={len(args)}, want=1") if not isinstance(args[0], Array): return Error( f"argument to 'first' must be ARRAY, got {args[0].type().value}") arr = args[0] return arr.elements[0] if len(arr.elements) > 0 else NULL
def len_fn(args): if len(args) != 1: return Error(f"wrong number of arguments. got={len(args)}, want=1") arg = args[0] if isinstance(arg, String): return Integer(len(arg.value)) elif isinstance(arg, Array): return Integer(len(arg.elements)) else: return Error( f"argument to 'len' not supported, got {arg.type().value}")
def eval_index_expression(left, index): if isinstance(left, Array) and isinstance(index, Integer): return eval_array_index_expression(left, index) elif isinstance(left, Hash): return eval_hash_index_expression(left, index) else: return Error(f"index operator not supported {left.type().value}")
def eval_prefix_expression(operator, right): if operator == "!": return eval_bang_operator_expression(right) elif operator == "-": return eval_minus_prefix_operator_expression(right) else: return Error(f"unknown operator: {operator}{right.type().value}")
def visit_Identifier(self, node, env): val = env.get(node.value) if val is not None: return val val = BUILTIN.get(node.value) if val is not None: return val return Error(f"identifier not found: {node.value}")
def apply_function(self, fn, args): if isinstance(fn, Function): extended_env = extend_function_env(fn, args) if isinstance(extended_env, Error): return extended_env evaluated = self.visit(fn.body, extended_env) if evaluated is None: return None return unwrap_return_value(evaluated) elif isinstance(fn, BuiltIn): return fn.function(args) else: return Error(f"not a function: {fn}")
def visit_HashLiteral(self, node, env): pairs = {} for key_node, val_node in node.pairs.items(): key = self.visit(key_node, env) if is_error(key): return key if not isinstance(key, Hashable): return Error(f"unusable as hash key: {key.type().value}") value = self.visit(val_node, env) if is_error(value): return value hashed_key = key.hash_key() pairs[hashed_key] = HashPair(key, value) return Hash(pairs)
def eval_integer_infix_expression(operator, left, right): left_val = left.value right_val = right.value if operator == "+": return Integer(left_val + right_val) elif operator == "-": return Integer(left_val - right_val) elif operator == "*": return Integer(left_val * right_val) elif operator == "/": return Integer(left_val / right_val) elif operator == "<": return to_bool(left_val < right_val) elif operator == ">": return to_bool(left_val > right_val) elif operator == "==": return to_bool(left_val == right_val) elif operator == "!=": return to_bool(left_val != right_val) else: return Error( f"unknown operator: {left.type().value} {operator} {right.type().value}" )
def eval_hash_index_expression(hash_obj, index): if not isinstance(index, Hashable): return Error(f"unusable as hash key: {index.type().value}") pair = hash_obj.pairs.get(index.hash_key()) return pair.value if pair is not None else NULL
def eval_string_infix_expression(operator, left, right): if operator != "+": return Error( f"unknown operator: {left.type().value} {operator} {right.type().value}" ) return String(left.value + right.value)
def eval_minus_prefix_operator_expression(right): if not isinstance(right, Integer): return Error(f"unknown operator: -{right.type().value}") return Integer(-right.value)