mirror of
https://github.com/python/cpython.git
synced 2025-07-13 22:35:18 +00:00

(Code contributed by Jiwon Seo.) The documentation portion of the patch is being re-worked and will be checked-in soon. Likewise, PEP 289 will be updated to reflect Guido's rationale for the design decisions on binding behavior (as described in in his patch comments and in discussions on python-dev). The test file, test_genexps.py, is written in doctest format and is meant to exercise all aspects of the the patch. Further additions are welcome from everyone. Please stress test this new feature as much as possible before the alpha release.
386 lines
12 KiB
Python
386 lines
12 KiB
Python
import parser
|
|
import unittest
|
|
from test import test_support
|
|
|
|
#
|
|
# First, we test that we can generate trees from valid source fragments,
|
|
# and that these valid trees are indeed allowed by the tree-loading side
|
|
# of the parser module.
|
|
#
|
|
|
|
class RoundtripLegalSyntaxTestCase(unittest.TestCase):
|
|
|
|
def roundtrip(self, f, s):
|
|
st1 = f(s)
|
|
t = st1.totuple()
|
|
try:
|
|
st2 = parser.sequence2st(t)
|
|
except parser.ParserError:
|
|
self.fail("could not roundtrip %r" % s)
|
|
|
|
self.assertEquals(t, st2.totuple(),
|
|
"could not re-generate syntax tree")
|
|
|
|
def check_expr(self, s):
|
|
self.roundtrip(parser.expr, s)
|
|
|
|
def check_suite(self, s):
|
|
self.roundtrip(parser.suite, s)
|
|
|
|
def test_yield_statement(self):
|
|
self.check_suite("def f(): yield 1")
|
|
self.check_suite("def f(): return; yield 1")
|
|
self.check_suite("def f(): yield 1; return")
|
|
self.check_suite("def f():\n"
|
|
" for x in range(30):\n"
|
|
" yield x\n")
|
|
|
|
def test_expressions(self):
|
|
self.check_expr("foo(1)")
|
|
self.check_expr("[1, 2, 3]")
|
|
self.check_expr("[x**3 for x in range(20)]")
|
|
self.check_expr("[x**3 for x in range(20) if x % 3]")
|
|
self.check_expr("foo(*args)")
|
|
self.check_expr("foo(*args, **kw)")
|
|
self.check_expr("foo(**kw)")
|
|
self.check_expr("foo(key=value)")
|
|
self.check_expr("foo(key=value, *args)")
|
|
self.check_expr("foo(key=value, *args, **kw)")
|
|
self.check_expr("foo(key=value, **kw)")
|
|
self.check_expr("foo(a, b, c, *args)")
|
|
self.check_expr("foo(a, b, c, *args, **kw)")
|
|
self.check_expr("foo(a, b, c, **kw)")
|
|
self.check_expr("foo + bar")
|
|
self.check_expr("foo - bar")
|
|
self.check_expr("foo * bar")
|
|
self.check_expr("foo / bar")
|
|
self.check_expr("foo // bar")
|
|
self.check_expr("lambda: 0")
|
|
self.check_expr("lambda x: 0")
|
|
self.check_expr("lambda *y: 0")
|
|
self.check_expr("lambda *y, **z: 0")
|
|
self.check_expr("lambda **z: 0")
|
|
self.check_expr("lambda x, y: 0")
|
|
self.check_expr("lambda foo=bar: 0")
|
|
self.check_expr("lambda foo=bar, spaz=nifty+spit: 0")
|
|
self.check_expr("lambda foo=bar, **z: 0")
|
|
self.check_expr("lambda foo=bar, blaz=blat+2, **z: 0")
|
|
self.check_expr("lambda foo=bar, blaz=blat+2, *y, **z: 0")
|
|
self.check_expr("lambda x, *y, **z: 0")
|
|
self.check_expr("(x for x in range(10))")
|
|
self.check_expr("foo(x for x in range(10))")
|
|
|
|
def test_print(self):
|
|
self.check_suite("print")
|
|
self.check_suite("print 1")
|
|
self.check_suite("print 1,")
|
|
self.check_suite("print >>fp")
|
|
self.check_suite("print >>fp, 1")
|
|
self.check_suite("print >>fp, 1,")
|
|
|
|
def test_simple_expression(self):
|
|
# expr_stmt
|
|
self.check_suite("a")
|
|
|
|
def test_simple_assignments(self):
|
|
self.check_suite("a = b")
|
|
self.check_suite("a = b = c = d = e")
|
|
|
|
def test_simple_augmented_assignments(self):
|
|
self.check_suite("a += b")
|
|
self.check_suite("a -= b")
|
|
self.check_suite("a *= b")
|
|
self.check_suite("a /= b")
|
|
self.check_suite("a //= b")
|
|
self.check_suite("a %= b")
|
|
self.check_suite("a &= b")
|
|
self.check_suite("a |= b")
|
|
self.check_suite("a ^= b")
|
|
self.check_suite("a <<= b")
|
|
self.check_suite("a >>= b")
|
|
self.check_suite("a **= b")
|
|
|
|
def test_function_defs(self):
|
|
self.check_suite("def f(): pass")
|
|
self.check_suite("def f(*args): pass")
|
|
self.check_suite("def f(*args, **kw): pass")
|
|
self.check_suite("def f(**kw): pass")
|
|
self.check_suite("def f(foo=bar): pass")
|
|
self.check_suite("def f(foo=bar, *args): pass")
|
|
self.check_suite("def f(foo=bar, *args, **kw): pass")
|
|
self.check_suite("def f(foo=bar, **kw): pass")
|
|
|
|
self.check_suite("def f(a, b): pass")
|
|
self.check_suite("def f(a, b, *args): pass")
|
|
self.check_suite("def f(a, b, *args, **kw): pass")
|
|
self.check_suite("def f(a, b, **kw): pass")
|
|
self.check_suite("def f(a, b, foo=bar): pass")
|
|
self.check_suite("def f(a, b, foo=bar, *args): pass")
|
|
self.check_suite("def f(a, b, foo=bar, *args, **kw): pass")
|
|
self.check_suite("def f(a, b, foo=bar, **kw): pass")
|
|
|
|
def test_import_from_statement(self):
|
|
self.check_suite("from sys.path import *")
|
|
self.check_suite("from sys.path import dirname")
|
|
self.check_suite("from sys.path import dirname as my_dirname")
|
|
self.check_suite("from sys.path import dirname, basename")
|
|
self.check_suite(
|
|
"from sys.path import dirname as my_dirname, basename")
|
|
self.check_suite(
|
|
"from sys.path import dirname, basename as my_basename")
|
|
|
|
def test_basic_import_statement(self):
|
|
self.check_suite("import sys")
|
|
self.check_suite("import sys as system")
|
|
self.check_suite("import sys, math")
|
|
self.check_suite("import sys as system, math")
|
|
self.check_suite("import sys, math as my_math")
|
|
|
|
def test_pep263(self):
|
|
self.check_suite("# -*- coding: iso-8859-1 -*-\n"
|
|
"pass\n")
|
|
|
|
def test_assert(self):
|
|
self.check_suite("assert alo < ahi and blo < bhi\n")
|
|
|
|
#
|
|
# Second, we take *invalid* trees and make sure we get ParserError
|
|
# rejections for them.
|
|
#
|
|
|
|
class IllegalSyntaxTestCase(unittest.TestCase):
|
|
|
|
def check_bad_tree(self, tree, label):
|
|
try:
|
|
parser.sequence2st(tree)
|
|
except parser.ParserError:
|
|
pass
|
|
else:
|
|
self.fail("did not detect invalid tree for %r" % label)
|
|
|
|
def test_junk(self):
|
|
# not even remotely valid:
|
|
self.check_bad_tree((1, 2, 3), "<junk>")
|
|
|
|
def test_illegal_yield_1(self):
|
|
# Illegal yield statement: def f(): return 1; yield 1
|
|
tree = \
|
|
(257,
|
|
(264,
|
|
(285,
|
|
(259,
|
|
(1, 'def'),
|
|
(1, 'f'),
|
|
(260, (7, '('), (8, ')')),
|
|
(11, ':'),
|
|
(291,
|
|
(4, ''),
|
|
(5, ''),
|
|
(264,
|
|
(265,
|
|
(266,
|
|
(272,
|
|
(275,
|
|
(1, 'return'),
|
|
(313,
|
|
(292,
|
|
(293,
|
|
(294,
|
|
(295,
|
|
(297,
|
|
(298,
|
|
(299,
|
|
(300,
|
|
(301,
|
|
(302, (303, (304, (305, (2, '1')))))))))))))))))),
|
|
(264,
|
|
(265,
|
|
(266,
|
|
(272,
|
|
(276,
|
|
(1, 'yield'),
|
|
(313,
|
|
(292,
|
|
(293,
|
|
(294,
|
|
(295,
|
|
(297,
|
|
(298,
|
|
(299,
|
|
(300,
|
|
(301,
|
|
(302,
|
|
(303, (304, (305, (2, '1')))))))))))))))))),
|
|
(4, ''))),
|
|
(6, ''))))),
|
|
(4, ''),
|
|
(0, ''))))
|
|
self.check_bad_tree(tree, "def f():\n return 1\n yield 1")
|
|
|
|
def test_illegal_yield_2(self):
|
|
# Illegal return in generator: def f(): return 1; yield 1
|
|
tree = \
|
|
(257,
|
|
(264,
|
|
(265,
|
|
(266,
|
|
(278,
|
|
(1, 'from'),
|
|
(281, (1, '__future__')),
|
|
(1, 'import'),
|
|
(279, (1, 'generators')))),
|
|
(4, ''))),
|
|
(264,
|
|
(285,
|
|
(259,
|
|
(1, 'def'),
|
|
(1, 'f'),
|
|
(260, (7, '('), (8, ')')),
|
|
(11, ':'),
|
|
(291,
|
|
(4, ''),
|
|
(5, ''),
|
|
(264,
|
|
(265,
|
|
(266,
|
|
(272,
|
|
(275,
|
|
(1, 'return'),
|
|
(313,
|
|
(292,
|
|
(293,
|
|
(294,
|
|
(295,
|
|
(297,
|
|
(298,
|
|
(299,
|
|
(300,
|
|
(301,
|
|
(302, (303, (304, (305, (2, '1')))))))))))))))))),
|
|
(264,
|
|
(265,
|
|
(266,
|
|
(272,
|
|
(276,
|
|
(1, 'yield'),
|
|
(313,
|
|
(292,
|
|
(293,
|
|
(294,
|
|
(295,
|
|
(297,
|
|
(298,
|
|
(299,
|
|
(300,
|
|
(301,
|
|
(302,
|
|
(303, (304, (305, (2, '1')))))))))))))))))),
|
|
(4, ''))),
|
|
(6, ''))))),
|
|
(4, ''),
|
|
(0, ''))))
|
|
self.check_bad_tree(tree, "def f():\n return 1\n yield 1")
|
|
|
|
def test_print_chevron_comma(self):
|
|
# Illegal input: print >>fp,
|
|
tree = \
|
|
(257,
|
|
(264,
|
|
(265,
|
|
(266,
|
|
(268,
|
|
(1, 'print'),
|
|
(35, '>>'),
|
|
(290,
|
|
(291,
|
|
(292,
|
|
(293,
|
|
(295,
|
|
(296,
|
|
(297,
|
|
(298, (299, (300, (301, (302, (303, (1, 'fp')))))))))))))),
|
|
(12, ','))),
|
|
(4, ''))),
|
|
(0, ''))
|
|
self.check_bad_tree(tree, "print >>fp,")
|
|
|
|
def test_a_comma_comma_c(self):
|
|
# Illegal input: a,,c
|
|
tree = \
|
|
(258,
|
|
(311,
|
|
(290,
|
|
(291,
|
|
(292,
|
|
(293,
|
|
(295,
|
|
(296,
|
|
(297,
|
|
(298, (299, (300, (301, (302, (303, (1, 'a')))))))))))))),
|
|
(12, ','),
|
|
(12, ','),
|
|
(290,
|
|
(291,
|
|
(292,
|
|
(293,
|
|
(295,
|
|
(296,
|
|
(297,
|
|
(298, (299, (300, (301, (302, (303, (1, 'c'))))))))))))))),
|
|
(4, ''),
|
|
(0, ''))
|
|
self.check_bad_tree(tree, "a,,c")
|
|
|
|
def test_illegal_operator(self):
|
|
# Illegal input: a $= b
|
|
tree = \
|
|
(257,
|
|
(264,
|
|
(265,
|
|
(266,
|
|
(267,
|
|
(312,
|
|
(291,
|
|
(292,
|
|
(293,
|
|
(294,
|
|
(296,
|
|
(297,
|
|
(298,
|
|
(299,
|
|
(300, (301, (302, (303, (304, (1, 'a'))))))))))))))),
|
|
(268, (37, '$=')),
|
|
(312,
|
|
(291,
|
|
(292,
|
|
(293,
|
|
(294,
|
|
(296,
|
|
(297,
|
|
(298,
|
|
(299,
|
|
(300, (301, (302, (303, (304, (1, 'b'))))))))))))))))),
|
|
(4, ''))),
|
|
(0, ''))
|
|
self.check_bad_tree(tree, "a $= b")
|
|
|
|
def test_malformed_global(self):
|
|
#doesn't have global keyword in ast
|
|
tree = (257,
|
|
(264,
|
|
(265,
|
|
(266,
|
|
(282, (1, 'foo'))), (4, ''))),
|
|
(4, ''),
|
|
(0, ''))
|
|
self.check_bad_tree(tree, "malformed global ast")
|
|
|
|
def test_main():
|
|
test_support.run_unittest(
|
|
RoundtripLegalSyntaxTestCase,
|
|
IllegalSyntaxTestCase
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_main()
|