Ejemplo n.º 1
0
    def test_hash_literals(self):
        input = '''let two = "two";
        {
          "one": 10 - 9,
          two: 1 + 1,
          "thr" + "ee": 6 / 2,
          4: 4,
          true: 5,
          false: 6
        }'''

        evaluated = testEval(input)
        result = evaluated
        if not result:
            self.fail('Eval didn\'t return Hash. got=%s (%s)' % (evaluated, evaluated))

        expected = [
            (object.GetHashKey(object.String(Value='one')), 1),
            (object.GetHashKey(object.String(Value='two')), 2),
            (object.GetHashKey(object.String(Value='three')), 3),
            (object.GetHashKey(object.Integer(Value=4)), 4),
            (object.GetHashKey(evaluator.TRUE), 5),
            (object.GetHashKey(evaluator.FALSE), 6),
        ]

        if len(result.Pairs) != len(expected):
            self.fail('Hash has wrong num of pairs. got=%s' % len(result.Pairs))

        for expectedKey, expectedValue in expected:
            # TODO: xxx
            pair = [x for x in result.Pairs if x[0].Value == expectedKey.Value][0][1]
            if not pair:
                self.fail('no pair for given key in Pairs')

            testIntegerObject(self, pair.Value, expectedValue)
Ejemplo n.º 2
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
    }
    '''

    evaluated = _test_eval(input)
    assert issubclass(evaluated.__class__, object.Hash), \
        "Eval didn't return Hash. got={} ({})".format(evaluated.__class__.__name__, evaluated)

    expected = {
        object.String('one').hash_key(): 1,
        object.String('two').hash_key(): 2,
        object.String('three').hash_key(): 3,
        object.Integer(4).hash_key(): 4,
        evaluator.TRUE.hash_key(): 5,
        evaluator.FALSE.hash_key(): 6,
    }

    assert len(evaluated.pairs) == len(expected), \
        'Hash has wrong num of pairs. got={}'.format(len(evaluated.pairs))

    for expected_key, expected_value in expected.items():
        assert expected_key in evaluated.pairs, \
            'no pair for given key in pairs: ' + str(expected_key)
        pair = evaluated.pairs[expected_key]

        _test_integer_object(pair.value, expected_value)
Ejemplo n.º 3
0
def test_string_hash_key():
    hello1 = object.String('Hello World')
    hello2 = object.String('Hello World')
    diff1 = object.String('My name is johnny')
    diff2 = object.String('My name is johnny')

    assert hello1.hash_key() == hello2.hash_key(), \
        'strings with same content have different hash keys'

    assert diff1.hash_key() == diff2.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'
Ejemplo n.º 4
0
    def test_string_hash_key(self):
        hello1 = object.String(Value='Hello World')
        hello2 = object.String(Value='Hello World')
        diff1 = object.String(Value='My name is johnny')
        diff2 = object.String(Value='My name is johnny')

        if object.GetHashKey(hello1) != object.GetHashKey(hello2):
            self.fail('strings with same content have different hash keys')

        if object.GetHashKey(diff1) != object.GetHashKey(diff2):
            self.fail('strings with same content have different hash keys')

        if object.GetHashKey(hello1) == object.GetHashKey(diff1):
            self.fail('strings with different content have same hash keys')
Ejemplo n.º 5
0
def eval_infix_expression(operator: str, lhs: monkey_obj.Object,
                          rhs: monkey_obj.Object) -> monkey_obj.Object:
    if isinstance(lhs, monkey_obj.Integer) and isinstance(
            rhs, monkey_obj.Integer):
        return eval_integer_infix_expression(operator, lhs, rhs)
    elif type(lhs) != type(rhs):
        return monkey_obj.Error(
            f"type mismatch: {lhs.object_type()} {operator} {rhs.object_type()}"
        )

    elif isinstance(lhs, monkey_obj.String) and isinstance(
            rhs, monkey_obj.String):
        if operator != "+":
            return monkey_obj.Error(
                f"unknown operator: {lhs.object_type()} {operator} {rhs.object_type()}"
            )
        return monkey_obj.String(value=lhs.value + rhs.value)

    elif operator == "==":
        return native_bool_to_boolean_object(lhs == rhs)
    elif operator == "!=":
        return native_bool_to_boolean_object(lhs != rhs)
    return monkey_obj.Error(
        f"unknown operator: {lhs.object_type()} {operator} {rhs.object_type()}"
    )
Ejemplo n.º 6
0
def evalStringInfixExpression(operator: str, left: object.Object,
                              right: object.Object) -> object.Object:
    if operator != '+':
        return newError('unknown operator: %s %s %s',
                        (left.Type.TypeName, operator, right.Type.TypeName))

    leftVal = left.Value
    rightVal = right.Value
    return object.String(Value=leftVal + rightVal)
Ejemplo n.º 7
0
def eval_string_infix_operation(operator: str, left: object.Object,
                                right: object.Object) -> object.Object:
    if operator != '+':
        return new_error('unknown operator: {} {} {}'.format(
            left.type(), operator, right.type()))

    left_val = left.value
    right_val = right.value
    return object.String(left_val + right_val)
Ejemplo n.º 8
0
def eval(node: ast.Node, env: object.Environment):
    if type(node) is ast.Program:
        return eval_program(node.statements, env)
    elif type(node) is ast.ExpressionStatement:
        return eval(node.expression, env)
    elif type(node) is ast.LetStatement:
        val = eval(node.value, env)
        if is_error(val):
            return val
        env.set(node.name.value, val)
    elif type(node) is ast.Identifier:
        return eval_identifier(node, env)
    elif type(node) is ast.StringLiteral:
        return object.String(value=node.value)
    elif type(node) is ast.FunctionLiteral:
        parameters = node.parameters
        body = node.body
        return object.Function(parameters=parameters, body=body, env=env)
    elif type(node) is ast.CallExpression:
        fun = eval(node.function, env)
        if is_error(fun):
            return fun
        args = eval_expressions(node.arguments, env)
        if len(args) == 1 and is_error(args[0]):
            return args[0]
        return apply_function(fun, args)
    elif type(node) is ast.PrefixExpression:
        right = eval(node.right, env)
        if is_error(right):
            return right
        return eval_prefix_expression(node.operator, right)
    elif type(node) is 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 type(node) is ast.IntegerLiteral:
        return object.Integer(value=node.value)
    elif type(node) is ast.BlockStatement:
        return eval_block_statements(node.statements, env)
    elif type(node) is ast.IfExpression:
        return eval_if_expression(node, env)
    elif type(node) is ast.ReturnStatement:
        val = eval(node.return_value, env)
        return object.ReturnValue(value=val)
    elif type(node) is ast.Boolean:
        return object.TRUE if node.value is True else object.FALSE
Ejemplo n.º 9
0
def Eval(node: Any, env: object.Environment) -> Optional[object.Object]:
    if type(node) == ast.Program:
        return evalProgram(node, env)
    elif type(node) == ast.ExpressionStatement:
        return Eval(node.ExpressionValue, env)
    elif type(node) == ast.IntegerLiteral:
        return object.Integer(Value=node.Value)
    elif type(node) == ast.Boolean:
        return nativeBoolToBooleanObject(node.Value)
    elif type(node) == ast.PrefixExpression:
        right = Eval(node.Right, env)
        if right:
            if isError(right):
                return right
            return evalPrefixExpression(node.Operator, right)
        else:
            return None
    elif type(node) == ast.InfixExpression:
        left = Eval(node.Left, env)
        if not left:
            return None
        if isError(left):
            return left
        right = Eval(node.Right, env)
        if not right:
            return None
        if isError(right):
            return right
        evaluated = evalInfixExpression(node.Operator, left, right)
        return evaluated
    elif type(node) == ast.BlockStatement:
        return evalBlockStatement(node, env)
    elif type(node) == ast.IfExpression:
        return evalIfExpression(node, env)
    elif type(node) == ast.ReturnStatement:
        val = Eval(node.ReturnValue, env)
        if val:
            if isError(val):
                return val
            return object.ReturnValue(Value=val)
        else:
            return None
    elif type(node) == ast.LetStatement:
        val = Eval(node.Value, env)
        if val:
            if isError(val):
                return val
            env.Set(node.Name.Value, val)
        else:
            return None
    elif type(node) == ast.Identifier:
        return evalIdentifier(node, env)
    elif type(node) == ast.FunctionLiteral:
        params = node.Parameters
        body = node.Body
        return object.Function(Parameters=params, Env=env, Body=body)
    elif type(node) == ast.CallExpression:
        if node.Function.TokenLiteral() == 'quote':
            return quote(node.Arguments[0], env)
        function = Eval(node.Function, env)
        if function:
            if isError(function):
                return function
        args = evalExpressions(node.Arguments, env)
        if len(args) == 1 and isError(args[0]):
            return args[0]
        if not function:
            return None
        return applyFunction(function, args)
    elif type(node) == ast.StringLiteral:
        return object.String(Value=node.Value)
    elif type(node) == ast.ArrayLiteral:
        elements = evalExpressions(node.Elements, env)
        if len(elements) == 1 and isError(elements[0]):
            return elements[0]
        return object.Array(Elements=elements)
    elif type(node) == ast.IndexExpression:
        left = Eval(node.Left, env)
        if not left:
            return None
        if isError(left):
            return left
        index = Eval(node.Index, env)
        if not index:
            return None
        if isError(index):
            return index
        return evalIndexExpression(left, index)
    elif type(node) == ast.HashLiteral:
        return evalHashLiteral(node, env)
    return None
Ejemplo n.º 10
0
def Eval(node: ast.Node, env) -> monkey_obj.Object:

    if isinstance(node, ast.Program):
        return eval_program(node.statements, env)

    elif isinstance(node, ast.HashLiteral):
        return eval_hash_literal(node, env)

    elif isinstance(node, ast.ArrayLiteral):
        elements = [Eval(e, env) for e in node.elements]
        if len(elements) == 1 and isinstance(elements[0], monkey_obj.Error):
            return elements[0]
        return monkey_obj.Array(elements=elements)

    elif isinstance(node, ast.IndexExpression):
        left = Eval(node.left, env)
        if left is not None and isinstance(left, monkey_obj.Error):
            return left

        index = Eval(node.index, env)
        if index is not None and isinstance(index, monkey_obj.Error):
            return index

        return eval_index_expression(left, index)

    elif isinstance(node, ast.StringLiteral):
        return monkey_obj.String(value=node.value)

    elif isinstance(node, ast.CallExpression):
        function = Eval(node.function, env)
        if function is not None and isinstance(function, monkey_obj.Error):
            return function

        args = [Eval(e, env) for e in node.arguments]
        for arg in args:
            if arg is not None and isinstance(function, monkey_obj.Error):
                return arg
        return apply_function(function, args)

    elif isinstance(node, ast.FunctionLiteral):
        params = node.params
        body = node.body
        return monkey_obj.Function(params, env, body)

    elif isinstance(node, ast.BlockStatement):
        return eval_block_statements(node.statements, env)

    elif isinstance(node, ast.IfExpression):
        return eval_if_expression(node, env)

    elif isinstance(node, ast.Identifier):
        return eval_identifier(node, env)

    elif isinstance(node, ast.LetStatement):
        val = Eval(node.value, env)
        if val is not None and isinstance(val, monkey_obj.Error):
            return val
        env[node.name.value] = val
        return monkey_obj.NULL

    elif isinstance(node, ast.ReturnStatement):
        val = Eval(node.value, env)
        if val is not None and isinstance(val, monkey_obj.Error):
            return val
        return monkey_obj.ReturnValue(value=val)

    elif isinstance(node, ast.ExpressionStatement):
        return Eval(node.expression, env)

    elif isinstance(node, ast.Boolean):
        return native_bool_to_boolean_object(node.value)

    elif isinstance(node, ast.IntegerLiteral):
        return monkey_obj.Integer(value=node.value)

    elif isinstance(node, ast.PrefixExpression):
        right = Eval(node.right, env)
        if right is not None and isinstance(right, monkey_obj.Error):
            return val
        return eval_prefix_expression(node.operator, right)

    elif isinstance(node, ast.InfixExpression):
        left = Eval(node.left, env)
        if left is not None and isinstance(left, monkey_obj.Error):
            return left
        right = Eval(node.right, env)
        if right is not None and isinstance(right, monkey_obj.Error):
            return val
        return eval_infix_expression(node.operator, left, right)

    else:
        raise NotImplementedError(str(node), node.token_literal())
Ejemplo n.º 11
0
def eval_string_infix_expression(operator, left, right):
    if operator is not "+":
        return object.Error("unknown operator: {} {} {}".format(left.object_type, operator, right.object_type))
        # use python string concat underneath
    return object.String(value=left.value + right.value)
Ejemplo n.º 12
0
def eval(node: ast.Node,
         env: object.Environment) -> Union[object.Object, None]:

    # Statements

    if issubclass(node.__class__, ast.Program):
        return eval_program(node, env)

    elif issubclass(node.__class__, ast.BlockStatement):
        return eval_block_statement(node, env)

    elif issubclass(node.__class__, ast.ExpressionStatement):
        return eval(node.expression, env)

    elif issubclass(node.__class__, ast.ReturnStatement):
        val = eval(node.return_value, env)
        if is_error(val):
            return val
        return object.ReturnValue(val)

    elif issubclass(node.__class__, ast.LetStatement):
        val = eval(node.value, env)
        if is_error(val):
            return val
        env.set(node.name.value, val)

    # Expressions

    elif issubclass(node.__class__, ast.IntegerLiteral):
        return object.Integer(node.value)

    elif issubclass(node.__class__, ast.StringLiteral):
        return object.String(node.value)

    elif issubclass(node.__class__, ast.Boolean):
        return native_bool_to_boolean_object(node.value)

    elif issubclass(node.__class__, ast.PrefixExpression):
        right = eval(node.right, env)
        if is_error(right):
            return right
        return eval_prefix_expression(node.operator, right)

    elif issubclass(node.__class__, 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 issubclass(node.__class__, ast.IfExpression):
        return eval_if_expression(node, env)

    elif issubclass(node.__class__, ast.Identifier):
        return eval_identifier(node, env)

    elif issubclass(node.__class__, ast.FunctionLiteral):
        params = node.parameters
        body = node.body
        return object.Function(params, body, env)

    elif issubclass(node.__class__, 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 issubclass(node.__class__, ast.ArrayLiteral):
        elements = eval_expressions(node.elements, env)
        if len(elements) == 1 and is_error(elements[0]):
            return elements[0]
        return object.Array(elements)

    elif issubclass(node.__class__, 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 issubclass(node.__class__, ast.HashLiteral):
        return eval_hash_literal(node, env)

    return None