Beispiel #1
0
 def _eval_infix_expression(
         self, operator: str, left: monkey_object.MonkeyObject,
         right: monkey_object.MonkeyObject) -> monkey_object.MonkeyObject:
     if left.type_() == monkey_object.ObjectType.INTEGER and \
        right.type_() == monkey_object.ObjectType.INTEGER:
         return self._eval_integer_infix_expression(operator, left, right)
     if left.type_() == monkey_object.ObjectType.STRING and \
        right.type_() == monkey_object.ObjectType.STRING:
         return self._eval_string_infix_expression(operator, left, right)
     # For booleans we can use reference comparison to check for equality. It
     # works because of our singleton True and False instances but wouldn't
     # work for integers since they aren't singletons. 5 == 5 would be false
     # when comparing references. To compare integer we must unwrap the
     # integer stored inside each Integer object and compare their values.
     if operator == "==":
         return self._native_bool_to_boolean_object(left == right)
     if operator == "!=":
         return self._native_bool_to_boolean_object(left != right)
     if left.type_() != right.type_():
         return monkey_object.Error(
             f"type mismatch: {left.type_().value} {operator} {right.type_().value}"
         )
     return monkey_object.Error(
         f"unknown operator: {left.type_().value} {operator} {right.type_().value}"
     )
Beispiel #2
0
def _len(args: List[monkey_object.MonkeyObject]) -> monkey_object.MonkeyObject:
    if len(args) != 1:
        return monkey_object.Error(
            f"wrong number of arguments. Got {len(args)}, want 1")
    if isinstance(args[0], monkey_object.String):
        return monkey_object.Integer(len(args[0].value))
    if isinstance(args[0], monkey_object.Array):
        return monkey_object.Integer(len(args[0].elements))
    return monkey_object.Error(
        f"argument to 'len' not supported. Got {args[0].type_().value}")
Beispiel #3
0
def _push(args: List[monkey_object.MonkeyObject]) -> monkey_object.MonkeyObject:
    if len(args) != 2:
        return monkey_object.Error(
            f"wrong number of arguments. Got {len(args)}, want 2")
    if args[0].type_() != monkey_object.ObjectType.ARRAY:
        return monkey_object.Error(
            f"argument to 'push' must be ARRAY. Got {args[0].type_().value}")
    array = cast(monkey_object.Array, args[0])
    # Monkey arrays are immutable so we must clone the underlying Python type
    new_elements = array.elements.copy()
    new_elements.append(args[1])
    return monkey_object.Array(new_elements)
Beispiel #4
0
def _first(args: List[monkey_object.MonkeyObject]) -> monkey_object.MonkeyObject:
    from evaluator import Evaluator
    if len(args) != 1:
        return monkey_object.Error(
            f"wrong number of arguments. Got {len(args)}, want 1")
    if args[0].type_() != monkey_object.ObjectType.ARRAY:
        return monkey_object.Error(
            f"argument to 'first' must be ARRAY. Got {args[0].type_().value}")
    array = cast(monkey_object.Array, args[0])
    if len(array.elements) > 0:
        return array.elements[0]
    return Evaluator.null
Beispiel #5
0
def _rest(args: List[monkey_object.MonkeyObject]) -> monkey_object.MonkeyObject:
    from evaluator import Evaluator
    if len(args) != 1:
        return monkey_object.Error(
            f"wrong number of arguments. Got {len(args)}, want 1")
    if args[0].type_() != monkey_object.ObjectType.ARRAY:
        return monkey_object.Error(
            f"argument to 'rest' must be ARRAY. Got {args[0].type_().value}")
    array = cast(monkey_object.Array, args[0])
    length = len(array.elements)
    if length > 0:
        new_elements = array.elements[1:].copy()
        return monkey_object.Array(new_elements)
    return Evaluator.null
Beispiel #6
0
 def _eval_integer_infix_expression(self, operator: str, left: monkey_object.MonkeyObject,
                                    right: monkey_object.MonkeyObject) -> \
                                    monkey_object.MonkeyObject:
     # Called from _eval_infix_expression which type type assertion. mypy
     # cannot infer, so we have to explicitly guard with asserts.
     assert isinstance(left, monkey_object.Integer)
     assert isinstance(right, monkey_object.Integer)
     left_val = left.value
     right_val = right.value
     if operator == "+":
         return monkey_object.Integer(left_val + right_val)
     if operator == "-":
         return monkey_object.Integer(left_val - right_val)
     if operator == "*":
         return monkey_object.Integer(left_val * right_val)
     if operator == "/":
         return monkey_object.Integer(left_val // right_val)
     if operator == "<":
         return self._native_bool_to_boolean_object(left_val < right_val)
     if operator == ">":
         return self._native_bool_to_boolean_object(left_val > right_val)
     if operator == "==":
         return self._native_bool_to_boolean_object(left_val == right_val)
     if operator == "!=":
         return self._native_bool_to_boolean_object(left_val != right_val)
     return monkey_object.Error(
         f"unknown operator: {left.type_().value} {operator} {right.type_().value}"
     )
Beispiel #7
0
 def _eval_minus_prefix_operator_expression(self, right: monkey_object.MonkeyObject) -> \
                                            monkey_object.MonkeyObject:
     if right.type_() != monkey_object.ObjectType.INTEGER:
         return monkey_object.Error(
             f"unknown operator: -{right.type_().value}")
     value = cast(monkey_object.Integer, right).value
     return monkey_object.Integer(-value)
Beispiel #8
0
 def _eval_identifier(self, node: ast.Identifier, env: environment.Environment) -> \
                      monkey_object.MonkeyObject:
     value = env.get(node.value)
     if value is not None:
         return value
     if node.value in builtin.builtins:
         return builtin.builtins[node.value]
     return monkey_object.Error(f"identifier not found: {node.value}")
Beispiel #9
0
 def _eval_hash_index_expression(self, expr: monkey_object.MonkeyObject,
                                 index: monkey_object.MonkeyObject) -> \
                                 monkey_object.MonkeyObject:
     if not isinstance(index, monkey_object.Hashable):
         return monkey_object.Error(
             f"unusable as hash key: {index.type_().value}")
     if not index.hash_key() in expr.pairs:
         return Evaluator.null
     return expr.pairs[index.hash_key()].value
Beispiel #10
0
 def _eval_prefix_expression(self, operator: str,
                             right: monkey_object.MonkeyObject) -> \
                             monkey_object.MonkeyObject:
     if operator == "!":
         return self._eval_bang_operator_expression(right)
     if operator == "-":
         return self._eval_minus_prefix_operator_expression(right)
     return monkey_object.Error(
         f"unknown operator: {operator}{right.type_().value}")
Beispiel #11
0
 def _eval_index_expression(self, left: monkey_object.MonkeyObject,
                            index: monkey_object.MonkeyObject) -> \
                            monkey_object.MonkeyObject:
     if left.type_() == monkey_object.ObjectType.ARRAY and \
        index.type_() == monkey_object.ObjectType.INTEGER:
         return self._eval_array_index_expression(left, index)
     if left.type_() == monkey_object.ObjectType.HASH:
         return self._eval_hash_index_expression(left, index)
     return monkey_object.Error(
         f"index operator not supported: {left.type_().value}")
Beispiel #12
0
 def _apply_function(
         self, function: monkey_object.MonkeyObject,
         args: List[monkey_object.MonkeyObject]
 ) -> monkey_object.MonkeyObject:
     if isinstance(function, monkey_object.Function):
         extended_env = self._extend_function_environment(function, args)
         evaluated = self.eval(function.body, extended_env)
         return self._unwrap_return_value(evaluated)
     if isinstance(function, monkey_object.Builtin):
         return function.function(args)
     return monkey_object.Error(f"not a function: {function.type_().value}")
Beispiel #13
0
 def _eval_string_infix_expression(self, operator: str,
                                   left: monkey_object.MonkeyObject,
                                   right: monkey_object.MonkeyObject) -> \
                                   monkey_object.MonkeyObject:
     assert isinstance(left, monkey_object.String)
     assert isinstance(right, monkey_object.String)
     if operator != "+":
         return monkey_object.Error(
             f"unknown operator: {left.type_().value} {operator} {right.type_().value}"
         )
     left_val = left.value
     right_val = right.value
     return monkey_object.String(left_val + right_val)
Beispiel #14
0
 def _eval_hash_literal(
         self, node: ast.HashLiteral,
         env: environment.Environment) -> monkey_object.MonkeyObject:
     pairs: Dict[monkey_object.HashKey, monkey_object.HashPair] = {}
     for key_node, value_node in node.pairs.items():
         key = self.eval(key_node, env)
         if self._is_error(key):
             return key
         if not isinstance(key, monkey_object.Hashable):
             return monkey_object.Error(
                 f"unusable as hash key: {key.type_().value}")
         value = self.eval(value_node, env)
         if self._is_error(value):
             return value
         hashed = key.hash_key()
         pairs[hashed] = monkey_object.HashPair(key, value)
     return monkey_object.Hash(pairs)
Beispiel #15
0
def new_error(fmt: str, *args, **kwargs) -> mobject.Error:
    return mobject.Error(fmt.format(*args, **kwargs))