Пример #1
0
    def test_function_literal_parsing(self):
        source = "fn(x, y) { x + y; }"

        lexer = Lexer(source)
        parser = Parser(lexer)
        program = parser.parse_program()
        self.assert_check_parser_errors(parser)

        self.assertEqual(1, len(program.statements),
                         f'program.statements does not contain 1 statements. got={len(program.statements)}')

        expression_statement = program.statements[0]  # ExpressionStatement AST node.
        function = expression_statement.expression  # FunctionLiteral AST node.

        self.assertEqual(2, len(function.parameters),
                         f'function literal parameters wrong. want 2, got={len(function.parameters)}')

        self.assert_test_literal_expression(function.parameters[0], "x")
        self.assert_test_literal_expression(function.parameters[1], "y")

        self.assertEqual(1, len(function.body.statements),
                         f'function.body.statements has not 1 statements. got={len(function.body.statements)}')

        body_stmt = function.body.statements[0]  # ExpressionStatement AST node.

        self.assert_test_infix_expression(body_stmt.expression, "x", "+", "y")
Пример #2
0
    def test_parsing_prefix_expressions(self):
        prefix_tests = [
            ["!5;", "!", 5],
            ["-15;", "-", 15],
            ["!true;", "!", True],
            ["!false;", "!", False],
        ]

        for tt in prefix_tests:
            source = tt[0]
            operator = tt[1]
            value = tt[2]

            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.parse_program()
            self.assert_check_parser_errors(parser)

            self.assertEqual(1, len(program.statements),
                             f'program.statements does not contain 1 statements. got={len(program.statements)}')

            stmt = program.statements[0]
            exp = stmt.expression

            self.assertEqual(exp.operator, operator, f"exp.operator is not '{operator}'. got={exp.operator}")

            self.assertTrue(self.assert_test_literal_expression(exp.right, value))
Пример #3
0
    def test_if_else_expression(self):
        source = "if (x < y) { x } else { y }"
        lexer = Lexer(source)
        parser = Parser(lexer)
        program = parser.parse_program()

        self.assert_check_parser_errors(parser)
        self.assertEqual(1, len(program.statements))

        stmt = program.statements[0]  # ExpressionStatement AST

        exp = stmt.expression  # IfExpression AST node

        if not self.assert_test_infix_expression(exp.condition, "x", "<", "y"):
            return

        if len(exp.consequence.statements) != 1:
            print(f'consequence is not 1 statements. got={len(exp.consequence.statements)}')

        consequence = exp.consequence.statements[0]  # ExpressionStatement AST

        if not self.assert_test_identifier(consequence.expression, "x"):
            return

        if len(exp.alternative.statements) != 1:
            print(f'alternative is not 1 statements. got={len(exp.alternative.statements)}')

        alternative = exp.alternative.statements[0]  # ExpressionStatement AST

        if not self.assert_test_identifier(alternative.expression, "y"):
            return
Пример #4
0
    def test_let_statements(self):
        tests = [
            ["let x = 5;", "x", 5],
            ["let y = true;", "y", True],
            ["let foobar = y;", "foobar", "y"],
        ]

        for tt in tests:
            source = tt[0]
            expected_identifier = tt[1]
            expected_value = tt[2]

            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.parse_program()
            self.assert_check_parser_errors(parser)

            self.assertEqual(1, len(program.statements),
                             f"program.statements does not contain 1 statements. got={len(program.statements)}")

            stmt = program.statements[0]  # ExpressionStatement AST node.
            if not self.assert_test_let_statement(stmt, expected_identifier):
                return

            val = stmt.value
            if not self.assert_test_literal_expression(val, expected_value):
                return
Пример #5
0
    def assert_test_eval(self, source):
        lexer = Lexer(source)
        parser = Parser(lexer)
        program = parser.parse_program()
        eva = Evaluator()
        env = Environment()

        return eva.eval(node=program, env=env)
Пример #6
0
    def test_null_literal_expression(self):
        lexer = Lexer("null;")
        parser = Parser(lexer)
        program = parser.parse_program()
        self.assert_check_parser_errors(parser)
        self.assertEqual(1, len(program.statements),
                         f"program has not enough statements. got={len(program.statements)}")

        expression_statement = program.statements[0]
        null_literal = expression_statement.expression

        self.assertEqual(None, null_literal.value,
                         f"null_literal.value not 'null'. got={null_literal.value}")
Пример #7
0
    def test_identifier_expression(self):
        lexer = Lexer("foobar;")
        parser = Parser(lexer)

        program = parser.parse_program()
        self.assert_check_parser_errors(parser)

        self.assertEqual(1, len(program.statements),f'program has not enough statements. got={len(program.statements)}')

        expression_statement = program.statements[0]
        ident = expression_statement.expression

        self.assertEqual("foobar", ident.value, f'ident.value not {"foobar"} got={ident.value}')

        self.assertEqual("foobar", ident.token_literal(),
                         f"ident.token_literal() not {'foobar'}. got={ident.token_literal()}")
Пример #8
0
    def test_integer_literal_expression(self):
        lexer = Lexer("5;")
        parser = Parser(lexer)

        program = parser.parse_program()
        self.assert_check_parser_errors(parser)

        self.assertEqual(1, len(program.statements),
                         f"program has not enough statements. got={len(program.statements)}")

        expression_statement = program.statements[0]
        literal = expression_statement.expression

        self.assertEqual(5, literal.value,
                         f"literal.value not {5}. got={literal.value}")

        self.assertEqual("5", literal.token_literal(),
                         f"literal.token_literal() not {5}. got={literal.token_literal()}")
Пример #9
0
    def test_return_statements(self):
        source = """
            return 5;
            return 10;
            return 993322;
        """
        lexer = Lexer(source)
        parser = Parser(lexer)

        program = parser.parse_program()
        self.assert_check_parser_errors(parser)

        self.assertEqual(3, len(program.statements),
                         f'program.statements does not contain 3 statements. got={len(program.statements)}')

        for return_stmt in program.statements:
            self.assertEqual("return", return_stmt.token_literal(),
                             f'return_stmt.token_literal not "return", got {return_stmt.token_literal()}')
Пример #10
0
    def test_boolean_expression(self):
        tests = [
            ["true;", True],
            ["false;", False],
        ]
        for tt in tests:
            source = tt[0]
            expected = tt[1]
            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.parse_program()
            self.assert_check_parser_errors(parser)

            self.assertEqual(1, len(program.statements))

            expression_statement = program.statements[0]
            boolean_exp = expression_statement.expression

            self.assertEqual(boolean_exp.value, expected)
Пример #11
0
    def test_parsing_infix_expressions(self):
        infix_tests = [
            ["5 + 5;", 5, "+", 5],
            ["5 - 5;", 5, "-", 5],
            ["5 * 5;", 5, "*", 5],
            ["5 / 5;", 5, "/", 5],
            ["5 < 5;", 5, "<", 5],
            ["5 > 5;", 5, ">", 5],
            ["5 == 5;", 5, "==", 5],
            ["5 != 5;", 5, "!=", 5],
            ["true == true", True, "==", True],
            ["true != false", True, "!=", False],
            ["false == false", False, "==", False],
        ]

        for tt in infix_tests:
            source = tt[0]
            left_value = tt[1]
            operator = tt[2]
            right_value = tt[3]

            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.parse_program()
            self.assert_check_parser_errors(parser)

            self.assertEqual(1, len(program.statements),
                             f"program.statements does not contain 1 statements. got={len(program.statements)}")

            stmt = program.statements[0]  # ExpressionStatement AST
            exp = stmt.expression  # InfixExpression AST

            if not self.assert_test_literal_expression(exp.left, left_value):
                return

            if not self.assert_test_literal_expression(exp.right, right_value):
                return

            self.assertEqual(exp.operator, operator, f"exp.operator is not '{operator}'. got={exp.operator}")

            if not self.assert_test_literal_expression(exp.right, right_value):
                return
Пример #12
0
    def test_call_expression_parsing(self):
        source = "add(1, 2 * 3, 4 + 5);"
        lexer = Lexer(source)
        parser = Parser(lexer)
        program = parser.parse_program()
        self.assert_check_parser_errors(parser)

        self.assertEqual(1, len(program.statements),
                         f'program.statements does not contain 1 statements. got={len(program.statements)}')

        stmt = program.statements[0]  # ExpressionStatement AST node.
        exp = stmt.expression  # CallExpression AST node.

        if not self.assert_test_identifier(exp.function, "add"):
            return

        self.assertEqual(3, len(exp.arguments), f'wrong length of arguments. got={len(exp.arguments)}')

        self.assert_test_literal_expression(exp.arguments[0], 1)
        self.assert_test_infix_expression(exp.arguments[1], 2, "*", 3)
        self.assert_test_infix_expression(exp.arguments[2], 4, "+", 5)
Пример #13
0
    def test_operator_precedence_parsing(self):
        tests = [
            ["-a * b", "((-a) * b)"],
            ["!-a", "(!(-a))"],
            ["a + b + c", "((a + b) + c)"],
            ["a + b - c", "((a + b) - c)"],
            ["a * b * c", "((a * b) * c)"],
            ["a * b / c", "((a * b) / c)"],
            ["a + b / c", "(a + (b / c))"],
            ["a + b * c + d / e - f", "(((a + (b * c)) + (d / e)) - f)"],
            ["3 + 4; -5 * 5", "(3 + 4)((-5) * 5)"],
            ["5 > 4 == 3 < 4", "((5 > 4) == (3 < 4))"],
            ["5 < 4 != 3 > 4", "((5 < 4) != (3 > 4))"],
            ["3 + 4 * 5 == 3 * 1 + 4 * 5", "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))"],
            ["true", "true"],
            ["false", "false"],
            ["3 > 5 == false", "((3 > 5) == false)"],
            ["3 < 5 == true", "((3 < 5) == true)"],
            ["1 + (2 + 3) + 4", "((1 + (2 + 3)) + 4)"],
            ["(5 + 5) * 2", "((5 + 5) * 2)"],
            ["2 / (5 + 5)", "(2 / (5 + 5))"],
            ["-(5 + 5)", "(-(5 + 5))"],
            ["!(true == true)", "(!(true == true))"],
            ["a + add(b * c) + d", "((a + add((b * c))) + d)"],
            ["add(a, b, 1, 2 * 3, 4 + 5, add(6, 7 * 8))", "add(a, b, 1, (2 * 3), (4 + 5), add(6, (7 * 8)))"],
            ["add(a + b + c * d / f + g)", "add((((a + b) + ((c * d) / f)) + g))"],
        ]

        for tt in tests:
            source = tt[0]
            expected = tt[1]
            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.parse_program()
            self.assert_check_parser_errors(parser)

            actual = program.string()

            self.assertEqual(actual, expected, f"expected={expected}, got={actual}")
Пример #14
0
def start():
    print('Hello! This is SpeedMonkey programming language!\n')
    print('Feel free to type in commands\n')
    env = Environment()
    while True:
        try:
            source = input(PROMPT)
        except EOFError:
            break
        if not source:
            continue

        lexer = Lexer(source)
        parser = Parser(lexer)
        program = parser.parse_program()

        if len(parser.errors) != 0:
            print_parser_errors(parser.errors)

        evaluator = Evaluator()
        evaluated = evaluator.eval(node=program, env=env)
        if evaluated is not None:
            print(evaluated.inspect())
Пример #15
0
    def test_function_parameter_parsing(self):
        tests = [
            ["fn() {};", []],
            ["fn(x) {};", ["x"]],
            ["fn(x, y, z) {};", ["x", "y", "z"]],
        ]

        for tt in tests:
            source = tt[0]
            expected_params = tt[1]

            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.parse_program()
            self.assert_check_parser_errors(parser)

            stmt = program.statements[0]  # ExpressionStatement AST node.
            function = stmt.expression  # FunctionLiteral AST node.

            if len(function.parameters) != len(expected_params):
                print(f'length parameters wrong. want {len(expected_params)}, got={len(function.parameters)}')

            for i, ident in enumerate(expected_params):
                self.assert_test_literal_expression(function.parameters[i], ident)
Пример #16
0
    def test_tokens(self):
        lexer = Lexer(
            """
        let five = 5;
        let ten = 10;
        
        let add = fn(x, y) {
            x + y;
        };
        
        let result = add(five, ten);
        !-/*5;
        5 < 10 > 5;
        
        if (5 < 10) {
            return true;
        } else {
            return false;
        }
        
        10 == 10;
        10 != 9;
        result = null;
            """
        )

        expected_tokens = [
            Token(TokenType.LET, "let"),
            Token(TokenType.IDENT, "five"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.INT, "5"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.LET, "let"),
            Token(TokenType.IDENT, "ten"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.INT, "10"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.LET, "let"),
            Token(TokenType.IDENT, "add"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.FUNCTION, "fn"),
            Token(TokenType.LPAREN, "("),
            Token(TokenType.IDENT, "x"),
            Token(TokenType.COMMA, ","),
            Token(TokenType.IDENT, "y"),
            Token(TokenType.RPAREN, ")"),
            Token(TokenType.LBRACE, "{"),
            Token(TokenType.IDENT, "x"),
            Token(TokenType.PLUS, "+"),
            Token(TokenType.IDENT, "y"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.RBRACE, "}"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.LET, "let"),
            Token(TokenType.IDENT, "result"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.IDENT, "add"),
            Token(TokenType.LPAREN, "("),
            Token(TokenType.IDENT, "five"),
            Token(TokenType.COMMA, ","),
            Token(TokenType.IDENT, "ten"),
            Token(TokenType.RPAREN, ")"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.BANG, "!"),
            Token(TokenType.MINUS, "-"),
            Token(TokenType.SLASH, "/"),
            Token(TokenType.ASTERISK, "*"),
            Token(TokenType.INT, "5"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.INT, "5"),
            Token(TokenType.LT, "<"),
            Token(TokenType.INT, "10"),
            Token(TokenType.GT, ">"),
            Token(TokenType.INT, "5"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.IF, "if"),
            Token(TokenType.LPAREN, "("),
            Token(TokenType.INT, "5"),
            Token(TokenType.LT, "<"),
            Token(TokenType.INT, "10"),
            Token(TokenType.RPAREN, ")"),
            Token(TokenType.LBRACE, "{"),
            Token(TokenType.RETURN, "return"),
            Token(TokenType.TRUE, "true"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.RBRACE, "}"),
            Token(TokenType.ELSE, "else"),
            Token(TokenType.LBRACE, "{"),
            Token(TokenType.RETURN, "return"),
            Token(TokenType.FALSE, "false"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.RBRACE, "}"),
            Token(TokenType.INT, "10"),
            Token(TokenType.EQ, "=="),
            Token(TokenType.INT, "10"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.INT, "10"),
            Token(TokenType.NOT_EQ, "!="),
            Token(TokenType.INT, "9"),
            Token(TokenType.SEMICOLON, ";"),
            Token(TokenType.IDENT, "result"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.NULL, "null"),
            Token(TokenType.SEMICOLON, ";"),
        ]
        for expected_token in expected_tokens:
            actual = lexer.next_token()

            self.assertEqual(expected_token.type, actual.type)
            self.assertEqual(expected_token.literal, actual.literal)
Пример #17
0
def test_expression():
    source = "1 + 2 + 3;"
    lexer = Lexer(source)
    parser = Parser(lexer)
    program = parser.parse_program()
    print(program.string())