Пример #1
0
    def test_simple_block_of_statements(self):
        '''Can parse a nested block of statements:
           `int x;
            {
              int y;
              x = 5;
            }`
        '''
        given = iter([
            Token('INT_TYPE', 'int'),
            Token('ID', 'x'),
            Token('SEMI', ';'),

            Token('LCURLY', '{'),
            Token('INT_TYPE', 'int'),
            Token('ID', 'y'),
            Token('SEMI', ';'),
            Token('ID', 'x'),
            Token('EQUAL', '='),
            Token('INTEGER', '5'),
            Token('SEMI', ';'),
            Token('RCURLY', '}'),
        ])

        expected = ast.Block([
            ast.Declaration('int', [ast.ID('x')]),
            ast.Block([
                ast.Declaration('int', [ast.ID('y')]),
                ast.Assignment(ast.ID('x'), ast.Integer(5))
            ])
        ])

        result = parser.parse(given)

        assert expected == result
Пример #2
0
    def test_single_if_statement(self):
        '''Can parse a single if statement
           `if (1) {
              duck = 3;
            }`
        '''
        given = iter([
            Token('IF', 'if'),
            Token('LPAREN', '('),
            Token('INTEGER', '1'),
            Token('RPAREN', ')'),

            Token('LCURLY', '{'),
            Token('ID', 'duck'),
            Token('EQUAL', '='),
            Token('INTEGER', '3'),
            Token('SEMI', ';'),
            Token('RCURLY', '}'),
        ])

        expected = ast.Block([
            ast.IfStatement(
                ast.Integer(1),
                ast.Block([
                    ast.Assignment(ast.ID('duck'), ast.Integer(3))
                ]),
                ast.Block([])
            )
        ])

        result = parser.parse(given)

        assert expected == result
Пример #3
0
    def test_if_statement_error(self):
        '''An error with given program:
           `int x;
            if (x) {
              x = 1.0;
            } else {
              x = 0;
            }`'''

        given = ast.Block([
            ast.Declaration('int', [ast.ID('x')]),
            ast.IfStatement(
                ast.ID('x'),
                ast.Block([ast.Assignment(ast.ID('x'), ast.Float(1.0))]),
                ast.Block([ast.Assignment(ast.ID('x'), ast.Integer(0))]),
            )
        ])

        report = typechecker.typecheck(given)
        expected_errors = [
            TypecheckerError(ast.Assignment(ast.ID('x'), ast.Float(1.0)))
        ]

        for (r, e) in zip_longest(report.get_errors(), expected_errors):
            assert r == e
Пример #4
0
    def test_simple_program_correct(self):
        '''Can typecheck a simple program:
           `int wildcat, animals[2];
            float duck;

            wildcat = 1;
            duck = 1.0;

            if(duck) {
              animals[0] = wildcat;
              animals[1] = 2;
            } else {
              animals[0] = 1;
            }

            duck = (duck + 2.5) * 33.0 / 2.0;
            `
        '''

        given = ast.Block([
            ast.Declaration('int', [
                ast.ID('wildcat'),
                ast.ArrayRef(ast.ID('animals'), ast.Integer(2))
            ]),
            ast.Declaration('float', [ast.ID('duck')]),
            ast.Assignment(ast.ID('wildcat'), ast.Integer(1)),
            ast.Assignment(ast.ID('duck'), ast.Float(1.0)),
            ast.IfStatement(
                ast.ID('duck'),
                ast.Block([
                    ast.Assignment(
                        ast.ArrayRef(ast.ID('animals'), ast.Integer(0)),
                        ast.ID('wildcat')),
                    ast.Assignment(
                        ast.ArrayRef(ast.ID('animals'), ast.Integer(1)),
                        ast.Integer(2))
                ]),
                ast.Block([
                    ast.Assignment(
                        ast.ArrayRef(ast.ID('animals'), ast.Integer(0)),
                        ast.Integer(1))
                ])),
            ast.Assignment(
                ast.ID('duck'),
                ast.BinOp(
                    '/',
                    ast.BinOp('*',
                              ast.BinOp('+', ast.ID('duck'), ast.Float(2.5)),
                              ast.Float(33.0)), ast.Float(2.0)))
        ])

        report = typechecker.typecheck(given)
        expected_errors = []

        for (r, e) in zip_longest(report.get_errors(), expected_errors):
            assert r == e
Пример #5
0
    def test_compiler_parse(self):
        '''Can parse a simple program:'''
        given = '''
            float duck, goose, birds[2];
            int wildcat;

            duck = 1.0;
            goose = -1;

            wildcat = 1;

            birds[0] = duck;

            if (duck) {
              birds[1] = goose;
            } else {
              birds[1] = wildcat;
            }
        '''

        result = compiler.parse(given)

        expected = ast.Block([
            ast.Declaration('float', [
                ast.ID('duck'),
                ast.ID('goose'),
                ast.ArrayRef(ast.ID('birds'), ast.Integer(2))
            ]),
            ast.Declaration('int', [ast.ID('wildcat')]),
            ast.Assignment(ast.ID('duck'), ast.Float(1.0)),
            ast.Assignment(ast.ID('goose'), ast.UnaryOp('-', ast.Integer(1))),
            ast.Assignment(ast.ID('wildcat'), ast.Integer(1)),
            ast.Assignment(ast.ArrayRef(ast.ID('birds'), ast.Integer(0)),
                           ast.ID('duck')),
            ast.IfStatement(
                ast.ID('duck'),
                ast.Block([
                    ast.Assignment(
                        ast.ArrayRef(ast.ID('birds'), ast.Integer(1)),
                        ast.ID('goose'))
                ]),
                ast.Block([
                    ast.Assignment(
                        ast.ArrayRef(ast.ID('birds'), ast.Integer(1)),
                        ast.ID('wildcat'))
                ])),
        ])

        assert result == expected
Пример #6
0
    def test_if_else_statement(self):
        '''Can parse an if-else statement
           `if (x + 3) {
              duck = x;
            } else {
              goose = x;
            }`
        '''
        given = iter([
            Token('IF', 'if'),
            Token('LPAREN', '('),
            Token('ID', 'x'),
            Token('PLUS', '+'),
            Token('INTEGER', '3'),
            Token('RPAREN', ')'),

            Token('LCURLY', '{'),
            Token('ID', 'duck'),
            Token('EQUAL', '='),
            Token('ID', 'x'),
            Token('SEMI', ';'),
            Token('RCURLY', '}'),

            Token('ELSE', 'else'),

            Token('LCURLY', '{'),
            Token('ID', 'goose'),
            Token('EQUAL', '='),
            Token('ID', 'x'),
            Token('SEMI', ';'),
            Token('RCURLY', '}'),
        ])

        expected = ast.Block([
            ast.IfStatement(
                ast.BinOp('+', ast.ID('x'), ast.Integer(3)),
                ast.Block([
                    ast.Assignment(ast.ID('duck'), ast.ID('x'))
                ]),
                ast.Block([
                    ast.Assignment(ast.ID('goose'), ast.ID('x'))
                ])
            )
        ])

        result = parser.parse(given)

        assert expected == result
Пример #7
0
    def test_id_expr_error(self):
        '''No error with given program:
           `int ducks;
            float wildcats;
            ducks = 100;
            wildcats = 200 % ducks;`'''

        given = ast.Block([
            ast.Declaration('int', [ast.ID('ducks')]),
            ast.Declaration('float', [ast.ID('wildcats')]),
            ast.Assignment(ast.ID('ducks'), ast.Integer(100)),
            ast.Assignment(ast.ID('wildcats'),
                           ast.BinOp('%', ast.Integer(200), ast.ID('ducks')))
        ])

        report = typechecker.typecheck(given)
        expected_errors = [
            TypecheckerError(
                ast.Assignment(
                    ast.ID('wildcats'),
                    ast.BinOp('%', ast.Integer(200), ast.ID('ducks'))))
        ]

        for (r, e) in zip_longest(report.get_errors(), expected_errors):
            assert r == e
Пример #8
0
    def test_unary_op_expression(self):
        '''Unary operations are supported: `(5 + -1) - !3;`'''
        given = iter([
            Token('LPAREN', '('),
            Token('INTEGER', '5'),
            Token('PLUS', '+'),
            Token('MINUS', '-'),
            Token('INTEGER', '1'),
            Token('RPAREN', ')'),
            Token('MINUS', '-'),
            Token('BANG', '!'),
            Token('INTEGER', '3'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Statement(
                ast.BinOp(
                    '-',
                    ast.BinOp(
                        '+',
                        ast.Integer(5),
                        ast.UnaryOp('-', ast.Integer(1))
                    ),
                    ast.UnaryOp('!', ast.Integer(3))
                )
            )
        ])

        assert result == expected
Пример #9
0
    def test_relational_op_order(self):
        '''Relational ops have lowest precedence: `3 * 5 + 3 == 18;`'''
        given = iter([
            Token('INTEGER', '3'),
            Token('MUL', '*'),
            Token('INTEGER', '5'),
            Token('PLUS', '+'),
            Token('INTEGER', '3'),
            Token('EQUAL_EQUAL', '=='),
            Token('INTEGER', '18'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Statement(
                ast.BinOp(
                    '==',
                    ast.BinOp(
                        '+',
                        ast.BinOp('*', ast.Integer(3), ast.Integer(5)),
                        ast.Integer(3)
                    ),
                    ast.Integer(18)
                )
            )
        ])

        assert result == expected
Пример #10
0
    def test_mixed_expression(self):
        '''An expression can have both numbers and ids:
           `x * (y + 10);`'''
        given = iter([
            Token('ID', 'x'),
            Token('MUL', '*'),
            Token('LPAREN', '('),
            Token('ID', 'y'),
            Token('PLUS', '+'),
            Token('INTEGER', '10'),
            Token('RPAREN', ')'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Statement(
                ast.BinOp(
                    '*',
                    ast.ID('x'),
                    ast.BinOp('+', ast.ID('y'), ast.Integer(10))
                )
            )
        ])

        assert result == expected
Пример #11
0
    def test_parens(self):
        '''Honors parenthesis: `(1 + 5) * 20;`'''
        given = iter([
            Token('LPAREN', '('),
            Token('INTEGER', '1'),
            Token('PLUS', '+'),
            Token('INTEGER', '5'),
            Token('RPAREN', ')'),
            Token('MUL', '*'),
            Token('INTEGER', '20'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Statement(
                ast.BinOp(
                    '*',
                    ast.BinOp('+', ast.Integer(1), ast.Integer(5)),
                    ast.Integer(20)
                )
            )
        ])

        assert result == expected
Пример #12
0
    def test_expr_assignment_with_ids(self):
        '''Can parse assignment to expression with ids:
           `duck = (goose + 10) * duck;`'''
        given = iter([
            Token('ID', 'duck'),
            Token('EQUAL', '='),
            Token('LPAREN', '('),
            Token('ID', 'goose'),
            Token('PLUS', '+'),
            Token('INTEGER', '10'),
            Token('RPAREN', ')'),
            Token('MUL', '*'),
            Token('ID', 'duck'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Assignment(
                ast.ID('duck'),
                ast.BinOp(
                    '*',
                    ast.BinOp('+', ast.ID('goose'), ast.Integer(10)),
                    ast.ID('duck')
                )
            )
        ])

        assert result == expected
Пример #13
0
    def test_multiline_assignment(self):
        '''Can parse multiple assignments:
           `x = 5;
            y = 10 * z;
            sum_times_five = (x + y) * 5;`'''
        given = iter([
            Token('ID', 'x'),
            Token('EQUAL', '='),
            Token('INTEGER', '5'),
            Token('SEMI', ';'),
            Token('ID', 'y'),
            Token('EQUAL', '='),
            Token('INTEGER', '10'),
            Token('MUL', '*'),
            Token('ID', 'z'),
            Token('SEMI', ';'),
            Token('ID', 'sum_times_five'),
            Token('EQUAL', '='),
            Token('LPAREN', '('),
            Token('ID', 'x'),
            Token('PLUS', '+'),
            Token('ID', 'y'),
            Token('RPAREN', ')'),
            Token('MUL', '*'),
            Token('INTEGER', '5'),
            Token('SEMI', ';'),
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Assignment(
                ast.ID('x'),
                ast.Integer(5)
            ),
            ast.Assignment(
                ast.ID('y'),
                ast.BinOp('*', ast.Integer(10), ast.ID('z'))
            ),
            ast.Assignment(
                ast.ID('sum_times_five'),
                ast.BinOp(
                    '*',
                    ast.BinOp('+', ast.ID('x'), ast.ID('y')),
                    ast.Integer(5)
                )
            )
        ])

        assert result == expected
Пример #14
0
    def test_simple_correct(self):
        '''No errors with given program:
           `int cowbell;
            cowbell = 2000;`'''

        given = ast.Block([
            ast.Declaration('int', [ast.ID('cowbell')]),
            ast.Assignment(ast.ID('cowbell'), ast.Integer(2000))
        ])

        report = typechecker.typecheck(given)
        expected_errors = []

        for (r, e) in zip_longest(report.get_errors(), expected_errors):
            assert r == e
Пример #15
0
    def test_simple_declaration(self):
        '''Can parse a simple declaration: `int a;`'''
        given = iter([
            Token('INT_TYPE', 'int'),
            Token('ID', 'a'),
            Token('SEMI', ';')
        ])

        expected = ast.Block([
            ast.Declaration('int', [ast.ID('a')])
        ])

        result = parser.parse(given)

        assert expected == result
Пример #16
0
    def test_simple_id(self):
        '''IDs are treated as expressions: `x;`'''
        given = iter([
            Token('ID', 'x'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Statement(
                ast.ID('x')
            )
        ])

        assert result == expected
Пример #17
0
    def test_binop_correct(self):
        '''An error with given program:
           `int more_cowbell;
            more_cowbell = 2000 + 1;`'''

        given = ast.Block([
            ast.Declaration('int', [ast.ID('more_cowbell')]),
            ast.Assignment(ast.ID('more_cowbell'),
                           ast.BinOp('+', ast.Integer(2000), ast.Integer(1)))
        ])

        report = typechecker.typecheck(given)
        expected_errors = []

        for (r, e) in zip_longest(report.get_errors(), expected_errors):
            assert r == e
Пример #18
0
    def test_add(self):
        '''Can parse a simple addition: `1 + 1;`'''
        given = iter([
            Token('INTEGER', '1'),
            Token('PLUS', '+'),
            Token('INTEGER', '1'),
            Token('SEMI', ';')
        ])

        expected = ast.Block([
            ast.Statement(ast.BinOp('+', ast.Integer(1), ast.Integer(1)))
        ])

        result = parser.parse(given)

        assert expected == result
Пример #19
0
    def test_arrayref_expr_correct(self):
        '''No error with given program:
           `int x[3];
            x[0] = 1;`'''

        given = ast.Block([
            ast.Declaration('int',
                            [ast.ArrayRef(ast.ID('x'), ast.Integer(3))]),
            ast.Assignment(ast.ArrayRef(ast.ID('x'), ast.Integer(0)),
                           ast.Integer(1))
        ])

        report = typechecker.typecheck(given)
        expected_errors = []

        for (r, e) in zip_longest(report.get_errors(), expected_errors):
            assert r == e
Пример #20
0
    def test_simple_error(self):
        '''An error with given program:
           `int cowbell;
            cowbell = 2000.0;`'''

        given = ast.Block([
            ast.Declaration('int', [ast.ID('cowbell')]),
            ast.Assignment(ast.ID('cowbell'), ast.Float(2000.0))
        ])

        report = typechecker.typecheck(given)
        expected_errors = [
            TypecheckerError(
                ast.Assignment(ast.ID('cowbell'), ast.Float(2000.0)))
        ]

        for (r, e) in zip_longest(report.get_errors(), expected_errors):
            assert r == e
Пример #21
0
    def test_float_declaration(self):
        '''Can parse float declaration: `float duck;`'''
        given = iter([
            Token('FLOAT_TYPE', 'float'),
            Token('ID', 'duck'),
            Token('SEMI', ';')
        ])

        expected = ast.Block([
            ast.Declaration(
                'float',
                [ast.ID('duck')]
            )
        ])

        result = parser.parse(given)

        assert expected == result
Пример #22
0
    def test_arrayref_expression(self):
        '''Array reference is an expression: `arr[1];`'''
        given = iter([
            Token('ID', 'arr'),
            Token('LBRACE', '['),
            Token('INTEGER', '1'),
            Token('RBRACE', ']'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Statement(
                ast.ArrayRef(ast.ID('arr'), ast.Integer(1))
            )
        ])

        assert result == expected
Пример #23
0
    def test_assignment_to_id(self):
        '''Can parse assignment to another id: `x = y`'''
        given = iter([
            Token('ID', 'x'),
            Token('EQUAL', '='),
            Token('ID', 'y'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Assignment(
                ast.ID('x'),
                ast.ID('y')
            )
        ])

        assert result == expected
Пример #24
0
    def test_simple_assignment(self):
        '''Can parse a simple assignment: `x = 5;`'''
        given = iter([
            Token('ID', 'x'),
            Token('EQUAL', '='),
            Token('INTEGER', '5'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Assignment(
                ast.ID('x'),
                ast.Integer(5)
            )
        ])

        assert result == expected
Пример #25
0
    def test_unary_op_error(self):
        '''An error with given program:
           `int negative_cowbell;
            negative_cowbell = -2000.00;`'''

        given = ast.Block([
            ast.Declaration('int', [ast.ID('negative_cowbell')]),
            ast.Assignment(ast.ID('negative_cowbell'),
                           ast.UnaryOp('-', ast.Float(2000.00)))
        ])

        report = typechecker.typecheck(given)
        expected_errors = [
            TypecheckerError(
                ast.Assignment(ast.ID('negative_cowbell'),
                               ast.UnaryOp('-', ast.Float(2000.00))))
        ]

        for (r, e) in zip_longest(report.get_errors(), expected_errors):
            assert r == e
Пример #26
0
    def test_multiple_declaration(self):
        '''Can parse multiple declaration: `int ducks, and, wildcats;`'''
        given = iter([
            Token('INT_TYPE', 'int'),
            Token('ID', 'ducks'),
            Token('COMMA', ','),
            Token('ID', 'and'),
            Token('COMMA', ','),
            Token('ID', 'wildcats'),
            Token('SEMI', ';')
        ])

        expected = ast.Block([
            ast.Declaration(
                'int',
                [ast.ID('ducks'), ast.ID('and'), ast.ID('wildcats')]
            )
        ])

        result = parser.parse(given)

        assert expected == result
Пример #27
0
    def test_float_expression(self):
        '''Expression with floats and integers: `1.0 + 2;`'''
        given = iter([
            Token('FLOAT', '1.0'),
            Token('PLUS', '+'),
            Token('INTEGER', '2'),
            Token('SEMI', ';')
        ])

        result = parser.parse(given)

        expected = ast.Block([
            ast.Statement(
                ast.BinOp(
                    '+',
                    ast.Float(1.0),
                    ast.Integer(2)
                )
            )
        ])

        assert result == expected
Пример #28
0
    def test_op_order(self):
        '''Enforces the right op. precedence: `1 + 5 * 20;`'''
        given = iter([
            Token('INTEGER', '1'),
            Token('PLUS', '+'),
            Token('INTEGER', '5'),
            Token('MUL', '*'),
            Token('INTEGER', '20'),
            Token('SEMI', ';')
        ])

        expected = ast.Block([
            ast.Statement(
                ast.BinOp(
                    '+',
                    ast.Integer(1),
                    ast.BinOp('*', ast.Integer(5), ast.Integer(20))
                )
            )
        ])

        result = parser.parse(given)

        assert expected == result
Пример #29
0
 def if_statement(s):
     return ast.IfStatement(s[2], s[4], ast.Block([]))
Пример #30
0
    def test_simple_program(self):
        '''Can parse a simple program
           `int x[3], duck, goose, wildcat;

            duck = 1;
            goose = 2;

            x[0] = duck;
            x[duck] = goose;

            if (duck + x[duck]) {
              wildcat = duck;
            } else {
              wildcat = goose;
            }
            x[2] = wildcat;`
        '''
        given = iter([
            Token('INT_TYPE', 'int'),
            Token('ID', 'x'), Token('LBRACE', '['), Token('INTEGER', '3'), Token('RBRACE', ']'), Token('COMMA', ','),
            Token('ID', 'duck'), Token('COMMA', ','),
            Token('ID', 'goose'), Token('COMMA', ','),
            Token('ID', 'wildcat'), Token('SEMI', ';'),

            Token('ID', 'duck'), Token('EQUAL', '='), Token('INTEGER', '1'), Token('SEMI', ';'),
            Token('ID', 'goose'), Token('EQUAL', '='), Token('INTEGER', '2'), Token('SEMI', ';'),
            Token('ID', 'x'), Token('LBRACE', '['), Token('INTEGER', '0'), Token('RBRACE', ']'), Token('EQUAL', '='), Token('ID', 'duck'), Token('SEMI', ';'),
            Token('ID', 'x'), Token('LBRACE', '['), Token('ID', 'duck'), Token('RBRACE', ']'), Token('EQUAL', '='), Token('ID', 'goose'), Token('SEMI', ';'),
            Token('IF', 'if'), Token('LPAREN', '('), Token('ID', 'duck'), Token('PLUS', '+'), Token('ID', 'x'), Token('LBRACE', '['), Token('ID', 'duck'), Token('RBRACE', ']'), Token('RPAREN', ')'),
            Token('LCURLY', '{'), Token('ID', 'wildcat'), Token('EQUAL', '='), Token('ID', 'duck'), Token('SEMI', ';'), Token('RCURLY', '}'),
            Token('ELSE', 'else'), Token('LCURLY', '{'), Token('ID', 'wildcat'), Token('EQUAL', '='), Token('ID', 'goose'), Token('SEMI', ';'), Token('RCURLY', '}'),
            Token('ID', 'x'), Token('LBRACE', '['), Token('INTEGER', '2'), Token('RBRACE', ']'), Token('EQUAL', '='), Token('ID', 'wildcat'), Token('SEMI', ';')
        ])

        expected = ast.Block([
            ast.Declaration(
                'int',
                [ast.ArrayRef(ast.ID('x'), ast.Integer(3)), ast.ID('duck'), ast.ID('goose'), ast.ID('wildcat')]
            ),
            ast.Assignment(ast.ID('duck'), ast.Integer(1)),
            ast.Assignment(ast.ID('goose'), ast.Integer(2)),

            ast.Assignment(ast.ArrayRef(ast.ID('x'), ast.Integer(0)), ast.ID('duck')),
            ast.Assignment(ast.ArrayRef(ast.ID('x'), ast.ID('duck')), ast.ID('goose')),

            ast.IfStatement(
                ast.BinOp('+', ast.ID('duck'), ast.ArrayRef(ast.ID('x'), ast.ID('duck'))),
                ast.Block([
                    ast.Assignment(ast.ID('wildcat'), ast.ID('duck'))
                ]),
                ast.Block([
                    ast.Assignment(ast.ID('wildcat'), ast.ID('goose'))
                ])
            ),

            ast.Assignment(ast.ArrayRef(ast.ID('x'), ast.Integer(2)), ast.ID('wildcat')),
        ])

        result = parser.parse(given)

        assert expected == result