PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/interpreter/astcompiler/test/test_symtable.py

https://bitbucket.org/dac_io/pypy
Python | 359 lines | 341 code | 18 blank | 0 comment | 11 complexity | 6462a23c696ce96a7263115f79aa6199 MD5 | raw file
  1. import string
  2. import py
  3. from pypy.interpreter.astcompiler import ast, astbuilder, symtable, consts
  4. from pypy.interpreter.pyparser import pyparse
  5. from pypy.interpreter.pyparser.error import SyntaxError
  6. class TestSymbolTable:
  7. def setup_class(cls):
  8. cls.parser = pyparse.PythonParser(cls.space)
  9. def mod_scope(self, source, mode="exec"):
  10. info = pyparse.CompileInfo("<test>", mode,
  11. consts.CO_FUTURE_WITH_STATEMENT)
  12. tree = self.parser.parse_source(source, info)
  13. module = astbuilder.ast_from_node(self.space, tree, info)
  14. builder = symtable.SymtableBuilder(self.space, module, info)
  15. scope = builder.find_scope(module)
  16. assert isinstance(scope, symtable.ModuleScope)
  17. return scope
  18. def func_scope(self, func_code):
  19. mod_scope = self.mod_scope(func_code)
  20. assert len(mod_scope.children) == 1
  21. func_name = mod_scope.lookup("f")
  22. assert func_name == symtable.SCOPE_LOCAL
  23. func_scope = mod_scope.children[0]
  24. assert isinstance(func_scope, symtable.FunctionScope)
  25. return func_scope
  26. def class_scope(self, class_code):
  27. mod_scope = self.mod_scope(class_code)
  28. assert len(mod_scope.children) == 1
  29. class_name = mod_scope.lookup("x")
  30. assert class_name == symtable.SCOPE_LOCAL
  31. class_scope = mod_scope.children[0]
  32. assert isinstance(class_scope, symtable.ClassScope)
  33. return class_scope
  34. def gen_scope(self, gen_code):
  35. mod_scope = self.mod_scope(gen_code)
  36. assert len(mod_scope.children) == 1
  37. gen_scope = mod_scope.children[0]
  38. assert isinstance(gen_scope, symtable.FunctionScope)
  39. assert not gen_scope.children
  40. assert gen_scope.name == "genexp"
  41. return mod_scope, gen_scope
  42. def check_unknown(self, scp, *names):
  43. for name in names:
  44. assert scp.lookup(name) == symtable.SCOPE_UNKNOWN
  45. def test_toplevel(self):
  46. scp = self.mod_scope("x = 4")
  47. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  48. assert not scp.locals_fully_known
  49. scp = self.mod_scope("x = 4", "single")
  50. assert not scp.locals_fully_known
  51. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  52. scp = self.mod_scope("x*4*6", "eval")
  53. assert not scp.locals_fully_known
  54. assert scp.lookup("x") == symtable.SCOPE_GLOBAL_IMPLICIT
  55. def test_duplicate_argument(self):
  56. input = "def f(x, x): pass"
  57. exc = py.test.raises(SyntaxError, self.mod_scope, input).value
  58. assert exc.msg == "duplicate argument 'x' in function definition"
  59. def test_function_defaults(self):
  60. scp = self.mod_scope("y = 4\ndef f(x=y): return x")
  61. self.check_unknown(scp, "x")
  62. assert scp.lookup("y") == symtable.SCOPE_LOCAL
  63. scp = scp.children[0]
  64. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  65. self.check_unknown(scp, "y")
  66. def check_comprehension(self, template):
  67. def brack(s):
  68. return template % (s,)
  69. scp, gscp = self.gen_scope(brack("y[1] for y in z"))
  70. assert scp.lookup("z") == symtable.SCOPE_GLOBAL_IMPLICIT
  71. self.check_unknown(scp, "y", "x")
  72. self.check_unknown(gscp, "z")
  73. assert gscp.lookup("y") == symtable.SCOPE_LOCAL
  74. assert gscp.lookup(".0") == symtable.SCOPE_LOCAL
  75. scp, gscp = self.gen_scope(brack("x for x in z if x"))
  76. self.check_unknown(scp, "x")
  77. assert gscp.lookup("x") == symtable.SCOPE_LOCAL
  78. scp, gscp = self.gen_scope(brack("x for y in g for f in n if f[h]"))
  79. self.check_unknown(scp, "f")
  80. assert gscp.lookup("f") == symtable.SCOPE_LOCAL
  81. def test_genexp(self):
  82. self.check_comprehension("(%s)")
  83. def test_setcomp(self):
  84. self.check_comprehension("{%s}")
  85. def test_dictcomp(self):
  86. scp, gscp = self.gen_scope("{x : x[3] for x in y}")
  87. assert scp.lookup("y") == symtable.SCOPE_GLOBAL_IMPLICIT
  88. self.check_unknown(scp, "a", "b", "x")
  89. self.check_unknown(gscp, "y")
  90. assert gscp.lookup("x") == symtable.SCOPE_LOCAL
  91. assert gscp.lookup(".0") == symtable.SCOPE_LOCAL
  92. scp, gscp = self.gen_scope("{x : x[1] for x in y if x[23]}")
  93. self.check_unknown(scp, "x")
  94. assert gscp.lookup("x") == symtable.SCOPE_LOCAL
  95. def test_arguments(self):
  96. scp = self.func_scope("def f(): pass")
  97. assert not scp.children
  98. self.check_unknown(scp, "x", "y")
  99. assert not scp.symbols
  100. assert not scp.roles
  101. scp = self.func_scope("def f(x): pass")
  102. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  103. scp = self.func_scope("def f(*x): pass")
  104. assert scp.has_variable_arg
  105. assert not scp.has_keywords_arg
  106. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  107. scp = self.func_scope("def f(**x): pass")
  108. assert scp.has_keywords_arg
  109. assert not scp.has_variable_arg
  110. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  111. scp = self.func_scope("def f((x, y), a): pass")
  112. for name in ("x", "y", "a"):
  113. assert scp.lookup(name) == symtable.SCOPE_LOCAL
  114. scp = self.func_scope("def f(((a, b), c)): pass")
  115. for name in ("a", "b", "c"):
  116. assert scp.lookup(name) == symtable.SCOPE_LOCAL
  117. def test_function(self):
  118. scp = self.func_scope("def f(): x = 4")
  119. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  120. scp = self.func_scope("def f(): x")
  121. assert scp.lookup("x") == symtable.SCOPE_GLOBAL_IMPLICIT
  122. def test_nested_scopes(self):
  123. def nested_scope(*bodies):
  124. names = enumerate("f" + string.ascii_letters)
  125. lines = []
  126. for body, (level, name) in zip(bodies, names):
  127. lines.append(" " * level + "def %s():\n" % (name,))
  128. if body:
  129. if isinstance(body, str):
  130. body = [body]
  131. lines.extend(" " * (level + 1) + line + "\n"
  132. for line in body)
  133. return self.func_scope("".join(lines))
  134. scp = nested_scope("x = 1", "return x")
  135. assert not scp.has_free
  136. assert scp.child_has_free
  137. assert scp.lookup("x") == symtable.SCOPE_CELL
  138. child = scp.children[0]
  139. assert child.has_free
  140. assert child.lookup("x") == symtable.SCOPE_FREE
  141. scp = nested_scope("x = 1", None, "return x")
  142. assert not scp.has_free
  143. assert scp.child_has_free
  144. assert scp.lookup("x") == symtable.SCOPE_CELL
  145. child = scp.children[0]
  146. assert not child.has_free
  147. assert child.child_has_free
  148. assert child.lookup("x") == symtable.SCOPE_FREE
  149. child = child.children[0]
  150. assert child.has_free
  151. assert not child.child_has_free
  152. assert child.lookup("x") == symtable.SCOPE_FREE
  153. scp = nested_scope("x = 1", "x = 3", "return x")
  154. assert scp.child_has_free
  155. assert not scp.has_free
  156. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  157. child = scp.children[0]
  158. assert child.child_has_free
  159. assert not child.has_free
  160. assert child.lookup("x") == symtable.SCOPE_CELL
  161. child = child.children[0]
  162. assert child.has_free
  163. assert child.lookup("x") == symtable.SCOPE_FREE
  164. def test_class(self):
  165. scp = self.mod_scope("class x(A, B): pass")
  166. cscp = scp.children[0]
  167. for name in ("A", "B"):
  168. assert scp.lookup(name) == symtable.SCOPE_GLOBAL_IMPLICIT
  169. self.check_unknown(cscp, name)
  170. scp = self.func_scope("""def f(x):
  171. class X:
  172. def n():
  173. return x
  174. a = x
  175. return X()""")
  176. self.check_unknown(scp, "a")
  177. assert scp.lookup("x") == symtable.SCOPE_CELL
  178. assert scp.lookup("X") == symtable.SCOPE_LOCAL
  179. cscp = scp.children[0]
  180. assert cscp.lookup("a") == symtable.SCOPE_LOCAL
  181. assert cscp.lookup("x") == symtable.SCOPE_FREE
  182. fscp = cscp.children[0]
  183. assert fscp.lookup("x") == symtable.SCOPE_FREE
  184. self.check_unknown(fscp, "a")
  185. scp = self.func_scope("""def f(n):
  186. class X:
  187. def n():
  188. return y
  189. def x():
  190. return n""")
  191. assert scp.lookup("n") == symtable.SCOPE_CELL
  192. cscp = scp.children[0]
  193. assert cscp.lookup("n") == symtable.SCOPE_LOCAL
  194. assert "n" in cscp.free_vars
  195. xscp = cscp.children[1]
  196. assert xscp.lookup("n") == symtable.SCOPE_FREE
  197. def test_lambda(self):
  198. scp = self.mod_scope("lambda x: y")
  199. self.check_unknown(scp, "x", "y")
  200. assert len(scp.children) == 1
  201. lscp = scp.children[0]
  202. assert isinstance(lscp, symtable.FunctionScope)
  203. assert lscp.name == "lambda"
  204. assert lscp.lookup("x") == symtable.SCOPE_LOCAL
  205. assert lscp.lookup("y") == symtable.SCOPE_GLOBAL_IMPLICIT
  206. scp = self.mod_scope("lambda x=a: b")
  207. self.check_unknown(scp, "x", "b")
  208. assert scp.lookup("a") == symtable.SCOPE_GLOBAL_IMPLICIT
  209. lscp = scp.children[0]
  210. self.check_unknown(lscp, "a")
  211. def test_import(self):
  212. scp = self.mod_scope("import x")
  213. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  214. scp = self.mod_scope("import x as y")
  215. assert scp.lookup("y") == symtable.SCOPE_LOCAL
  216. self.check_unknown(scp, "x")
  217. scp = self.mod_scope("import x.y")
  218. assert scp.lookup("x") == symtable.SCOPE_LOCAL
  219. self.check_unknown(scp, "y")
  220. def test_from_import(self):
  221. scp = self.mod_scope("from x import y")
  222. self.check_unknown("x")
  223. assert scp.lookup("y") == symtable.SCOPE_LOCAL
  224. scp = self.mod_scope("from a import b as y")
  225. assert scp.lookup("y") == symtable.SCOPE_LOCAL
  226. self.check_unknown(scp, "a", "b")
  227. scp = self.mod_scope("from x import *")
  228. self.check_unknown("x")
  229. scp = self.func_scope("def f(): from x import *")
  230. self.check_unknown(scp, "x")
  231. assert not scp.optimized
  232. assert scp.import_star
  233. def test_global(self):
  234. scp = self.func_scope("def f():\n global x\n x = 4")
  235. assert scp.lookup("x") == symtable.SCOPE_GLOBAL_EXPLICIT
  236. input = "def f(x):\n global x"
  237. scp = self.func_scope("""def f():
  238. y = 3
  239. def x():
  240. global y
  241. y = 4
  242. def z():
  243. return y""")
  244. assert scp.lookup("y") == symtable.SCOPE_CELL
  245. xscp, zscp = scp.children
  246. assert xscp.lookup("y") == symtable.SCOPE_GLOBAL_EXPLICIT
  247. assert zscp.lookup("y") == symtable.SCOPE_FREE
  248. exc = py.test.raises(SyntaxError, self.func_scope, input).value
  249. assert exc.msg == "name 'x' is local and global"
  250. def test_optimization(self):
  251. assert not self.mod_scope("").can_be_optimized
  252. assert not self.class_scope("class x: pass").can_be_optimized
  253. assert self.func_scope("def f(): pass").can_be_optimized
  254. def test_unoptimization_with_nested_scopes(self):
  255. table = (
  256. ("from x import *; exec 'hi'", "function 'f' uses import * " \
  257. "and bare exec, which are illegal because it"),
  258. ("from x import *", "import * is not allowed in function 'f' " \
  259. "because it"),
  260. ("exec 'hi'", "unqualified exec is not allowed in function 'f' " \
  261. "because it")
  262. )
  263. for line, error in table:
  264. input = """def n():
  265. x = 4
  266. def f():
  267. %s
  268. return x""" % (line,)
  269. exc = py.test.raises(SyntaxError, self.mod_scope, input).value
  270. assert exc.msg == error + " is a nested function"
  271. input = """def f():
  272. %s
  273. x = 4
  274. def n():
  275. return x""" % (line,)
  276. exc = py.test.raises(SyntaxError, self.mod_scope, input).value
  277. assert exc.msg == error + " contains a nested function with free variables"
  278. input = """def f():
  279. %s
  280. x = 4
  281. class Y:
  282. def n():
  283. return x""" % (line,)
  284. exc = py.test.raises(SyntaxError, self.mod_scope, input).value
  285. assert exc.msg == error + " contains a nested function with free variables"
  286. def test_importstar_warning(self, capfd):
  287. self.mod_scope("def f():\n from re import *")
  288. _, err1 = capfd.readouterr()
  289. self.mod_scope("if 1:\n from re import *")
  290. _, err2 = capfd.readouterr()
  291. capfd.close()
  292. assert "import * only allowed at module level" in err1
  293. assert not "import * only allowed at module level" in err2
  294. def test_exec(self):
  295. self.mod_scope("exec 'hi'")
  296. scp = self.func_scope("def f(): exec 'hi'")
  297. assert not scp.optimized
  298. assert not scp.locals_fully_known
  299. assert isinstance(scp.bare_exec, ast.Exec)
  300. assert scp.has_exec
  301. for line in ("exec 'hi' in g", "exec 'hi' in g, h"):
  302. scp = self.func_scope("def f(): " + line)
  303. assert scp.optimized
  304. assert not scp.locals_fully_known
  305. assert scp.bare_exec is None
  306. assert scp.has_exec
  307. def test_yield(self):
  308. scp = self.func_scope("def f(): yield x")
  309. assert scp.is_generator
  310. for input in ("yield x", "class y: yield x"):
  311. exc = py.test.raises(SyntaxError, self.mod_scope, "yield x").value
  312. assert exc.msg == "'yield' outside function"
  313. for input in ("yield\n return x", "return x\n yield"):
  314. input = "def f():\n " + input
  315. exc = py.test.raises(SyntaxError, self.func_scope, input).value
  316. assert exc.msg == "'return' with argument inside generator"
  317. scp = self.func_scope("def f():\n return\n yield x")
  318. def test_return(self):
  319. for input in ("class x: return", "return"):
  320. exc = py.test.raises(SyntaxError, self.func_scope, input).value
  321. assert exc.msg == "return outside function"
  322. def test_tmpnames(self):
  323. scp = self.mod_scope("with x: pass")
  324. assert scp.lookup("_[1]") == symtable.SCOPE_LOCAL
  325. scp = self.mod_scope("with x as y: pass")
  326. assert scp.lookup("_[1]") == symtable.SCOPE_LOCAL
  327. assert scp.lookup("_[2]") == symtable.SCOPE_LOCAL