Spaces:
Build error
Build 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() | |