def join_fn(args: List[objects.Object]) -> objects.Object: if len(args) != 2: return wrong_number_of_args(actual=len(args), expected=2) if args[0].object_type() != ObjectType.ARRAY_OBJ: return objects.Error( f"first argument to `join` must be ARRAY, got {args[0].object_type().value}" ) if args[1].object_type() != ObjectType.STRING_OBJ: return objects.Error( f"second argument to `join` must be STRING, got {args[1].object_type().value}" ) elements = args[0].elements if len(elements) == 0: return objects.String("") if len(elements) == 1: return objects.String(str(elements[0])) max_ = len(elements) - 1 out = f"" for i, el in enumerate(elements): out += str(el) if i < max_: out += str(args[1]) return objects.String(out)
def evaluate_string_infix_expression(operator: str, left: objects.Object, right: objects.Object) -> objects.Object: if operator == "+": return objects.String(left.value + right.value) elif operator == "==": return objects.Boolean(left.value == right.value) elif operator == "!=": return objects.Boolean(left.value != right.value) return new_error( f"unknown operator: {left.object_type().value} {operator} {right.object_type().value}" )
def reverse_fn(args: List[objects.Object]) -> objects.Object: if len(args) != 1: return wrong_number_of_args(actual=len(args), expected=1) src = args[0] if src.object_type() == ObjectType.ARRAY_OBJ: reversed_elements = src.elements[::-1] return objects.Array(reversed_elements) elif src.object_type() == ObjectType.STRING_OBJ: return objects.String(src.value[::-1]) return objects.Error( f"argument to `reverse` must be ARRAY or STRING, got {src.object_type().value}" )
def split_fn(args: List[objects.Object]) -> objects.Object: if len(args) != 2: return wrong_number_of_args(actual=len(args), expected=2) string = args[0] delimiter = args[1] if not isinstance(string, objects.String): return objects.Error( f"first argument to `split` must be STRING, got {string.object_type().value}({args[0]})" ) if not isinstance(delimiter, objects.String): return objects.Error( f"second argument to `split` must be STRING, got {delimiter.object_type().value}({args[1]})" ) elements = string.value.split(delimiter.value) strElements = [objects.String(el) for el in elements] return objects.Array(strElements)
def str_fn(args: List[objects.Object]) -> objects.Object: if len(args) != 1: return wrong_number_of_args(actual=len(args), expected=1) return objects.String(str(args[0]))
def type_fn(args: List[objects.Object]) -> objects.Object: if len(args) != 1: return wrong_number_of_args(actual=len(args), expected=1) return objects.String(args[0].object_type().value)
def exported_hash(self) -> objects.Hash: pairs = {} for k, v in self.store.items(): s = objects.String(k) pairs[s.hash_key()] = objects.HashPair(s, v) return objects.Hash(pairs)
def evaluate(node: ast.Node, env: objects.Environment) -> objects.Object: # print(f"EVALUATING: node:<{node}>, type: <{type(node)}>") if isinstance(node, ast.Program): return evaluate_program(node, env) elif isinstance(node, ast.ExpressionStatement): return evaluate(node.expression, env) elif isinstance(node, ast.BlockStatement): return evaluate_block_statement(node, env) elif isinstance(node, ast.ReturnStatement): value = evaluate(node.return_value, env) if is_error(value): return value return objects.ReturnValue(value) elif isinstance(node, ast.LetStatement): val = evaluate(node.value, env) if is_error(val): return val env.set(node.name.value, val) elif isinstance(node, ast.IntegerLiteral): return objects.Integer(node.value) elif isinstance(node, ast.StringLiteral): return objects.String(node.value) elif isinstance(node, ast.ArrayLiteral): elements = evaluate_expressions(node.elements, env) if len(elements) == 1 and is_error(elements[0]): return elements[0] return objects.Array(elements) elif isinstance(node, ast.HashLiteral): return evaluate_hash_literal(node, env) elif isinstance(node, ast.Boolean): if node.value: return objects.Boolean(True) return objects.Boolean(False) elif isinstance(node, ast.PrefixExpression): right = evaluate(node.right, env) if is_error(right): return right return evaluate_prefix_expression(node.operator, right) elif isinstance(node, ast.InfixExpression): left = evaluate(node.left, env) if is_error(left): return left right = evaluate(node.right, env) if is_error(right): return right return evaluate_infix_expression(node.operator, left, right) elif isinstance(node, ast.IfExpression): return evaluate_if_expression(node, env) elif isinstance(node, ast.Identifier): return evaluate_identifier(node, env) elif isinstance(node, ast.FunctionLiteral): params = node.parameters body = node.body return objects.Function(params, body, env) elif isinstance(node, ast.CallExpression): function = evaluate(node.function, env) if is_error(function): return function args = evaluate_expressions(node.arguments, env) if len(args) == 1 and is_error(args[0]): return args[0] return apply_function(function, args) elif isinstance(node, ast.IndexExpression): left = evaluate(node.left, env) if is_error(left): return left index = evaluate(node.index, env) if is_error(index): return index return evaluate_index_expression(left, index) elif isinstance(node, ast.ImportExpression): return evaluate_import_expression(node, env) elif isinstance(node, ast.WhileStatement): return evaluate_while_statement(node, env) return None