コード例 #1
0
def eval_integer_infix_expression(
        operator: str, left: object.Object,
        right: object.Object) -> Union[object.Object, None]:
    left_val = left.value
    right_val = right.value

    if operator == '+':
        return object.Integer(left_val + right_val)
    elif operator == '-':
        return object.Integer(left_val - right_val)
    elif operator == '*':
        return object.Integer(left_val * right_val)
    elif operator == '/':
        return object.Integer(left_val / right_val)
    elif operator == '<':
        return native_bool_to_boolean_object(left_val < right_val)
    elif operator == '>':
        return native_bool_to_boolean_object(left_val > right_val)
    elif operator == '==':
        return native_bool_to_boolean_object(left_val == right_val)
    elif operator == '!=':
        return native_bool_to_boolean_object(left_val != right_val)
    else:
        return new_error('unknown operator: {} {} {}', left.type(), operator,
                         right.type())
コード例 #2
0
def _len(*args) -> object.Object:
    if len(args) != 1:
        return evaluator.new_error('wrong number of arguments. got={}, want=1'.format(len(args)))

    if type(args[0]) == object.Array:
        return object.Integer(len(args[0].elements))
    elif type(args[0]) == object.String:
        return object.Integer(len(args[0].value))
    else:
        return evaluator.new_error('argument to `len` not supported, got {}'.format(args[0].type()))
コード例 #3
0
def _builtin_len(args: List[monkey_obj.Object]) -> monkey_obj.Object:
    if len(args) != 1:
        return monkey_obj.Error(
            f"wrong number of arguments. got={len(args)}, want=1")
    item = next(iter(args))
    if isinstance(item, monkey_obj.String):
        return monkey_obj.Integer(value=len(item.value))
    elif isinstance(item, monkey_obj.Array):
        return monkey_obj.Integer(value=len(item.elements))
    else:
        return monkey_obj.Error(
            f"argument to `len` not supported, got {item.object_type()}")
コード例 #4
0
ファイル: evaluator.py プロジェクト: rokujyouhitoma/monkey-py
def builtin_len(args: List[object.Object]) -> object.Object:
    if len(args) != 1:
        return newError('wrong number of arguments. got=%s, want=1',
                        (len(args), ))

    arg = args[0]
    if type(arg) == object.Array:
        arg = cast(object.Array, arg)
        return object.Integer(Value=int(len(arg.Elements)))
    elif type(arg) == object.String:
        return object.Integer(Value=int(len(arg.Value)))
    else:
        return newError('argument to \'len\' not supported, got %s',
                        (args[0].Type.TypeName, ))
コード例 #5
0
ファイル: test_object.py プロジェクト: morinokami/pymonkey
def test_integer_hash_key():
    one1 = object.Integer(1)
    one2 = object.Integer(1)
    two1 = object.Integer(2)
    two2 = object.Integer(2)

    assert one1.hash_key() == one2.hash_key(), \
        'integers with same content have twoerent hash keys'

    assert two1.hash_key() == two2.hash_key(), \
        'integers with same content have twoerent hash keys'

    assert one1.hash_key() != two1.hash_key(), \
        'integers with tworent content have same hash keys'
コード例 #6
0
def eval_minus_prefix_expression(right: object.Object) -> object.Object:
    if right.type() != object.INTEGER_OBJ:
        return new_error('unknown operator: -{}', right.type())

    value = right.value

    return object.Integer(-value)
コード例 #7
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)
コード例 #8
0
ファイル: test_evaluator.py プロジェクト: morinokami/pymonkey
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)
コード例 #9
0
def len_builtin(*args):
    if len(args) != 1:
        return object.Error(
            'wrong number of arguments, got= {}, want = 1'.format(len(args)))
    if type(args[0]) is object.String:
        return object.Integer(value=len(args[0].value))
    else:
        return object.Error("argument to 'len' not supported, got {}".format(
            args[0].object_type))
コード例 #10
0
ファイル: evaluator.py プロジェクト: rokujyouhitoma/monkey-py
def evalMinusPrefixOperatorExpression(
        right: Optional[object.Object]) -> object.Object:
    if not right:
        return NULL
    if right.Type.TypeName != object.INTEGER_OBJ:
        return newError('unknown operator: -%s', (right.Type.TypeName, ))

    value = right.Value
    return object.Integer(Value=-value)
コード例 #11
0
def eval_integer_infix_expression(operator, left, right):
    left_val = left.value
    right_val = right.value
    if operator == '+':
        return object.Integer(value=left_val + right_val)
    elif operator == '-':
        return object.Integer(value=left_val - right_val)
    elif operator == '*':
        return object.Integer(value=left_val * right_val)
    elif operator == '/':
        return object.Integer(value=left_val / right_val)
    elif operator == '<':
        return native_bool_to_boolean_object(left_val < right_val)
    elif operator == '>':
        return native_bool_to_boolean_object(left_val > right_val)
    elif operator == '==':
        return native_bool_to_boolean_object(left_val == right_val)
    elif operator == '!=':
        return native_bool_to_boolean_object(left_val != right_val)
    else:
        # an error
        return object.NULL
コード例 #12
0
ファイル: evaluator.py プロジェクト: rokujyouhitoma/monkey-py
def evalIntegerInfixExpression(operator: str, left: object.Object,
                               right: object.Object) -> object.Object:
    leftVal = left.Value
    rightVal = right.Value
    if operator == '+':
        return object.Integer(Value=leftVal + rightVal)
    elif operator == '-':
        return object.Integer(Value=leftVal - rightVal)
    elif operator == '*':
        return object.Integer(Value=leftVal * rightVal)
    elif operator == '/':
        return object.Integer(Value=leftVal / rightVal)
    elif operator == '<':
        return nativeBoolToBooleanObject(leftVal < rightVal)
    elif operator == '>':
        return nativeBoolToBooleanObject(leftVal > rightVal)
    elif operator == '==':
        return nativeBoolToBooleanObject(leftVal == rightVal)
    elif operator == '!=':
        return nativeBoolToBooleanObject(leftVal != rightVal)
    else:
        return newError('unknown operator: %s %s %s',
                        (left.Type.TypeName, operator, right.Type.TypeName))
コード例 #13
0
def eval_integer_infix_expression(
        operator: str, lhs: monkey_obj.Integer,
        rhs: monkey_obj.Integer) -> monkey_obj.Object:
    if operator == "+":
        return monkey_obj.Integer(value=lhs.value + rhs.value)
    elif operator == "-":
        return monkey_obj.Integer(value=lhs.value - rhs.value)
    elif operator == "*":
        return monkey_obj.Integer(value=lhs.value * rhs.value)
    elif operator == "/":
        return monkey_obj.Integer(value=lhs.value // rhs.value)
    elif operator == "<":
        return native_bool_to_boolean_object(lhs.value < rhs.value)
    elif operator == ">":
        return native_bool_to_boolean_object(lhs.value > rhs.value)
    elif operator == "==":
        return native_bool_to_boolean_object(lhs.value == rhs.value)
    elif operator == "!=":
        return native_bool_to_boolean_object(lhs.value != rhs.value)
    else:
        return monkey_obj.Error(
            f"unknown operator: {lhs.object_type()} {operator} {rhs.object_type()}"
        )
コード例 #14
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
コード例 #15
0
ファイル: evaluator.py プロジェクト: rokujyouhitoma/monkey-py
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
コード例 #16
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())
コード例 #17
0
def eval_minus_prefix_operator(rhs: monkey_obj.Object) -> monkey_obj.Object:
    if not isinstance(rhs, monkey_obj.Integer):
        return monkey_obj.Error(f"unknown operator: -{rhs.object_type()}")
    return monkey_obj.Integer(value=-(rhs.value))
コード例 #18
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
コード例 #19
0
def eval_minus_prefix_operator_expression(right):
    if type(right) is not object.Integer:
        return object.Error(message="unknown operator: {}{}".format("-", right.object_type))
    else:
        return object.Integer(value=-right.value)