def rest_fn(args: List[objects.Object]) -> objects.Object: if len(args) != 1: return wrong_number_of_args(actual=len(args), expected=1) if args[0].object_type() != ObjectType.ARRAY_OBJ: return objects.Error( f"argument to `rest` must be ARRAY, got {args[0].object_type().value}" ) arr = args[0] if len(arr.elements): return objects.Array(arr.elements[1:]) return objects.Array([])
def evaluate_array_infix_expression(operator: str, left: objects.Object, right: objects.Object) -> objects.Object: if operator != "+": return new_error( f"unknown operator: {left.object_type().value} {operator} {right.object_type().value}" ) return objects.Array(left.elements + right.elements)
def push_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 `push` must be ARRAY, got {args[0].object_type().value}" ) arr = args[0] new_elements = list(arr.elements) new_elements.append(args[1]) return objects.Array(new_elements)
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 values_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.HASH_OBJ: hash_ = src elif src.object_type() == ObjectType.MODULE: if not isinstance(src, objects.Module): return objects.Error( f"argument to `values` must be HASH or MODULE, got {src.object_type().value}({src})" ) hash_ = module.attrs else: return objects.Error( f"argument to `values` must be HASH or MODULE, got {src.object_type().value}({src})" ) values = [hash_pair.value for hash_key, hash_pair in hash_.pairs.items()] return objects.Array(values)
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