Example #1
0
    def test_do_while_statement(self):
        source_code = """
        do while .t.
            return 1
        enddo
        """
        lexer = Lexer(source_code)
        parser = Parser(lexer)
        program = parser.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)}'
        )

        do_while = program.statements[0]

        condition = do_while.condition
        self.assertEqual(
            True, condition.value,
            f'condition.value is not True, got={condition.value}')

        body = do_while.block.statements[0]
        integer = body.value

        self.assertEqual(1, integer.value,
                         f'integer.value is not 1, got={integer.value}')
Example #2
0
    def test_function_with_params(self):
        source_code = """
        function retorna_1(foo, bar)
            return 1
        endfunc
        """
        lexer = Lexer(source_code)
        parser = Parser(lexer)
        program = parser.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)}'
        )

        func = program.statements[0]
        self.assertEqual("retorna_1", func.name.value)

        identi1 = func.params[0]
        self.assertEqual("foo", identi1.value,
                         f'identi1.value no es foo, got={identi1.value}')

        identi2 = func.params[1]
        self.assertEqual("bar", identi2.value,
                         f'identi1.value no es bar, got={identi2.value}')

        return_ast = func.body.statements[0]
        integer = return_ast.value

        self.assertEqual(1, integer.value,
                         f'integer.value no es 1, got={integer.value}')
Example #3
0
    def test_unary_expressions(self):
        tests = [
            ["!5", "!", 5],
            ["-15", "-", 15],
            ["!.t.", "!", True],
            ["!.f.", "!", False],
        ]

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

            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.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)}'
            )

            exp = program.statements[0]

            self.assertEqual(
                exp.operator, operator,
                f"exp.operator is not '{operator}'. got={exp.operator}")
            self.assertEqual(
                exp.right.value, value,
                f'exp.right is not {value}. got={exp.right.value}')
Example #4
0
    def test_if_else_statement(self):
        source_code = """
        if .t.
            return 1
        else
            return 2
        endif
        """
        lexer = Lexer(source_code)
        parser = Parser(lexer)
        program = parser.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)}'
        )

        if_stmt = program.statements[0]

        self.assertEqual(if_stmt.condition.value,
                         True)  # Condición del if (.t.)
        # Consecuencia
        return_if_ast = if_stmt.consequence.statements[0]
        integer_ast = return_if_ast.value
        self.assertEqual(
            1, integer_ast.value,
            f'integer_ast.value is not 1, got={integer_ast.value}.')
        # Alternativa
        return_else_ast = if_stmt.alternative.statements[0]
        integer_ast = return_else_ast.value
        self.assertEqual(
            2, integer_ast.value,
            f'integer_ast.value is not 2, got={integer_ast.value}.')
Example #5
0
    def assert_test_eval(self, source):
        lexer = Lexer(source)
        parser = Parser(lexer)
        program = parser.program()
        eva = Evaluator()
        env = Environment()

        return eva.eval(ast_node=program, env=env)
Example #6
0
    def test_null(self):
        lexer = Lexer(".null.")
        parser = Parser(lexer)
        program = parser.program()
        self.assert_check_parser_errors(parser)
        self.assertEqual(1, len(program.statements))

        null = program.statements[0]
        self.assertEqual(None, null.value,
                         f'boolean.value is not None. got={null.value}')
Example #7
0
    def test_function_call_no_params(self):
        lexer = Lexer("foo()")
        parser = Parser(lexer)
        program = parser.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)}'
        )

        func = program.statements[0]
        self.assertEqual("foo", func.name.value,
                         f'func.name no es foo, got={func.name.value}')
Example #8
0
    def test_integer(self):
        lexer = Lexer("5")
        parser = Parser(lexer)

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

        self.assertEqual(
            1, len(program.statements),
            f'program has not enough statements. got={len(program.statements)}'
        )
        integer = program.statements[0]
        self.assertEqual(5, integer.value,
                         f'integer.value is not 5. got={integer.value}')
Example #9
0
    def test_string(self):
        lexer = Lexer('"hello world"')
        parser = Parser(lexer)

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

        self.assertEqual(
            1, len(program.statements),
            f'program has not enough statements. got={len(program.statements)}'
        )
        string = program.statements[0]
        self.assertEqual(
            "hello world", string.value,
            f'string.value is not hello world. got={string.value}')
Example #10
0
    def test_identifier(self):
        lexer = Lexer("foobar")
        parser = Parser(lexer)

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

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

        ident = program.statements[0]

        self.assertEqual("foobar", ident.value,
                         f'ident.value not "foobar" got={ident.value}')
Example #11
0
    def test_assignment_statement(self):
        lexer = Lexer("foo = bar")
        parser = Parser(lexer)
        program = parser.program()
        self.assert_check_parser_errors(parser)
        self.assertEqual(1, len(program.statements))

        assignment = program.statements[0]
        ident_var = assignment.name
        ident_value = assignment.value

        self.assertEqual("foo", ident_var.value,
                         f'ident.value is not foo. got={ident_var.value}')
        self.assertEqual(
            "bar", ident_value.value,
            f'ident_value.value is not bar. got={ident_value.value}')
Example #12
0
def repl():
    """
    REPL: se llama así por cada una de las fases que realiza durante 1 ciclo:
    R: Read - Leer y analizar (parse) el código fuente.
    E: Eval - Evaluar el AST generado por el parser.
    P: Print - Imprimir el resultado en la consola.
    L: Loop - Repetir el ciclo.
    :return:
    """
    print_header()
    env = Environment()
    source_code = ''
    while True:
        try:
            user_input = input(">> ")
        except EOFError:
            break
        if not user_input:
            continue
        """
        Usamos el ';' para unir declaraciones de más de 1 línea.
        """
        if user_input[len(user_input) - 1] == ';':
            source_code += '\n' + user_input[0:len(user_input) - 1]
            continue
        else:
            source_code += '\n' + user_input

        if user_input == 'quit':
            break

        lexer = Lexer(source_code)
        parser = Parser(lexer)
        program = parser.program()

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

        evaluator = Evaluator()
        evaluated = evaluator.eval(ast_node=program, env=env)
        if evaluated is not None:
            print(evaluated.to_string())

        source_code = ''
Example #13
0
    def test_boolean(self):
        tests = [
            [".t.", True],
            [".f.", False],
        ]
        for tt in tests:
            source = tt[0]
            expected = tt[1]

            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.program()
            self.assert_check_parser_errors(parser)
            self.assertEqual(1, len(program.statements))

            boolean = program.statements[0]
            self.assertEqual(
                expected, boolean.value,
                f'boolean.value is not {expected}. got={boolean.value}')
Example #14
0
    def test_binary_expressions(self):
        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],
            [".t. == .t.", True, "==", True],
            [".t. != .f.", True, "!=", False],
            [".f. == .f.", False, "==", False],
        ]

        for tt in tests:
            source = tt[0]
            left = tt[1]
            operator = tt[2]
            right = tt[3]

            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.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)}'
            )

            exp = program.statements[0]

            self.assertEqual(exp.left.value, left,
                             f'exp.left is not {left}. got={exp.left.value}')
            self.assertEqual(
                exp.operator, operator,
                f"exp.operator is not '{operator}'. got={exp.operator}")
            self.assertEqual(
                exp.right.value, right,
                f'exp.right is not {right}. got={exp.right.value}')
Example #15
0
    def test_function_call_with_args(self):
        lexer = Lexer("foo(1, 2)")
        parser = Parser(lexer)
        program = parser.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)}'
        )

        func = program.statements[0]
        self.assertEqual("foo", func.name.value,
                         f'func.name no es foo, got={func.name.value}')

        # Validar los argumentos
        arg1 = func.arguments[0]
        arg2 = func.arguments[1]
        self.assertEqual(1, arg1.value,
                         f'arg1.value no es 1, got={arg1.value}')
        self.assertEqual(2, arg2.value,
                         f'arg2.value no es 2, got={arg2.value}')
Example #16
0
    def test_return_statement(self):
        tests = [["return \n", Boolean(value=True)],
                 ["return .f.", Boolean(value=False)],
                 ["return 5", Integer(value=5)],
                 ["return foobar", Identifier(value="foobar")],
                 ["return .null.", Null()]]
        for tt in tests:
            source = tt[0]
            expected = tt[1]

            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.program()
            self.assert_check_parser_errors(parser)
            self.assertEqual(1, len(program.statements))

            return_stmt = program.statements[0]
            return_value = return_stmt.value
            self.assertEqual(
                expected.value, return_value.value,
                f'return_stmt.value is not {expected.value}. got={return_value.value}'
            )
Example #17
0
    def test_function_without_parenthesis(self):
        source_code = """
        function retorna_1
            return 1
        endfunc
        """
        lexer = Lexer(source_code)
        parser = Parser(lexer)
        program = parser.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)}'
        )

        func = program.statements[0]
        self.assertEqual("retorna_1", func.name.value)

        return_ast = func.body.statements[0]
        integer = return_ast.value

        self.assertEqual(1, integer.value,
                         f'integer.value no es 1, got={integer.value}')
Example #18
0
    def test_variable_declaration(self):
        tests = [
            [
                "public a",
                VariableDecl(name=Identifier(value="a"), scope='public')
            ],
            [
                "local b",
                VariableDecl(name=Identifier(value="b"), scope='local')
            ],
            [
                "private c",
                VariableDecl(name=Identifier(value="c"), scope='private')
            ],
        ]
        for tt in tests:
            source = tt[0]
            expected = tt[1]

            lexer = Lexer(source)
            parser = Parser(lexer)
            program = parser.program()
            self.assert_check_parser_errors(parser)
            self.assertEqual(1, len(program.statements))

            variable = program.statements[0]

            self.assertEqual(
                expected.name.value, variable.name.value,
                f'expected.token.value is not {expected.name.value}. got={variable.name.value}'
            )

            self.assertEqual(
                expected.scope, variable.scope,
                f'expected.scope is not {expected.scope}. got={variable.scope}'
            )
Example #19
0
    def test_tokens(self):
        source_code = """
        && Ejemplo FoxLite
        x = 10 && Declaración de variable 'x'     
        y = 20 && Declaración de variable 'y'    
        && Prueba de IF
        
        if x >= y
          messagebox("x es mayor")
        else
          ? "x es menor"
        endif
        
        
        do while x < 99
           x = x + 1
           ? "Contando por", x
           
           if x == 55
              return
           endif
        enddo
        a = .t.
        b = .f.
        c = .null.
        """
        expected_tokens = [
            Token(TokenType.IDENT, "x"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.INT, "10"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.IDENT, "y"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.INT, "20"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.IF, "if"),
            Token(TokenType.IDENT, "x"),
            Token(TokenType.GREATER_EQ, ">="),
            Token(TokenType.IDENT, "y"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.MESSAGEBOX, "messagebox"),
            Token(TokenType.LPAREN, "("),
            Token(TokenType.STRING, "x es mayor"),
            Token(TokenType.RPAREN, ")"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.ELSE, "else"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.PRINT, "?"),
            Token(TokenType.STRING, "x es menor"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.ENDIF, "endif"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.DO, "do"),
            Token(TokenType.WHILE, "while"),
            Token(TokenType.IDENT, "x"),
            Token(TokenType.LESS, "<"),
            Token(TokenType.INT, "99"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.IDENT, "x"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.IDENT, "x"),
            Token(TokenType.PLUS, "+"),
            Token(TokenType.INT, "1"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.PRINT, "?"),
            Token(TokenType.STRING, "Contando por"),
            Token(TokenType.COMMA, ","),
            Token(TokenType.IDENT, "x"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.IF, "if"),
            Token(TokenType.IDENT, "x"),
            Token(TokenType.EQUAL, "=="),
            Token(TokenType.INT, "55"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.RETURN, "return"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.ENDIF, "endif"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.ENDDO, "enddo"),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.IDENT, "a"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.TRUE, ".t."),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.IDENT, "b"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.FALSE, ".f."),
            Token(TokenType.LBREAK, "LBREAK"),
            Token(TokenType.IDENT, "c"),
            Token(TokenType.ASSIGN, "="),
            Token(TokenType.NULL, ".null."),
            Token(TokenType.LBREAK, "LBREAK"),
        ]
        lexer = Lexer(source_code=source_code)

        for expected_token in expected_tokens:
            actual = lexer.next_token()
            self.assertEqual(expected_token.type, actual.Type)
            self.assertEqual(expected_token.value, actual.value)