Example #1
0
    def test_callexp_parsing(self):
        input_case = "add(1, 2 * 3, 4 + 5)"
        lexer = Lexer(input_case)
        parser = Parser(lexer)

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

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

        stmt = program.statements[0]

        if not isinstance(stmt, ExpressionStatement):
            self.fail(f"Expected ExpressionStatement, got {stmt}.")

        exp = stmt.expression
        if not isinstance(exp, CallExpression):
            self.fail(f"Expected CallExpression, got {exp}.")

        self._test_identifier(exp.function, "add")
        self.assertEqual(len(exp.arguments), 3,
                         f"Wrong length of args, got {len(exp.arguments)}.")

        self._test_literal_exp(exp.arguments[0], 1)
        self._test_infix_exp(exp.arguments[1], 2, "*", 3)
        self._test_infix_exp(exp.arguments[2], 4, "+", 5)
Example #2
0
    def test_identifier(self):
        inputcase = "foobar;"
        lexer = Lexer(inputcase)
        parser = Parser(lexer)
        program = parser.parse_program()

        self._check_parser_errors(parser)

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

        if not isinstance(program.statements[0], ExpressionStatement):
            self.fail(
                f"program.statements[0] not a instance of ExpressionStatement."
            )

        ident = program.statements[0].expression
        if not isinstance(ident, Identifier):
            self.fail(f"Exp not a instance of Identifier.")

        self.assertEqual(ident.value, "foobar",
                         f"ident.value != foobar, got {ident.value}.")
        self.assertEqual(
            ident.token_literal(),
            "foobar",
            f"ident.token_literal() != foobar, got {ident.token_literal()}.",
        )
Example #3
0
    def _test_eval(self, input_case: str):
        lexer = Lexer(input_case)
        parser = Parser(lexer)
        env = objects.Environment()

        program = parser.parse_program()
        return evaluator.evaluate(program, env)
Example #4
0
    def test_parsing_dict_withexp(self):
        input_case = '{"one": 0 + 1, "two": 10 - 8, "three": 15 / 5}'
        lexer = Lexer(input_case)
        parser = Parser(lexer)

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

        stmt = program.statements[0].expression
        if not isinstance(stmt, DictionaryLiteral):
            self.fail(f"Expected DictionaryLiteral, got {stmt}.")

        self.assertEqual(
            len(stmt.pairs), 3,
            f"hash.pairs has wrong length. got {len(stmt.pairs)}.")

        tests = {
            "one": lambda e: self._test_infix_exp(e, 0, "+", 1),
            "two": lambda e: self._test_infix_exp(e, 10, "-", 8),
            "three": lambda e: self._test_infix_exp(e, 15, "/", 5),
        }

        for key, val in stmt.pairs.items():
            if not isinstance(key, StringLiteral):
                self.fail(f"key not StringLiteral, got {key}.")

            test_func = tests.get(str(key), None)
            self.assertNotEqual(test_func, None,
                                f"No test function for key {str(key)} found.")
            test_func(val)
Example #5
0
def start() -> None:

    # Print some information.
    sys_env = platform.system()
    print(f"\nPrymate {prymate.__version__} [Running on {sys_env}]")
    print("Type exit() to exit from the REPL.\n")

    # Start the REPL loop.
    env = Environment()
    while True:
        line = input(">>> ")
        if not line:
            continue

        parser = Parser(Lexer(line))
        program = parser.parse_program()

        if parser.errors:
            print("There was a error while parsing the program.\nErrors:")
            for x in parser.errors:
                print(f"\t{x}\n")
            continue

        evaluated = evaluate(program, env)
        if evaluated is not None:
            print(evaluated.inspect())
Example #6
0
    def test_return(self):
        tests = [
            ["return 5;", 5],
            ["return true;", True],
            ["return foobar;", "foobar"],
        ]
        for tt in tests:
            lexer = Lexer(tt[0])
            parser = Parser(lexer)

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

            self.assertEqual(
                len(program.statements),
                1,
                f"Expected 1 statements, found {len(program.statements)}.",
            )

            stmt = program.statements[0]
            if not isinstance(stmt, ReturnStatement):
                self.fail(f"Expected ReturnStatement, got {stmt}.")

            self.assertEqual(
                stmt.token_literal(),
                "return",
                f"Expected 'return', got {stmt.token_literal()}.",
            )

            self._test_literal_exp(stmt.return_value, tt[1])
Example #7
0
    def test_fnparameter_parsing(self):
        tests = [
            ["fn() {};", []],
            ["fn(x) {};", ["x"]],
            ["fn(x, y, z) {};", ["x", "y", "z"]],
        ]

        for tt in tests:
            lexer = Lexer(tt[0])
            parser = Parser(lexer)

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

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

            self.assertEqual(
                len(function.parameters),
                len(tt[1]),
                f"Expected {len(tt[1])} params, got {len(function.parameters)}.",
            )

            for i, ident in enumerate(tt[1]):
                self._test_literal_exp(function.parameters[i], ident)
Example #8
0
    def test_if_else_exp(self):
        input_case = "if (x < y) { x } else { y }"

        lexer = Lexer(input_case)
        parser = Parser(lexer)

        program = parser.parse_program()

        self._check_parser_errors(parser)

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

        stmt = program.statements[0]

        if not isinstance(stmt, ExpressionStatement):
            self.fail(f"Expected ExpressionStatement, got {stmt}.")

        exp = stmt.expression
        if not isinstance(exp, IfExpression):
            self.fail(f"Expected IfExpression, got {exp}.")

        self._test_infix_exp(exp.condition, "x", "<", "y")

        self.assertEqual(
            len(exp.consequence.statements),
            1,
            f"If Consequence has not enough statements, got {len(program.statements)}.",
        )

        consequence = exp.consequence.statements[0]

        if not isinstance(consequence, ExpressionStatement):
            self.fail(f"Expected ExpressionStatement, got {consequence}.")

        self._test_identifier(consequence.expression, "x")

        self.assertEqual(
            len(exp.alternative.statements),
            1,
            f"exp.alternative was not None, got {exp.alternative}",
        )

        alt = exp.alternative.statements[0]
        if not isinstance(alt, ExpressionStatement):
            self.fail(f"Expected ExpressionStatement, got {alt}.")
        self._test_identifier(alt.expression, "y")
Example #9
0
    def test_parsing_emptydict(self):
        input_case = "{}"
        lexer = Lexer(input_case)
        parser = Parser(lexer)

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

        stmt = program.statements[0].expression
        if not isinstance(stmt, DictionaryLiteral):
            self.fail(f"Expected DictionaryLiteral, got {stmt}.")

        self.assertEqual(
            len(stmt.pairs), 0,
            f"hash.pairs has wrong length. got {len(stmt.pairs)}.")
Example #10
0
    def test_parsing_index_exp(self):
        input_case = "myArray[1 + 1]"
        lexer = Lexer(input_case)
        parser = Parser(lexer)

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

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

        if not isinstance(index_exp, IndexExpression):
            self.fail(f"exp not ast.IndexExpression. got={index_exp}")

        self._test_identifier(
            index_exp.left,
            "myArray",
        )
        self._test_infix_exp(index_exp.index, 1, "+", 1)
Example #11
0
    def test_string_literal_exp(self):
        input_case = '"hello world";'
        lexer = Lexer(input_case)
        parser = Parser(lexer)

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

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

        if not isinstance(literal, StringLiteral):
            self.fail(f"literal is not a StringLiteral, got {literal}.")

        self.assertEqual(
            literal.value,
            "hello world",
            f"literal value expected 'hello world', got {literal.value}.",
        )
Example #12
0
    def test_function_literal_parsing(self):
        input_case = "fn(x, y) { x + y; }"

        lexer = Lexer(input_case)
        parser = Parser(lexer)

        program = parser.parse_program()

        self._check_parser_errors(parser)

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

        stmt = program.statements[0]

        if not isinstance(stmt, ExpressionStatement):
            self.fail(f"Expected ExpressionStatement, got {stmt}.")

        exp = stmt.expression
        if not isinstance(exp, FunctionLiteral):
            self.fail(f"Expected FunctionLiteral, got {exp}.")

        self.assertEqual(len(exp.parameters), 2,
                         f"Expected 2 params, got {len(exp.parameters)}.")
        self._test_literal_exp(exp.parameters[0], "x")
        self._test_literal_exp(exp.parameters[1], "y")

        self.assertEqual(
            len(exp.body.statements),
            1,
            f"Expected 1 statement, got {len(exp.body.statements)}.",
        )

        body_stmt = exp.body.statements[0]
        if not isinstance(body_stmt, ExpressionStatement):
            self.fail(f"Expected ExpressionStatement, got {body_stmt}.")

        self._test_infix_exp(body_stmt.expression, "x", "+", "y")
Example #13
0
    def test_parsing_array_literals(self):
        input_case = "[1, 2 * 2, 3 + 3]"
        lexer = Lexer(input_case)
        parser = Parser(lexer)

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

        stmt = program.statements[0]
        array = stmt.expression
        if not isinstance(array, ArrayLiteral):
            self.fail(f"exp not ast.ArrayLiteral. got={array}")

        self.assertEqual(
            len(array.elements),
            3,
            f"len(array.elements) not 3. got={len(array.elements)}",
        )

        self._test_int_literal(array.elements[0], 1)
        self._test_infix_exp(array.elements[1], 2, "*", 2)
        self._test_infix_exp(array.elements[2], 3, "+", 3)
Example #14
0
    def test_parsing_infix_exp(self):
        infix_tests = [
            ["5 + 5;", 5, "+", 5],
            ["5 - 5;", 5, "-", 5],
            ["5 * 5;", 5, "*", 5],
            ["1.5 * 1.5;", 1.5, "*", 1.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:
            lexer = Lexer(tt[0])
            parser = Parser(lexer)

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

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

            if not isinstance(program.statements[0], ExpressionStatement):
                self.fail(
                    f"program.statements[0] not a instance of ExpressionStatement."
                )

            ident = program.statements[0].expression
            self._test_infix_exp(ident, tt[1], tt[2], tt[3])
Example #15
0
    def test_parsing_prefix_exp(self):
        prefix_tests = [
            ["!5;", "!", 5],
            ["-15;", "-", 15],
            ["!true", "!", True],
            ["!false", "!", False],
        ]

        for tt in prefix_tests:
            lexer = Lexer(tt[0])
            parser = Parser(lexer)

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

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

            if not isinstance(program.statements[0], ExpressionStatement):
                self.fail(
                    f"program.statements[0] not a instance of ExpressionStatement."
                )

            ident = program.statements[0].expression
            if not isinstance(ident, PrefixExpression):
                self.fail(f"Exp not a instance of PrefixExpression.")

            self.assertEqual(
                ident.operator,
                tt[1],
                f"ident.operator != {tt[1]}, got {ident.operator}.",
            )

            self._test_literal_exp(ident.right, tt[2])
Example #16
0
    def test_parsing_dict(self):
        input_case = '{"one": 1, "two": 2, "three": 3}'
        lexer = Lexer(input_case)
        parser = Parser(lexer)

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

        stmt = program.statements[0].expression
        if not isinstance(stmt, DictionaryLiteral):
            self.fail(f"Expected DictionaryLiteral, got {stmt}.")

        self.assertEqual(
            len(stmt.pairs), 3,
            f"hash.pairs has wrong length. got {len(stmt.pairs)}.")

        tests = {"one": 1, "two": 2, "three": 3}

        for key, val in stmt.pairs.items():
            if not isinstance(key, StringLiteral):
                self.fail(f"key not StringLiteral, got {key}.")

            expected = tests[str(key)]
            self._test_int_literal(val, expected)
Example #17
0
    def test_let(self):
        tests = [
            ["let x = 5;", "x", 5],
            ["let y = true;", "y", True],
            ["let foobar = y;", "foobar", "y"],
        ]

        for tt in tests:
            lexer = Lexer(tt[0])
            parser = Parser(lexer)

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

            self.assertEqual(
                len(program.statements),
                1,
                f"Expected no. of statements is 1, found {len(program.statements)}.",
            )

            stmt = program.statements[0]

            self._test_let_statement(stmt, tt[1])
            self._test_literal_exp(stmt.value, tt[2])
Example #18
0
    def test_complex_exp(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", "(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)))"
            ],
            [
                "3 + 4 * 5 == 3 * 1 + 4 * 5",
                "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))"
            ],
            [
                "3.12 + 4 * 5.3 == 3 * 1 + 4 * 5",
                "((3.12 + (4 * 5.3)) == ((3 * 1) + (4 * 5)))",
            ],
            ["true", "true"],
            ["false", "false"],
            ["3 > 5 == false", "((3 > 5) == false)"],
            ["3.5 > 5.039411 == false", "((3.5 > 5.039411) == 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))"
            ],
            [
                "a * [1, 2, 3, 4][b * c] * d",
                "((a * ([1, 2, 3, 4][(b * c)])) * d)"
            ],
            [
                "add(a * b[2], b[1], 2 * [1, 2][1])",
                "add((a * (b[2])), (b[1]), (2 * ([1, 2][1])))",
            ],
        ]

        for tt in tests:
            lexer = Lexer(tt[0])
            parser = Parser(lexer)
            program = parser.parse_program()
            self._check_parser_errors(parser)

            actual = str(program)

            self.assertEqual(actual, tt[1],
                             f"Expected {tt[1]}, got {str(program)}.")