Spaces:
Runtime error
Runtime error
| # mode: run | |
| # tag: syntax | |
| """ | |
| Uses TreeFragment to test invalid syntax. | |
| """ | |
| from __future__ import absolute_import | |
| from ...TestUtils import CythonTest | |
| from ..Errors import CompileError | |
| from .. import ExprNodes | |
| # Copied from CPython's test_grammar.py | |
| VALID_UNDERSCORE_LITERALS = [ | |
| '0_0_0', | |
| '4_2', | |
| '1_0000_0000', | |
| '0b1001_0100', | |
| '0xffff_ffff', | |
| '0o5_7_7', | |
| '1_00_00.5', | |
| '1_00_00.5j', | |
| '1_00_00.5e5', | |
| '1_00_00j', | |
| '1_00_00e5_1', | |
| '1e1_0', | |
| '.1_4', | |
| '.1_4e1', | |
| '.1_4j', | |
| ] | |
| # Copied from CPython's test_grammar.py | |
| INVALID_UNDERSCORE_LITERALS = [ | |
| # Trailing underscores: | |
| '0_', | |
| '42_', | |
| '1.4j_', | |
| '0b1_', | |
| '0xf_', | |
| '0o5_', | |
| # Underscores in the base selector: | |
| '0_b0', | |
| '0_xf', | |
| '0_o5', | |
| # Underscore right after the base selector: | |
| '0b_0', | |
| '0x_f', | |
| '0o_5', | |
| # Old-style octal, still disallowed: | |
| #'0_7', | |
| #'09_99', | |
| # Special case with exponent: | |
| '0 if 1_Else 1', | |
| # Underscore right before a dot: | |
| '1_.4', | |
| '1_.4j', | |
| # Underscore right after a dot: | |
| '1._4', | |
| '1._4j', | |
| '._5', | |
| # Underscore right after a sign: | |
| '1.0e+_1', | |
| # Multiple consecutive underscores: | |
| '4_______2', | |
| '0.1__4', | |
| '0b1001__0100', | |
| '0xffff__ffff', | |
| '0o5__77', | |
| '1e1__0', | |
| # Underscore right before j: | |
| '1.4_j', | |
| '1.4e5_j', | |
| # Underscore right before e: | |
| '1_e1', | |
| '1.4_e1', | |
| # Underscore right after e: | |
| '1e_1', | |
| '1.4e_1', | |
| # Whitespace in literals | |
| '1_ 2', | |
| '1 _2', | |
| '1_2.2_ 1', | |
| '1_2.2 _1', | |
| '1_2e _1', | |
| '1_2e2 _1', | |
| '1_2e 2_1', | |
| ] | |
| class TestGrammar(CythonTest): | |
| def test_invalid_number_literals(self): | |
| for literal in INVALID_UNDERSCORE_LITERALS: | |
| for expression in ['%s', '1 + %s', '%s + 1', '2 * %s', '%s * 2']: | |
| code = 'x = ' + expression % literal | |
| try: | |
| self.fragment(u'''\ | |
| # cython: language_level=3 | |
| ''' + code) | |
| except CompileError as exc: | |
| assert code in [s.strip() for s in str(exc).splitlines()], str(exc) | |
| else: | |
| assert False, "Invalid Cython code '%s' failed to raise an exception" % code | |
| def test_valid_number_literals(self): | |
| for literal in VALID_UNDERSCORE_LITERALS: | |
| for i, expression in enumerate(['%s', '1 + %s', '%s + 1', '2 * %s', '%s * 2']): | |
| code = 'x = ' + expression % literal | |
| node = self.fragment(u'''\ | |
| # cython: language_level=3 | |
| ''' + code).root | |
| assert node is not None | |
| literal_node = node.stats[0].rhs # StatListNode([SingleAssignmentNode('x', expr)]) | |
| if i > 0: | |
| # Add/MulNode() -> literal is first or second operand | |
| literal_node = literal_node.operand2 if i % 2 else literal_node.operand1 | |
| if 'j' in literal or 'J' in literal: | |
| assert isinstance(literal_node, ExprNodes.ImagNode) | |
| elif '.' in literal or 'e' in literal or 'E' in literal and not ('0x' in literal or '0X' in literal): | |
| assert isinstance(literal_node, ExprNodes.FloatNode) | |
| else: | |
| assert isinstance(literal_node, ExprNodes.IntNode) | |
| if __name__ == "__main__": | |
| import unittest | |
| unittest.main() | |