Exemple #1
0
def test_hash_literals():
    input = """
    let two = "two";
    {
        "one": 10 - 9,
        two: 1 + 1,
        "thr" + "ee": 6/2,
        4: 4,
        true: 5,
        false: 6
    }
    """

    expected = {
        mobject.String(value="one").hash_key: 1,
        mobject.String(value="two").hash_key: 2,
        mobject.String(value="three").hash_key: 3,
        mobject.Integer(value=4).hash_key: 4,
        mobject.Boolean(value=True).hash_key: 5,
        mobject.Boolean(value=False).hash_key: 6
    }

    evaluated = eval_test(input)
    assert type(evaluated
                ) == mobject.Hash, f"object is not Hash, got {type(evaluated)}"
    assert len(evaluated.pairs) == len(
        expected
    ), f"hash has wrong number of pairs. got {len(evaluated.pairs)}, want {len(expected)}"

    for k, v in expected.items():
        pair = evaluated.pairs.get(k)
        assert pair is not None, f"no pair for key {k} can be found in hash"
        integer_object_test(pair.value, v)
Exemple #2
0
 def test_string_hash_key(self) -> None:
     hello1 = monkey_object.String("Hello World")
     hello2 = monkey_object.String("Hello World")
     diff1 = monkey_object.String("My name is johnny")
     diff2 = monkey_object.String("My name is johnny")
     self.assertEqual(hello1.hash_key(), hello2.hash_key())
     self.assertEqual(diff1.hash_key(), diff2.hash_key())
Exemple #3
0
 def test_hash_literals(self):
     text = """
         let two = "two";
         {
             "one": 10 - 9,
             two: 1 + 1,
             "thr" + "ee": 6 / 2,
             4: 4,
             true: 5,
             false: 6
         }
     """
     evaluated = self.eval_setup(text)
     if isinstance(evaluated, monkey_object.Error):
         print(f"ERROR: {evaluated.message}")
     assert isinstance(evaluated, monkey_object.Hash)
     expected = {
         monkey_object.String("one").hash_key(): 1,
         monkey_object.String("two").hash_key(): 2,
         monkey_object.String("three").hash_key(): 3,
         monkey_object.Integer(4).hash_key(): 4,
         TRUE.hash_key(): 5,
         FALSE.hash_key(): 6,
     }
     assert len(evaluated.pairs) == len(expected)
     for expected_pair in evaluated.pairs.values():
         pair = evaluated.pairs[expected_pair.key.hash_key()]
         self.check_integer_object(pair.value, expected_pair.value.value)
Exemple #4
0
def test_string_hash_key():
    hello1 = mobject.String(value="Hello World")
    hello2 = mobject.String(value="Hello World")
    diff1 = mobject.String(value="different string")
    diff2 = mobject.String(value="different string")

    assert hello1.hash_key == hello2.hash_key, "strings with same content have different hash keys"
    assert hello1.hash_key != diff1.hash_key, "strings with different content have same hash keys"
    assert diff1.hash_key == diff2.hash_key, "strings with same content have different hash keys"
 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)
 def test_hash_literals(self) -> None:
     source = """let two = "two";
                 {
                   "one": 10 - 9,
                   two: 1 + 1,
                   "thr" + "ee": 6 / 2,
                   4: 4,
                   true: 5,
                   false: 6
                 }"""
     evaluated = cast(monkey_object.Hash, self._test_eval(source))
     self.assertIsInstance(evaluated, monkey_object.Hash)
     expected: Dict[monkey_object.HashKey, int] = {
         monkey_object.String("one").hash_key(): 1,
         monkey_object.String("two").hash_key(): 2,
         monkey_object.String("three").hash_key(): 3,
         monkey_object.Integer(4).hash_key(): 4,
         Evaluator.true.hash_key(): 5,
         Evaluator.false.hash_key(): 6
     }
     self.assertEqual(len(evaluated.pairs), len(expected))
     for key, value in expected.items():
         pair = evaluated.pairs[key]
         self._test_integer_object(pair.value, value)
    def eval(self, node: ast.Node,
             env: environment.Environment) -> monkey_object.MonkeyObject:
        # statements
        if isinstance(node, ast.Program):
            return self._eval_program(
                cast(List[ast.BlockStatement], node.statements), env)
        if isinstance(node, ast.ExpressionStatement):
            return self.eval(node.expression, env)
        if isinstance(node, ast.BlockStatement):
            return self._eval_block_statement(
                cast(List[ast.Statement], node.statements), env)
        if isinstance(node, ast.ReturnStatement):
            value = self.eval(node.return_value, env)

            # Check for errors whenever Eval is called inside Eval in order to
            # stop errors from being passed around and bubbling up far from
            # their origin.
            if self._is_error(value):
                return value
            return monkey_object.ReturnValue(value)
        if isinstance(node, ast.LetStatement):
            value = self.eval(node.value, env)
            if self._is_error(value):
                return value
            return env.set(node.name.value, value)

        # expressions
        if isinstance(node, ast.IntegerLiteral):
            return monkey_object.Integer(node.value)
        if isinstance(node, ast.StringLiteral):
            return monkey_object.String(node.value)
        if isinstance(node, ast.Boolean):
            return self._native_bool_to_boolean_object(node.value)
        if isinstance(node, ast.PrefixExpression):
            right = self.eval(node.right, env)
            if self._is_error(right):
                return right
            return self._eval_prefix_expression(node.operator, right)
        if isinstance(node, ast.InfixExpression):
            left = self.eval(node.left, env)
            if self._is_error(left):
                return left
            right = self.eval(node.right, env)
            if self._is_error(right):
                return right
            return self._eval_infix_expression(node.operator, left, right)
        if isinstance(node, ast.IfExpression):
            return self._eval_if_expression(node, env)
        if isinstance(node, ast.Identifier):
            return self._eval_identifier(node, env)
        if isinstance(node, ast.FunctionLiteral):
            params = node.parameters
            body = node.body
            return monkey_object.Function(params, body, env)
        if isinstance(node, ast.CallExpression):
            function = self.eval(node.function, env)
            if self._is_error(function):
                return function
            args = self._eval_expressions(node.arguments, env)
            if len(args) == 1 and self._is_error(args[0]):
                return args[0]
            return self._apply_function(function, args)
        if isinstance(node, ast.ArrayLiteral):
            elements = self._eval_expressions(node.elements, env)
            if len(elements) == 1 and self._is_error(elements[0]):
                return elements[0]
            return monkey_object.Array(elements)
        if isinstance(node, ast.IndexExpression):
            left = self.eval(node.left, env)
            if self._is_error(left):
                return left
            index = self.eval(node.index, env)
            if self._is_error(index):
                return index
            return self._eval_index_expression(left, index)
        if isinstance(node, ast.HashLiteral):
            return self._eval_hash_literal(node, env)

        raise NotImplementedError
Exemple #8
0
def eval(node: ast.Node, env: mobject.Environment) -> MonkeyObject:
    typ = type(node)
    if typ == ast.Program:
        return eval_program(node, env)
    elif typ == ast.ExpressionStatement:
        return eval(node.expression, env)
    elif typ == ast.IntegerLiteral:
        return mobject.Integer(value=node.value)
    elif typ == ast.Boolean:
        return native_bool_to_boolean_object(node.value)
    elif typ == ast.StringLiteral:
        return mobject.String(value=node.value)
    elif typ == ast.Identifier:
        return eval_identifier(node, env)
    elif typ == ast.PrefixExpression:
        right = eval(node.right, env)
        if is_error(right):
            return right
        return eval_prefix_expression(node.operator, right)
    elif typ == ast.InfixExpression:
        left = eval(node.left, env)
        if is_error(left):
            return left
        right = eval(node.right, env)
        if is_error(right):
            return right
        return eval_infix_expression(node.operator, left, right)
    elif typ == ast.AssignExpression:
        value = eval(node.value, env)
        if is_error(value):
            return value
        val = env.reset(node.name.value, value)
        if val is None:
            return new_error("variable '{}' does not exist. Can't reassign",
                             node.name.value)
        return val
    elif typ == ast.BlockStatement:
        return eval_block_statement(node, env)
    elif typ == ast.IfExpression:
        return eval_if_expression(node, env)
    elif typ == ast.ForExpression:
        return eval_for_expression(node, env)
    elif typ == ast.WhileExpression:
        return eval_while_expression(node, env)
    elif typ == ast.ReturnStatement:
        val = eval(node.return_value, env)
        if is_error(val):
            return val
        return mobject.ReturnValue(val)
    elif typ == ast.BreakStatement:
        return mobject.Break()
    elif typ == ast.ContinueStatement:
        return mobject.Continue()
    elif typ == ast.LetStatement:
        val = eval(node.value, env)
        if is_error(val):
            return val
        env.set(node.name.value, val)
    elif typ == ast.FunctionLiteral:
        params = node.parameters
        body = node.body
        return mobject.Function(parameters=params, body=body, env=env)
    elif typ == ast.CallExpression:
        function = eval(node.function, env)
        if is_error(function):
            return function
        args = eval_expressions(node.arguments, env)
        if len(args) == 1 and is_error(args[0]):
            return args[0]
        return apply_function(function, args)
    elif typ == ast.ArrayLiteral:
        elements = eval_expressions(node.elements, env)
        if len(elements) == 1 and is_error(elements[0]):
            return elements[0]
        return mobject.Array(elements=elements)
    elif typ == ast.IndexExpression:
        left = eval(node.left, env)
        if is_error(left):
            return left
        index = eval(node.index, env)
        if is_error(index):
            return index
        return eval_index_expression(left, index)
    elif typ == ast.HashLiteral:
        return eval_hash_literal(node, env)
    else:
        return NULL
Exemple #9
0
def eval_string_infix_expression(operator: str, left: MonkeyObject,
                                 right: MonkeyObject) -> MonkeyObject:
    if operator != "+":
        return new_error("unknown operator: {} {} {}", left.typ, operator,
                         right.typ)
    return mobject.String(value=left.value + right.value)
Exemple #10
0
def to_str(arg: MonkeyObject) -> mobject.String:
    if arg.typ not in (mobject.STRING_OBJ, mobject.INTEGER_OBJ,
                       mobject.BOOLEAN_OBJ):
        return new_error("wrong argument type, 'to_str' does not accept {}",
                         arg.typ)
    return mobject.String(value=str(arg.value))