Cython 3.1.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. Cython/Build/BuildExecutable.py +169 -0
  2. Cython/Build/Cache.py +199 -0
  3. Cython/Build/Cythonize.py +250 -0
  4. Cython/Build/Dependencies.py +1275 -0
  5. Cython/Build/Distutils.py +1 -0
  6. Cython/Build/Inline.py +342 -0
  7. Cython/Build/IpythonMagic.py +560 -0
  8. Cython/Build/Tests/TestCyCache.py +119 -0
  9. Cython/Build/Tests/TestCythonizeArgsParser.py +481 -0
  10. Cython/Build/Tests/TestDependencies.py +133 -0
  11. Cython/Build/Tests/TestInline.py +112 -0
  12. Cython/Build/Tests/TestIpythonMagic.py +287 -0
  13. Cython/Build/Tests/TestRecythonize.py +212 -0
  14. Cython/Build/Tests/TestStripLiterals.py +155 -0
  15. Cython/Build/Tests/__init__.py +1 -0
  16. Cython/Build/__init__.py +8 -0
  17. Cython/CodeWriter.py +811 -0
  18. Cython/Compiler/AnalysedTreeTransforms.py +97 -0
  19. Cython/Compiler/Annotate.py +326 -0
  20. Cython/Compiler/AutoDocTransforms.py +314 -0
  21. Cython/Compiler/Buffer.py +680 -0
  22. Cython/Compiler/Builtin.py +862 -0
  23. Cython/Compiler/CmdLine.py +243 -0
  24. Cython/Compiler/Code.pxd +145 -0
  25. Cython/Compiler/Code.py +3328 -0
  26. Cython/Compiler/CodeGeneration.py +33 -0
  27. Cython/Compiler/CythonScope.py +179 -0
  28. Cython/Compiler/Dataclass.py +868 -0
  29. Cython/Compiler/DebugFlags.py +21 -0
  30. Cython/Compiler/Errors.py +295 -0
  31. Cython/Compiler/ExprNodes.py +15051 -0
  32. Cython/Compiler/FlowControl.pxd +97 -0
  33. Cython/Compiler/FlowControl.py +1438 -0
  34. Cython/Compiler/FusedNode.py +998 -0
  35. Cython/Compiler/Future.py +16 -0
  36. Cython/Compiler/Interpreter.py +57 -0
  37. Cython/Compiler/Lexicon.py +340 -0
  38. Cython/Compiler/LineTable.py +114 -0
  39. Cython/Compiler/Main.py +779 -0
  40. Cython/Compiler/MatchCaseNodes.py +259 -0
  41. Cython/Compiler/MemoryView.py +860 -0
  42. Cython/Compiler/ModuleNode.py +4065 -0
  43. Cython/Compiler/Naming.py +369 -0
  44. Cython/Compiler/Nodes.py +10557 -0
  45. Cython/Compiler/Optimize.py +5269 -0
  46. Cython/Compiler/Options.py +828 -0
  47. Cython/Compiler/ParseTreeTransforms.pxd +78 -0
  48. Cython/Compiler/ParseTreeTransforms.py +4441 -0
  49. Cython/Compiler/Parsing.pxd +9 -0
  50. Cython/Compiler/Parsing.py +4797 -0
  51. Cython/Compiler/Pipeline.py +425 -0
  52. Cython/Compiler/PyrexTypes.py +5572 -0
  53. Cython/Compiler/Pythran.py +223 -0
  54. Cython/Compiler/Scanning.pxd +40 -0
  55. Cython/Compiler/Scanning.py +574 -0
  56. Cython/Compiler/StringEncoding.py +347 -0
  57. Cython/Compiler/Symtab.py +2998 -0
  58. Cython/Compiler/Tests/TestBuffer.py +105 -0
  59. Cython/Compiler/Tests/TestBuiltin.py +72 -0
  60. Cython/Compiler/Tests/TestCmdLine.py +573 -0
  61. Cython/Compiler/Tests/TestCode.py +86 -0
  62. Cython/Compiler/Tests/TestFlowControl.py +65 -0
  63. Cython/Compiler/Tests/TestGrammar.py +202 -0
  64. Cython/Compiler/Tests/TestMemView.py +71 -0
  65. Cython/Compiler/Tests/TestParseTreeTransforms.py +285 -0
  66. Cython/Compiler/Tests/TestScanning.py +134 -0
  67. Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
  68. Cython/Compiler/Tests/TestStringEncoding.py +33 -0
  69. Cython/Compiler/Tests/TestTreeFragment.py +63 -0
  70. Cython/Compiler/Tests/TestTreePath.py +93 -0
  71. Cython/Compiler/Tests/TestTypes.py +75 -0
  72. Cython/Compiler/Tests/TestUtilityLoad.py +112 -0
  73. Cython/Compiler/Tests/TestVisitor.py +61 -0
  74. Cython/Compiler/Tests/Utils.py +36 -0
  75. Cython/Compiler/Tests/__init__.py +1 -0
  76. Cython/Compiler/TreeFragment.py +278 -0
  77. Cython/Compiler/TreePath.py +290 -0
  78. Cython/Compiler/TypeInference.py +584 -0
  79. Cython/Compiler/TypeSlots.py +1181 -0
  80. Cython/Compiler/UFuncs.py +311 -0
  81. Cython/Compiler/UtilNodes.py +387 -0
  82. Cython/Compiler/UtilityCode.py +274 -0
  83. Cython/Compiler/Version.py +8 -0
  84. Cython/Compiler/Visitor.pxd +53 -0
  85. Cython/Compiler/Visitor.py +861 -0
  86. Cython/Compiler/__init__.py +1 -0
  87. Cython/Coverage.py +443 -0
  88. Cython/Debugger/Cygdb.py +179 -0
  89. Cython/Debugger/DebugWriter.py +82 -0
  90. Cython/Debugger/Tests/TestLibCython.py +275 -0
  91. Cython/Debugger/Tests/__init__.py +1 -0
  92. Cython/Debugger/Tests/cfuncs.c +8 -0
  93. Cython/Debugger/Tests/codefile +49 -0
  94. Cython/Debugger/Tests/test_libcython_in_gdb.py +578 -0
  95. Cython/Debugger/Tests/test_libpython_in_gdb.py +90 -0
  96. Cython/Debugger/__init__.py +1 -0
  97. Cython/Debugger/libcython.py +1549 -0
  98. Cython/Debugger/libpython.py +2821 -0
  99. Cython/Debugging.py +20 -0
  100. Cython/Distutils/__init__.py +2 -0
  101. Cython/Distutils/build_ext.py +137 -0
  102. Cython/Distutils/extension.py +96 -0
  103. Cython/Distutils/old_build_ext.py +351 -0
  104. Cython/Includes/cpython/__init__.pxd +173 -0
  105. Cython/Includes/cpython/array.pxd +174 -0
  106. Cython/Includes/cpython/bool.pxd +37 -0
  107. Cython/Includes/cpython/buffer.pxd +112 -0
  108. Cython/Includes/cpython/bytearray.pxd +33 -0
  109. Cython/Includes/cpython/bytes.pxd +200 -0
  110. Cython/Includes/cpython/cellobject.pxd +35 -0
  111. Cython/Includes/cpython/ceval.pxd +8 -0
  112. Cython/Includes/cpython/codecs.pxd +121 -0
  113. Cython/Includes/cpython/complex.pxd +55 -0
  114. Cython/Includes/cpython/contextvars.pxd +141 -0
  115. Cython/Includes/cpython/conversion.pxd +36 -0
  116. Cython/Includes/cpython/datetime.pxd +384 -0
  117. Cython/Includes/cpython/descr.pxd +26 -0
  118. Cython/Includes/cpython/dict.pxd +187 -0
  119. Cython/Includes/cpython/exc.pxd +263 -0
  120. Cython/Includes/cpython/fileobject.pxd +57 -0
  121. Cython/Includes/cpython/float.pxd +47 -0
  122. Cython/Includes/cpython/function.pxd +65 -0
  123. Cython/Includes/cpython/genobject.pxd +25 -0
  124. Cython/Includes/cpython/getargs.pxd +12 -0
  125. Cython/Includes/cpython/instance.pxd +25 -0
  126. Cython/Includes/cpython/iterator.pxd +36 -0
  127. Cython/Includes/cpython/iterobject.pxd +24 -0
  128. Cython/Includes/cpython/list.pxd +92 -0
  129. Cython/Includes/cpython/long.pxd +149 -0
  130. Cython/Includes/cpython/longintrepr.pxd +19 -0
  131. Cython/Includes/cpython/mapping.pxd +63 -0
  132. Cython/Includes/cpython/marshal.pxd +66 -0
  133. Cython/Includes/cpython/mem.pxd +120 -0
  134. Cython/Includes/cpython/memoryview.pxd +50 -0
  135. Cython/Includes/cpython/method.pxd +49 -0
  136. Cython/Includes/cpython/module.pxd +208 -0
  137. Cython/Includes/cpython/number.pxd +258 -0
  138. Cython/Includes/cpython/object.pxd +433 -0
  139. Cython/Includes/cpython/pycapsule.pxd +143 -0
  140. Cython/Includes/cpython/pylifecycle.pxd +68 -0
  141. Cython/Includes/cpython/pyport.pxd +8 -0
  142. Cython/Includes/cpython/pystate.pxd +95 -0
  143. Cython/Includes/cpython/pythread.pxd +53 -0
  144. Cython/Includes/cpython/ref.pxd +67 -0
  145. Cython/Includes/cpython/sequence.pxd +134 -0
  146. Cython/Includes/cpython/set.pxd +119 -0
  147. Cython/Includes/cpython/slice.pxd +70 -0
  148. Cython/Includes/cpython/time.pxd +129 -0
  149. Cython/Includes/cpython/tuple.pxd +72 -0
  150. Cython/Includes/cpython/type.pxd +53 -0
  151. Cython/Includes/cpython/unicode.pxd +639 -0
  152. Cython/Includes/cpython/version.pxd +32 -0
  153. Cython/Includes/cpython/weakref.pxd +42 -0
  154. Cython/Includes/libc/__init__.pxd +1 -0
  155. Cython/Includes/libc/complex.pxd +35 -0
  156. Cython/Includes/libc/errno.pxd +127 -0
  157. Cython/Includes/libc/float.pxd +43 -0
  158. Cython/Includes/libc/limits.pxd +28 -0
  159. Cython/Includes/libc/locale.pxd +46 -0
  160. Cython/Includes/libc/math.pxd +209 -0
  161. Cython/Includes/libc/setjmp.pxd +10 -0
  162. Cython/Includes/libc/signal.pxd +64 -0
  163. Cython/Includes/libc/stddef.pxd +9 -0
  164. Cython/Includes/libc/stdint.pxd +105 -0
  165. Cython/Includes/libc/stdio.pxd +80 -0
  166. Cython/Includes/libc/stdlib.pxd +72 -0
  167. Cython/Includes/libc/string.pxd +50 -0
  168. Cython/Includes/libc/time.pxd +47 -0
  169. Cython/Includes/libcpp/__init__.pxd +4 -0
  170. Cython/Includes/libcpp/algorithm.pxd +320 -0
  171. Cython/Includes/libcpp/any.pxd +16 -0
  172. Cython/Includes/libcpp/atomic.pxd +59 -0
  173. Cython/Includes/libcpp/bit.pxd +29 -0
  174. Cython/Includes/libcpp/cast.pxd +12 -0
  175. Cython/Includes/libcpp/cmath.pxd +518 -0
  176. Cython/Includes/libcpp/complex.pxd +106 -0
  177. Cython/Includes/libcpp/deque.pxd +165 -0
  178. Cython/Includes/libcpp/execution.pxd +15 -0
  179. Cython/Includes/libcpp/forward_list.pxd +63 -0
  180. Cython/Includes/libcpp/functional.pxd +26 -0
  181. Cython/Includes/libcpp/iterator.pxd +34 -0
  182. Cython/Includes/libcpp/limits.pxd +61 -0
  183. Cython/Includes/libcpp/list.pxd +117 -0
  184. Cython/Includes/libcpp/map.pxd +252 -0
  185. Cython/Includes/libcpp/memory.pxd +115 -0
  186. Cython/Includes/libcpp/numbers.pxd +15 -0
  187. Cython/Includes/libcpp/numeric.pxd +131 -0
  188. Cython/Includes/libcpp/optional.pxd +34 -0
  189. Cython/Includes/libcpp/pair.pxd +1 -0
  190. Cython/Includes/libcpp/queue.pxd +25 -0
  191. Cython/Includes/libcpp/random.pxd +166 -0
  192. Cython/Includes/libcpp/set.pxd +228 -0
  193. Cython/Includes/libcpp/stack.pxd +11 -0
  194. Cython/Includes/libcpp/string.pxd +333 -0
  195. Cython/Includes/libcpp/typeindex.pxd +15 -0
  196. Cython/Includes/libcpp/typeinfo.pxd +10 -0
  197. Cython/Includes/libcpp/unordered_map.pxd +193 -0
  198. Cython/Includes/libcpp/unordered_set.pxd +152 -0
  199. Cython/Includes/libcpp/utility.pxd +30 -0
  200. Cython/Includes/libcpp/vector.pxd +167 -0
  201. Cython/Includes/openmp.pxd +50 -0
  202. Cython/Includes/posix/__init__.pxd +1 -0
  203. Cython/Includes/posix/dlfcn.pxd +14 -0
  204. Cython/Includes/posix/fcntl.pxd +86 -0
  205. Cython/Includes/posix/ioctl.pxd +4 -0
  206. Cython/Includes/posix/mman.pxd +101 -0
  207. Cython/Includes/posix/resource.pxd +57 -0
  208. Cython/Includes/posix/select.pxd +21 -0
  209. Cython/Includes/posix/signal.pxd +73 -0
  210. Cython/Includes/posix/stat.pxd +98 -0
  211. Cython/Includes/posix/stdio.pxd +37 -0
  212. Cython/Includes/posix/stdlib.pxd +29 -0
  213. Cython/Includes/posix/strings.pxd +9 -0
  214. Cython/Includes/posix/time.pxd +71 -0
  215. Cython/Includes/posix/types.pxd +30 -0
  216. Cython/Includes/posix/uio.pxd +26 -0
  217. Cython/Includes/posix/unistd.pxd +271 -0
  218. Cython/Includes/posix/wait.pxd +38 -0
  219. Cython/Plex/Actions.pxd +24 -0
  220. Cython/Plex/Actions.py +119 -0
  221. Cython/Plex/DFA.pxd +14 -0
  222. Cython/Plex/DFA.py +164 -0
  223. Cython/Plex/Errors.py +48 -0
  224. Cython/Plex/Lexicons.py +178 -0
  225. Cython/Plex/Machines.pxd +36 -0
  226. Cython/Plex/Machines.py +238 -0
  227. Cython/Plex/Regexps.py +539 -0
  228. Cython/Plex/Scanners.pxd +47 -0
  229. Cython/Plex/Scanners.py +360 -0
  230. Cython/Plex/Transitions.pxd +14 -0
  231. Cython/Plex/Transitions.py +239 -0
  232. Cython/Plex/__init__.py +34 -0
  233. Cython/Runtime/__init__.py +1 -0
  234. Cython/Runtime/refnanny.pyx +261 -0
  235. Cython/Shadow.py +656 -0
  236. Cython/Shadow.pyi +521 -0
  237. Cython/StringIOTree.py +170 -0
  238. Cython/Tempita/__init__.py +4 -0
  239. Cython/Tempita/_looper.py +154 -0
  240. Cython/Tempita/_tempita.py +1091 -0
  241. Cython/TestUtils.py +417 -0
  242. Cython/Tests/TestCodeWriter.py +128 -0
  243. Cython/Tests/TestCythonUtils.py +202 -0
  244. Cython/Tests/TestJediTyper.py +223 -0
  245. Cython/Tests/TestShadow.py +114 -0
  246. Cython/Tests/TestStringIOTree.py +67 -0
  247. Cython/Tests/TestTestUtils.py +90 -0
  248. Cython/Tests/__init__.py +1 -0
  249. Cython/Tests/xmlrunner.py +390 -0
  250. Cython/Utility/AsyncGen.c +1263 -0
  251. Cython/Utility/Buffer.c +875 -0
  252. Cython/Utility/Builtins.c +660 -0
  253. Cython/Utility/CConvert.pyx +134 -0
  254. Cython/Utility/CMath.c +95 -0
  255. Cython/Utility/CommonStructures.c +139 -0
  256. Cython/Utility/Complex.c +378 -0
  257. Cython/Utility/Coroutine.c +2413 -0
  258. Cython/Utility/CpdefEnums.pyx +108 -0
  259. Cython/Utility/CppConvert.pyx +279 -0
  260. Cython/Utility/CppSupport.cpp +133 -0
  261. Cython/Utility/CythonFunction.c +1851 -0
  262. Cython/Utility/Dataclasses.c +185 -0
  263. Cython/Utility/Dataclasses.py +112 -0
  264. Cython/Utility/Embed.c +125 -0
  265. Cython/Utility/Exceptions.c +1017 -0
  266. Cython/Utility/ExtensionTypes.c +797 -0
  267. Cython/Utility/FunctionArguments.c +573 -0
  268. Cython/Utility/ImportExport.c +912 -0
  269. Cython/Utility/MemoryView.pyx +1478 -0
  270. Cython/Utility/MemoryView_C.c +992 -0
  271. Cython/Utility/ModuleSetupCode.c +2501 -0
  272. Cython/Utility/NumpyImportArray.c +46 -0
  273. Cython/Utility/ObjectHandling.c +3054 -0
  274. Cython/Utility/Optimize.c +1533 -0
  275. Cython/Utility/Overflow.c +404 -0
  276. Cython/Utility/Printing.c +86 -0
  277. Cython/Utility/Profile.c +660 -0
  278. Cython/Utility/StringTools.c +1206 -0
  279. Cython/Utility/TestCyUtilityLoader.pyx +8 -0
  280. Cython/Utility/TestCythonScope.pyx +75 -0
  281. Cython/Utility/TestUtilityLoader.c +12 -0
  282. Cython/Utility/TypeConversion.c +1329 -0
  283. Cython/Utility/UFuncs.pyx +50 -0
  284. Cython/Utility/UFuncs_C.c +89 -0
  285. Cython/Utility/__init__.py +28 -0
  286. Cython/Utility/arrayarray.h +143 -0
  287. Cython/Utils.py +687 -0
  288. Cython/__init__.py +10 -0
  289. Cython/__init__.pyi +7 -0
  290. Cython/py.typed +0 -0
  291. Cython-3.1.0a1.dist-info/COPYING.txt +19 -0
  292. Cython-3.1.0a1.dist-info/LICENSE.txt +176 -0
  293. Cython-3.1.0a1.dist-info/METADATA +67 -0
  294. Cython-3.1.0a1.dist-info/RECORD +301 -0
  295. Cython-3.1.0a1.dist-info/WHEEL +5 -0
  296. Cython-3.1.0a1.dist-info/entry_points.txt +4 -0
  297. Cython-3.1.0a1.dist-info/top_level.txt +3 -0
  298. cython.py +29 -0
  299. pyximport/__init__.py +4 -0
  300. pyximport/pyxbuild.py +160 -0
  301. pyximport/pyximport.py +482 -0
@@ -0,0 +1,1438 @@
1
+ # cython: auto_pickle=True
2
+
3
+
4
+ import cython
5
+ cython.declare(PyrexTypes=object, ExprNodes=object, Nodes=object, Builtin=object,
6
+ Options=object, TreeVisitor=object, CythonTransform=object,
7
+ InternalError=object, error=object, warning=object,
8
+ fake_rhs_expr=object, TypedExprNode=object)
9
+
10
+ from . import Builtin
11
+ from . import ExprNodes
12
+ from . import Nodes
13
+ from . import Options
14
+ from . import PyrexTypes
15
+
16
+ from .Visitor import TreeVisitor, CythonTransform
17
+ from .Errors import error, warning, InternalError
18
+
19
+
20
+ class TypedExprNode(ExprNodes.ExprNode):
21
+ # Used for declaring assignments of a specified type without a known entry.
22
+ def __init__(self, type, may_be_none=None, pos=None):
23
+ super().__init__(pos)
24
+ self.type = type
25
+ self._may_be_none = may_be_none
26
+
27
+ def may_be_none(self):
28
+ return self._may_be_none != False
29
+
30
+ # Fake rhs to silence "unused variable" warning
31
+ fake_rhs_expr = TypedExprNode(PyrexTypes.unspecified_type)
32
+
33
+
34
+ class ControlBlock:
35
+ """Control flow graph node. Sequence of assignments and name references.
36
+
37
+ children set of children nodes
38
+ parents set of parent nodes
39
+ positions set of position markers
40
+
41
+ stats list of block statements
42
+ gen dict of assignments generated by this block
43
+ bounded set of entries that are definitely bounded in this block
44
+
45
+ Example:
46
+
47
+ a = 1
48
+ b = a + c # 'c' is already bounded or exception here
49
+
50
+ stats = [Assignment(a), NameReference(a), NameReference(c),
51
+ Assignment(b)]
52
+ gen = {Entry(a): Assignment(a), Entry(b): Assignment(b)}
53
+ bounded = {Entry(a), Entry(c)}
54
+
55
+ """
56
+
57
+ def __init__(self):
58
+ self.children = set()
59
+ self.parents = set()
60
+ self.positions = set()
61
+
62
+ self.stats = []
63
+ self.gen = {}
64
+ self.bounded = set()
65
+
66
+ self.i_input = 0
67
+ self.i_output = 0
68
+ self.i_gen = 0
69
+ self.i_kill = 0
70
+ self.i_state = 0
71
+
72
+ def empty(self):
73
+ return (not self.stats and not self.positions)
74
+
75
+ def detach(self):
76
+ """Detach block from parents and children."""
77
+ for child in self.children:
78
+ child.parents.remove(self)
79
+ for parent in self.parents:
80
+ parent.children.remove(self)
81
+ self.parents.clear()
82
+ self.children.clear()
83
+
84
+ def add_child(self, block):
85
+ self.children.add(block)
86
+ block.parents.add(self)
87
+
88
+
89
+ class ExitBlock(ControlBlock):
90
+ """Non-empty exit point block."""
91
+
92
+ def empty(self):
93
+ return False
94
+
95
+
96
+ class AssignmentList:
97
+ def __init__(self):
98
+ self.stats = []
99
+
100
+
101
+ class ControlFlow:
102
+ """Control-flow graph.
103
+
104
+ entry_point ControlBlock entry point for this graph
105
+ exit_point ControlBlock normal exit point
106
+ block ControlBlock current block
107
+ blocks set children nodes
108
+ entries set tracked entries
109
+ loops list stack for loop descriptors
110
+ exceptions list stack for exception descriptors
111
+ in_try_block int track if we're in a try...except or try...finally block
112
+ """
113
+
114
+ def __init__(self):
115
+ self.blocks = set()
116
+ self.entries = set()
117
+ self.loops = []
118
+ self.exceptions = []
119
+
120
+ self.entry_point = ControlBlock()
121
+ self.exit_point = ExitBlock()
122
+ self.blocks.add(self.exit_point)
123
+ self.block = self.entry_point
124
+ self.in_try_block = 0
125
+
126
+ def newblock(self, parent=None):
127
+ """Create floating block linked to `parent` if given.
128
+
129
+ NOTE: Block is NOT added to self.blocks
130
+ """
131
+ block = ControlBlock()
132
+ self.blocks.add(block)
133
+ if parent:
134
+ parent.add_child(block)
135
+ return block
136
+
137
+ def nextblock(self, parent=None):
138
+ """Create block children block linked to current or `parent` if given.
139
+
140
+ NOTE: Block is added to self.blocks
141
+ """
142
+ block = ControlBlock()
143
+ self.blocks.add(block)
144
+ if parent:
145
+ parent.add_child(block)
146
+ elif self.block:
147
+ self.block.add_child(block)
148
+ self.block = block
149
+ return self.block
150
+
151
+ def is_tracked(self, entry):
152
+ if entry.is_anonymous:
153
+ return False
154
+ return (entry.is_local or entry.is_pyclass_attr or entry.is_arg or
155
+ entry.from_closure or entry.in_closure or
156
+ entry.error_on_uninitialized)
157
+
158
+ def is_statically_assigned(self, entry):
159
+ if (entry.is_local and entry.is_variable and
160
+ (entry.type.is_struct_or_union or
161
+ entry.type.is_complex or
162
+ entry.type.is_array or
163
+ (entry.type.is_cpp_class and not entry.is_cpp_optional))):
164
+ # stack allocated structured variable => never uninitialised
165
+ return True
166
+ return False
167
+
168
+ def mark_position(self, node):
169
+ """Mark position, will be used to draw graph nodes."""
170
+ if self.block:
171
+ self.block.positions.add(node.pos[:2])
172
+
173
+ def mark_assignment(self, lhs, rhs, entry, rhs_scope=None):
174
+ if self.block and self.is_tracked(entry):
175
+ assignment = NameAssignment(lhs, rhs, entry, rhs_scope=rhs_scope)
176
+ self.block.stats.append(assignment)
177
+ self.block.gen[entry] = assignment
178
+ self.entries.add(entry)
179
+
180
+ def mark_argument(self, lhs, rhs, entry):
181
+ if self.block and self.is_tracked(entry):
182
+ assignment = Argument(lhs, rhs, entry)
183
+ self.block.stats.append(assignment)
184
+ self.block.gen[entry] = assignment
185
+ self.entries.add(entry)
186
+
187
+ def mark_deletion(self, node, entry):
188
+ if self.block and self.is_tracked(entry):
189
+ assignment = NameDeletion(node, entry)
190
+ self.block.stats.append(assignment)
191
+ self.block.gen[entry] = Uninitialized
192
+ self.entries.add(entry)
193
+
194
+ def mark_reference(self, node, entry):
195
+ if self.block and self.is_tracked(entry):
196
+ self.block.stats.append(NameReference(node, entry))
197
+ ## XXX: We don't track expression evaluation order so we can't use
198
+ ## XXX: successful reference as initialization sign.
199
+ ## # Local variable is definitely bound after this reference
200
+ ## if not node.allow_null:
201
+ ## self.block.bounded.add(entry)
202
+ self.entries.add(entry)
203
+
204
+ def normalize(self):
205
+ """Delete unreachable and orphan blocks."""
206
+ queue = {self.entry_point}
207
+ visited = set()
208
+ while queue:
209
+ root = queue.pop()
210
+ visited.add(root)
211
+ for child in root.children:
212
+ if child not in visited:
213
+ queue.add(child)
214
+
215
+ unreachable: set = self.blocks - visited
216
+ block: ControlBlock
217
+ for block in unreachable:
218
+ block.detach()
219
+
220
+ visited.remove(self.entry_point)
221
+
222
+ parent: ControlBlock
223
+ for block in visited:
224
+ if block.empty():
225
+ for parent in block.parents: # Re-parent
226
+ for child in block.children:
227
+ parent.add_child(child)
228
+ block.detach()
229
+ unreachable.add(block)
230
+ self.blocks -= unreachable
231
+
232
+ def initialize(self):
233
+ """Set initial state, map assignments to bits."""
234
+ self.assmts = {}
235
+ assmts: AssignmentList
236
+ block: ControlBlock
237
+
238
+ bit: int = 1
239
+ for entry in self.entries:
240
+ assmts = AssignmentList()
241
+ assmts.mask = assmts.bit = bit
242
+ self.assmts[entry] = assmts
243
+ bit <<= 1
244
+
245
+ for block in self.blocks:
246
+ for stat in block.stats:
247
+ if isinstance(stat, NameAssignment):
248
+ stat.bit = bit
249
+ assmts = self.assmts[stat.entry]
250
+ assmts.stats.append(stat)
251
+ assmts.mask |= bit
252
+ bit <<= 1
253
+
254
+ for block in self.blocks:
255
+ for entry, stat in block.gen.items():
256
+ assmts = self.assmts[entry]
257
+ if stat is Uninitialized:
258
+ block.i_gen |= assmts.bit
259
+ else:
260
+ block.i_gen |= stat.bit
261
+ block.i_kill |= assmts.mask
262
+ block.i_output = block.i_gen
263
+ for entry in block.bounded:
264
+ block.i_kill |= self.assmts[entry].bit
265
+
266
+ for assmts in self.assmts.values():
267
+ self.entry_point.i_gen |= assmts.bit
268
+ self.entry_point.i_output = self.entry_point.i_gen
269
+
270
+ def map_one(self, istate, entry):
271
+ ret = set()
272
+ assmts: AssignmentList = self.assmts[entry]
273
+ if istate & assmts.bit:
274
+ if self.is_statically_assigned(entry):
275
+ ret.add(StaticAssignment(entry))
276
+ elif entry.from_closure:
277
+ ret.add(Unknown)
278
+ else:
279
+ ret.add(Uninitialized)
280
+
281
+ assmt: NameAssignment
282
+ for assmt in assmts.stats:
283
+ if istate & assmt.bit:
284
+ ret.add(assmt)
285
+ return ret
286
+
287
+ def reaching_definitions(self):
288
+ """Per-block reaching definitions analysis."""
289
+ block: ControlBlock
290
+ parent: ControlBlock
291
+
292
+ dirty = True
293
+ while dirty:
294
+ dirty = False
295
+ for block in self.blocks:
296
+ i_input = 0
297
+ for parent in block.parents:
298
+ i_input |= parent.i_output
299
+ i_output = (i_input & ~block.i_kill) | block.i_gen
300
+ if i_output != block.i_output:
301
+ dirty = True
302
+ block.i_input = i_input
303
+ block.i_output = i_output
304
+
305
+
306
+ class LoopDescr:
307
+ def __init__(self, next_block, loop_block):
308
+ self.next_block = next_block
309
+ self.loop_block = loop_block
310
+ self.exceptions = []
311
+
312
+
313
+ class ExceptionDescr:
314
+ """Exception handling helper.
315
+
316
+ entry_point ControlBlock Exception handling entry point
317
+ finally_enter ControlBlock Normal finally clause entry point
318
+ finally_exit ControlBlock Normal finally clause exit point
319
+ """
320
+
321
+ def __init__(self, entry_point, finally_enter=None, finally_exit=None):
322
+ self.entry_point = entry_point
323
+ self.finally_enter = finally_enter
324
+ self.finally_exit = finally_exit
325
+
326
+
327
+ class NameAssignment:
328
+ def __init__(self, lhs, rhs, entry, rhs_scope=None):
329
+ if lhs.cf_state is None:
330
+ lhs.cf_state = set()
331
+ self.lhs = lhs
332
+ self.rhs = rhs
333
+ self.entry = entry
334
+ self.pos = lhs.pos
335
+ self.refs = set()
336
+ self.is_arg = False
337
+ self.is_deletion = False
338
+ self.inferred_type = None
339
+ # For generator expression targets, the rhs can have a different scope than the lhs.
340
+ self.rhs_scope = rhs_scope
341
+
342
+ def __repr__(self):
343
+ return '%s(entry=%r)' % (self.__class__.__name__, self.entry)
344
+
345
+ def infer_type(self):
346
+ self.inferred_type = self.rhs.infer_type(self.rhs_scope or self.entry.scope)
347
+ return self.inferred_type
348
+
349
+ def type_dependencies(self):
350
+ return self.rhs.type_dependencies(self.rhs_scope or self.entry.scope)
351
+
352
+ @property
353
+ def type(self):
354
+ if not self.entry.type.is_unspecified:
355
+ return self.entry.type
356
+ return self.inferred_type
357
+
358
+
359
+ class StaticAssignment(NameAssignment):
360
+ """Initialised at declaration time, e.g. stack allocation."""
361
+ def __init__(self, entry):
362
+ if not entry.type.is_pyobject:
363
+ may_be_none = False
364
+ else:
365
+ may_be_none = None # unknown
366
+ lhs = TypedExprNode(
367
+ entry.type, may_be_none=may_be_none, pos=entry.pos)
368
+ super().__init__(lhs, lhs, entry)
369
+
370
+ def infer_type(self):
371
+ return self.entry.type
372
+
373
+ def type_dependencies(self):
374
+ return ()
375
+
376
+
377
+ class Argument(NameAssignment):
378
+ def __init__(self, lhs, rhs, entry):
379
+ NameAssignment.__init__(self, lhs, rhs, entry)
380
+ self.is_arg = True
381
+
382
+
383
+ class NameDeletion(NameAssignment):
384
+ def __init__(self, lhs, entry):
385
+ NameAssignment.__init__(self, lhs, lhs, entry)
386
+ self.is_deletion = True
387
+
388
+ def infer_type(self):
389
+ inferred_type = self.rhs.infer_type(self.entry.scope)
390
+ if (not inferred_type.is_pyobject
391
+ and inferred_type.can_coerce_to_pyobject(self.entry.scope)):
392
+ return PyrexTypes.py_object_type
393
+ self.inferred_type = inferred_type
394
+ return inferred_type
395
+
396
+
397
+ class Uninitialized:
398
+ """Definitely not initialised yet."""
399
+
400
+
401
+ class Unknown:
402
+ """Coming from outer closure, might be initialised or not."""
403
+
404
+
405
+ class NameReference:
406
+ def __init__(self, node, entry):
407
+ if node.cf_state is None:
408
+ node.cf_state = set()
409
+ self.node = node
410
+ self.entry = entry
411
+ self.pos = node.pos
412
+
413
+ def __repr__(self):
414
+ return '%s(entry=%r)' % (self.__class__.__name__, self.entry)
415
+
416
+
417
+ class ControlFlowState(list):
418
+ # Keeps track of Node's entry assignments
419
+ #
420
+ # cf_is_null [boolean] It is uninitialized
421
+ # cf_maybe_null [boolean] May be uninitialized
422
+ # is_single [boolean] Has only one assignment at this point
423
+
424
+ cf_maybe_null = False
425
+ cf_is_null = False
426
+ is_single = False
427
+
428
+ def __init__(self, state):
429
+ if Uninitialized in state:
430
+ state.discard(Uninitialized)
431
+ self.cf_maybe_null = True
432
+ if not state:
433
+ self.cf_is_null = True
434
+ elif Unknown in state:
435
+ state.discard(Unknown)
436
+ self.cf_maybe_null = True
437
+ else:
438
+ if len(state) == 1:
439
+ self.is_single = True
440
+ # XXX: Remove fake_rhs_expr
441
+ super().__init__(
442
+ [i for i in state if i.rhs is not fake_rhs_expr])
443
+
444
+ def one(self):
445
+ return self[0]
446
+
447
+
448
+ class GVContext:
449
+ """Graphviz subgraph object."""
450
+
451
+ def __init__(self):
452
+ self.blockids = {}
453
+ self.nextid = 0
454
+ self.children = []
455
+ self.sources = {}
456
+
457
+ def add(self, child):
458
+ self.children.append(child)
459
+
460
+ def nodeid(self, block):
461
+ if block not in self.blockids:
462
+ self.blockids[block] = 'block%d' % self.nextid
463
+ self.nextid += 1
464
+ return self.blockids[block]
465
+
466
+ def extract_sources(self, block):
467
+ if not block.positions:
468
+ return ''
469
+ start = min(block.positions)
470
+ stop = max(block.positions)
471
+ srcdescr = start[0]
472
+ if srcdescr not in self.sources:
473
+ self.sources[srcdescr] = list(srcdescr.get_lines())
474
+ lines = self.sources[srcdescr]
475
+ return '\\n'.join([l.strip() for l in lines[start[1] - 1:stop[1]]])
476
+
477
+ def render(self, fp, name, annotate_defs=False):
478
+ """Render graphviz dot graph"""
479
+ fp.write('digraph %s {\n' % name)
480
+ fp.write(' node [shape=box];\n')
481
+ for child in self.children:
482
+ child.render(fp, self, annotate_defs)
483
+ fp.write('}\n')
484
+
485
+ def escape(self, text):
486
+ return text.replace('"', '\\"').replace('\n', '\\n')
487
+
488
+
489
+ class GV:
490
+ """Graphviz DOT renderer."""
491
+
492
+ def __init__(self, name, flow):
493
+ self.name = name
494
+ self.flow = flow
495
+
496
+ def render(self, fp, ctx, annotate_defs=False):
497
+ fp.write(' subgraph %s {\n' % self.name)
498
+ for block in self.flow.blocks:
499
+ label = ctx.extract_sources(block)
500
+ if annotate_defs:
501
+ for stat in block.stats:
502
+ if isinstance(stat, NameAssignment):
503
+ label += '\n %s [%s %s]' % (
504
+ stat.entry.name, 'deletion' if stat.is_deletion else 'definition', stat.pos[1])
505
+ elif isinstance(stat, NameReference):
506
+ if stat.entry:
507
+ label += '\n %s [reference %s]' % (stat.entry.name, stat.pos[1])
508
+ if not label:
509
+ label = 'empty'
510
+ pid = ctx.nodeid(block)
511
+ fp.write(' %s [label="%s"];\n' % (pid, ctx.escape(label)))
512
+ for block in self.flow.blocks:
513
+ pid = ctx.nodeid(block)
514
+ for child in block.children:
515
+ fp.write(' %s -> %s;\n' % (pid, ctx.nodeid(child)))
516
+ fp.write(' }\n')
517
+
518
+
519
+ class MessageCollection:
520
+ """Collect error/warnings messages first then sort"""
521
+ def __init__(self):
522
+ self.messages = set()
523
+
524
+ def error(self, pos, message):
525
+ self.messages.add((pos, True, message))
526
+
527
+ def warning(self, pos, message):
528
+ self.messages.add((pos, False, message))
529
+
530
+ def report(self):
531
+ for pos, is_error, message in sorted(self.messages):
532
+ if is_error:
533
+ error(pos, message)
534
+ else:
535
+ warning(pos, message, 2)
536
+
537
+
538
+ @cython.cfunc
539
+ def check_definitions(flow: ControlFlow, compiler_directives: dict):
540
+ flow.initialize()
541
+ flow.reaching_definitions()
542
+
543
+ # Track down state
544
+ assignments = set()
545
+ # Node to entry map
546
+ references = {}
547
+ assmt_nodes = set()
548
+
549
+ block: ControlBlock
550
+ assmt: NameAssignment
551
+ for block in flow.blocks:
552
+ i_state = block.i_input
553
+ for stat in block.stats:
554
+ i_assmts = flow.assmts[stat.entry]
555
+ state = flow.map_one(i_state, stat.entry)
556
+ if isinstance(stat, NameAssignment):
557
+ stat.lhs.cf_state.update(state)
558
+ assmt_nodes.add(stat.lhs)
559
+ i_state = i_state & ~i_assmts.mask
560
+ if stat.is_deletion:
561
+ i_state |= i_assmts.bit
562
+ else:
563
+ i_state |= stat.bit
564
+ assignments.add(stat)
565
+ if stat.rhs is not fake_rhs_expr:
566
+ stat.entry.cf_assignments.append(stat)
567
+ elif isinstance(stat, NameReference):
568
+ references[stat.node] = stat.entry
569
+ stat.entry.cf_references.append(stat)
570
+ stat.node.cf_state.update(state)
571
+ ## if not stat.node.allow_null:
572
+ ## i_state &= ~i_assmts.bit
573
+ ## # after successful read, the state is known to be initialised
574
+ state.discard(Uninitialized)
575
+ state.discard(Unknown)
576
+ for assmt in state:
577
+ assmt.refs.add(stat)
578
+
579
+ # Check variable usage
580
+ warn_maybe_uninitialized = compiler_directives['warn.maybe_uninitialized']
581
+ warn_unused_result = compiler_directives['warn.unused_result']
582
+ warn_unused = compiler_directives['warn.unused']
583
+ warn_unused_arg = compiler_directives['warn.unused_arg']
584
+
585
+ messages = MessageCollection()
586
+
587
+ # assignment hints
588
+ for node in assmt_nodes:
589
+ if Uninitialized in node.cf_state:
590
+ node.cf_maybe_null = True
591
+ if len(node.cf_state) == 1:
592
+ node.cf_is_null = True
593
+ else:
594
+ node.cf_is_null = False
595
+ elif Unknown in node.cf_state:
596
+ node.cf_maybe_null = True
597
+ else:
598
+ node.cf_is_null = False
599
+ node.cf_maybe_null = False
600
+
601
+ # Find uninitialized references and cf-hints
602
+ for node, entry in references.items():
603
+ if Uninitialized in node.cf_state:
604
+ node.cf_maybe_null = True
605
+ if (not entry.from_closure and len(node.cf_state) == 1
606
+ and entry.name not in entry.scope.scope_predefined_names):
607
+ node.cf_is_null = True
608
+ if (node.allow_null or entry.from_closure
609
+ or entry.is_pyclass_attr or entry.type.is_error):
610
+ pass # Can be uninitialized here
611
+ elif node.cf_is_null and not entry.in_closure:
612
+ if entry.error_on_uninitialized or (
613
+ Options.error_on_uninitialized and (
614
+ entry.type.is_pyobject or entry.type.is_unspecified)):
615
+ messages.error(
616
+ node.pos,
617
+ "local variable '%s' referenced before assignment"
618
+ % entry.name)
619
+ else:
620
+ messages.warning(
621
+ node.pos,
622
+ "local variable '%s' referenced before assignment"
623
+ % entry.name)
624
+ elif warn_maybe_uninitialized:
625
+ msg = "local variable '%s' might be referenced before assignment" % entry.name
626
+ if entry.in_closure:
627
+ msg += " (maybe initialized inside a closure)"
628
+ messages.warning(
629
+ node.pos,
630
+ msg)
631
+ elif Unknown in node.cf_state:
632
+ # TODO: better cross-closure analysis to know when inner functions
633
+ # are being called before a variable is being set, and when
634
+ # a variable is known to be set before even defining the
635
+ # inner function, etc.
636
+ node.cf_maybe_null = True
637
+ else:
638
+ node.cf_is_null = False
639
+ node.cf_maybe_null = False
640
+
641
+ # Unused result
642
+ for assmt in assignments:
643
+ if (not assmt.refs and not assmt.entry.is_pyclass_attr
644
+ and not assmt.entry.in_closure):
645
+ if assmt.entry.cf_references and warn_unused_result:
646
+ if assmt.is_arg:
647
+ messages.warning(assmt.pos, "Unused argument value '%s'" %
648
+ assmt.entry.name)
649
+ else:
650
+ messages.warning(assmt.pos, "Unused result in '%s'" %
651
+ assmt.entry.name)
652
+ assmt.lhs.cf_used = False
653
+
654
+ # Unused entries
655
+ for entry in flow.entries:
656
+ if (not entry.cf_references
657
+ and not entry.is_pyclass_attr):
658
+ if entry.name != '_' and not entry.name.startswith('unused'):
659
+ # '_' is often used for unused variables, e.g. in loops
660
+ if entry.is_arg:
661
+ if warn_unused_arg:
662
+ messages.warning(entry.pos, "Unused argument '%s'" %
663
+ entry.name)
664
+ else:
665
+ if warn_unused:
666
+ messages.warning(entry.pos, "Unused entry '%s'" %
667
+ entry.name)
668
+ entry.cf_used = False
669
+
670
+ messages.report()
671
+
672
+ for node in assmt_nodes:
673
+ node.cf_state = ControlFlowState(node.cf_state)
674
+ for node in references:
675
+ node.cf_state = ControlFlowState(node.cf_state)
676
+
677
+
678
+ class AssignmentCollector(TreeVisitor):
679
+ def __init__(self):
680
+ super().__init__()
681
+ self.assignments = []
682
+
683
+ def visit_Node(self):
684
+ self._visitchildren(self, None, None)
685
+
686
+ def visit_SingleAssignmentNode(self, node):
687
+ self.assignments.append((node.lhs, node.rhs))
688
+
689
+ def visit_CascadedAssignmentNode(self, node):
690
+ for lhs in node.lhs_list:
691
+ self.assignments.append((lhs, node.rhs))
692
+
693
+
694
+ class ControlFlowAnalysis(CythonTransform):
695
+
696
+ def find_in_stack(self, env):
697
+ if env == self.env:
698
+ return self.flow
699
+ for e, flow in reversed(self.stack):
700
+ if e is env:
701
+ return flow
702
+ assert False
703
+
704
+ def visit_ModuleNode(self, node):
705
+ dot_output = self.current_directives['control_flow.dot_output']
706
+ self.gv_ctx = GVContext() if dot_output else None
707
+
708
+ from .Optimize import ConstantFolding
709
+ self.constant_folder = ConstantFolding()
710
+
711
+ # Set of NameNode reductions
712
+ self.reductions = set()
713
+
714
+ self.in_inplace_assignment = False
715
+ self.env = node.scope
716
+ self.flow = ControlFlow()
717
+ self.stack = [] # a stack of (env, flow) tuples
718
+ self.object_expr = TypedExprNode(PyrexTypes.py_object_type, may_be_none=True)
719
+ self.visitchildren(node)
720
+
721
+ check_definitions(self.flow, self.current_directives)
722
+
723
+ if dot_output:
724
+ annotate_defs = self.current_directives['control_flow.dot_annotate_defs']
725
+ with open(dot_output, 'w') as fp:
726
+ self.gv_ctx.render(fp, 'module', annotate_defs=annotate_defs)
727
+ return node
728
+
729
+ def visit_FuncDefNode(self, node):
730
+ for arg in node.args:
731
+ if arg.default:
732
+ self.visitchildren(arg)
733
+ self.visitchildren(node, ('decorators',))
734
+ self.stack.append((self.env, self.flow))
735
+ self.env = node.local_scope
736
+ self.flow = ControlFlow()
737
+
738
+ # Collect all entries
739
+ for entry in node.local_scope.entries.values():
740
+ if self.flow.is_tracked(entry):
741
+ self.flow.entries.add(entry)
742
+
743
+ self.mark_position(node)
744
+ # Function body block
745
+ self.flow.nextblock()
746
+
747
+ for arg in node.args:
748
+ self._visit(arg)
749
+ if node.star_arg:
750
+ self.flow.mark_argument(node.star_arg,
751
+ TypedExprNode(Builtin.tuple_type,
752
+ may_be_none=False),
753
+ node.star_arg.entry)
754
+ if node.starstar_arg:
755
+ self.flow.mark_argument(node.starstar_arg,
756
+ TypedExprNode(Builtin.dict_type,
757
+ may_be_none=False),
758
+ node.starstar_arg.entry)
759
+ self._visit(node.body)
760
+ # Workaround for generators
761
+ if node.is_generator:
762
+ self._visit(node.gbody.body)
763
+
764
+ # Exit point
765
+ if self.flow.block:
766
+ self.flow.block.add_child(self.flow.exit_point)
767
+
768
+ # Cleanup graph
769
+ self.flow.normalize()
770
+ check_definitions(self.flow, self.current_directives)
771
+ self.flow.blocks.add(self.flow.entry_point)
772
+
773
+ if self.gv_ctx is not None:
774
+ self.gv_ctx.add(GV(node.local_scope.name, self.flow))
775
+
776
+ self.env, self.flow = self.stack.pop()
777
+ return node
778
+
779
+ def visit_DefNode(self, node):
780
+ node.used = True
781
+ return self.visit_FuncDefNode(node)
782
+
783
+ def visit_GeneratorBodyDefNode(self, node):
784
+ return node
785
+
786
+ def visit_CTypeDefNode(self, node):
787
+ return node
788
+
789
+ def mark_assignment(self, lhs, rhs=None, rhs_scope=None):
790
+ if not self.flow.block:
791
+ return
792
+ if self.flow.exceptions:
793
+ exc_descr = self.flow.exceptions[-1]
794
+ self.flow.block.add_child(exc_descr.entry_point)
795
+ self.flow.nextblock()
796
+
797
+ if not rhs:
798
+ rhs = self.object_expr
799
+ if lhs.is_name:
800
+ if lhs.entry is not None:
801
+ entry = lhs.entry
802
+ else:
803
+ entry = self.env.lookup(lhs.name)
804
+ if entry is None: # TODO: This shouldn't happen...
805
+ return
806
+ self.flow.mark_assignment(lhs, rhs, entry, rhs_scope=rhs_scope)
807
+ elif lhs.is_sequence_constructor:
808
+ for i, arg in enumerate(lhs.args):
809
+ if arg.is_starred:
810
+ # "a, *b = x" assigns a list to "b"
811
+ item_node = TypedExprNode(Builtin.list_type, may_be_none=False, pos=arg.pos)
812
+ elif rhs is self.object_expr:
813
+ item_node = rhs
814
+ else:
815
+ item_node = rhs.inferable_item_node(i)
816
+ self.mark_assignment(arg, item_node)
817
+ else:
818
+ self._visit(lhs)
819
+
820
+ if self.flow.exceptions:
821
+ exc_descr = self.flow.exceptions[-1]
822
+ self.flow.block.add_child(exc_descr.entry_point)
823
+ self.flow.nextblock()
824
+
825
+ def mark_position(self, node):
826
+ """Mark position if DOT output is enabled."""
827
+ if self.current_directives['control_flow.dot_output']:
828
+ self.flow.mark_position(node)
829
+
830
+ def visit_FromImportStatNode(self, node):
831
+ for name, target in node.items:
832
+ if name != "*":
833
+ self.mark_assignment(target)
834
+ self.visitchildren(node)
835
+ return node
836
+
837
+ def visit_AssignmentNode(self, node):
838
+ raise InternalError("Unhandled assignment node %s" % type(node))
839
+
840
+ def visit_SingleAssignmentNode(self, node):
841
+ self._visit(node.rhs)
842
+ self.mark_assignment(node.lhs, node.rhs)
843
+ return node
844
+
845
+ def visit_CascadedAssignmentNode(self, node):
846
+ self._visit(node.rhs)
847
+ for lhs in node.lhs_list:
848
+ self.mark_assignment(lhs, node.rhs)
849
+ return node
850
+
851
+ def visit_ParallelAssignmentNode(self, node):
852
+ collector = AssignmentCollector()
853
+ collector.visitchildren(node)
854
+ for lhs, rhs in collector.assignments:
855
+ self._visit(rhs)
856
+ for lhs, rhs in collector.assignments:
857
+ self.mark_assignment(lhs, rhs)
858
+ return node
859
+
860
+ def visit_InPlaceAssignmentNode(self, node):
861
+ self.in_inplace_assignment = True
862
+ self.visitchildren(node)
863
+ self.in_inplace_assignment = False
864
+ self.mark_assignment(node.lhs, self.constant_folder(node.create_binop_node()))
865
+ return node
866
+
867
+ def visit_DelStatNode(self, node):
868
+ for arg in node.args:
869
+ if arg.is_name:
870
+ entry = arg.entry or self.env.lookup(arg.name)
871
+ if entry.in_closure or entry.from_closure:
872
+ error(arg.pos,
873
+ "can not delete variable '%s' "
874
+ "referenced in nested scope" % entry.name)
875
+ if not node.ignore_nonexisting:
876
+ self._visit(arg) # mark reference
877
+ self.flow.mark_deletion(arg, entry)
878
+ else:
879
+ self._visit(arg)
880
+ return node
881
+
882
+ def visit_CArgDeclNode(self, node):
883
+ entry = self.env.lookup(node.name)
884
+ if entry:
885
+ may_be_none = not node.not_none
886
+ self.flow.mark_argument(
887
+ node, TypedExprNode(entry.type, may_be_none), entry)
888
+ return node
889
+
890
+ def visit_NameNode(self, node):
891
+ if self.flow.block:
892
+ entry = node.entry or self.env.lookup(node.name)
893
+ if entry:
894
+ self.flow.mark_reference(node, entry)
895
+
896
+ if entry in self.reductions and not self.in_inplace_assignment:
897
+ error(node.pos,
898
+ "Cannot read reduction variable in loop body")
899
+
900
+ return node
901
+
902
+ def visit_StatListNode(self, node):
903
+ if self.flow.block:
904
+ for stat in node.stats:
905
+ self._visit(stat)
906
+ if not self.flow.block:
907
+ stat.is_terminator = True
908
+ break
909
+ return node
910
+
911
+ def visit_Node(self, node):
912
+ self.visitchildren(node)
913
+ self.mark_position(node)
914
+ return node
915
+
916
+ def visit_SizeofVarNode(self, node):
917
+ return node
918
+
919
+ def visit_TypeidNode(self, node):
920
+ return node
921
+
922
+ def visit_IfStatNode(self, node):
923
+ next_block = self.flow.newblock()
924
+ parent = self.flow.block
925
+ # If clauses
926
+ for clause in node.if_clauses:
927
+ parent = self.flow.nextblock(parent)
928
+ self._visit(clause.condition)
929
+ self.flow.nextblock()
930
+ self._visit(clause.body)
931
+ if self.flow.block:
932
+ self.flow.block.add_child(next_block)
933
+ # Else clause
934
+ if node.else_clause:
935
+ self.flow.nextblock(parent=parent)
936
+ self._visit(node.else_clause)
937
+ if self.flow.block:
938
+ self.flow.block.add_child(next_block)
939
+ else:
940
+ parent.add_child(next_block)
941
+
942
+ if next_block.parents:
943
+ self.flow.block = next_block
944
+ else:
945
+ self.flow.block = None
946
+ return node
947
+
948
+ def visit_AssertStatNode(self, node):
949
+ """Essentially an if-condition that wraps a RaiseStatNode.
950
+ """
951
+ self.mark_position(node)
952
+ next_block = self.flow.newblock()
953
+ parent = self.flow.block
954
+ # failure case
955
+ parent = self.flow.nextblock(parent)
956
+ self._visit(node.condition)
957
+ self.flow.nextblock()
958
+ self._visit(node.exception)
959
+ if self.flow.block:
960
+ self.flow.block.add_child(next_block)
961
+ parent.add_child(next_block)
962
+ if next_block.parents:
963
+ self.flow.block = next_block
964
+ else:
965
+ self.flow.block = None
966
+ return node
967
+
968
+ def visit_WhileStatNode(self, node):
969
+ condition_block = self.flow.nextblock()
970
+ next_block = self.flow.newblock()
971
+ # Condition block
972
+ self.flow.loops.append(LoopDescr(next_block, condition_block))
973
+ if node.condition:
974
+ self._visit(node.condition)
975
+ # Body block
976
+ self.flow.nextblock()
977
+ self._visit(node.body)
978
+ self.flow.loops.pop()
979
+ # Loop it
980
+ if self.flow.block:
981
+ self.flow.block.add_child(condition_block)
982
+ self.flow.block.add_child(next_block)
983
+ # Else clause
984
+ if node.else_clause:
985
+ self.flow.nextblock(parent=condition_block)
986
+ self._visit(node.else_clause)
987
+ if self.flow.block:
988
+ self.flow.block.add_child(next_block)
989
+ else:
990
+ condition_block.add_child(next_block)
991
+
992
+ if next_block.parents:
993
+ self.flow.block = next_block
994
+ else:
995
+ self.flow.block = None
996
+ return node
997
+
998
+ def mark_forloop_target(self, node):
999
+ # TODO: Remove redundancy with range optimization...
1000
+ is_special = False
1001
+ sequence = node.iterator.sequence
1002
+ target = node.target
1003
+ env = node.iterator.expr_scope or self.env
1004
+ if isinstance(sequence, ExprNodes.SimpleCallNode):
1005
+ function = sequence.function
1006
+ if sequence.self is None and function.is_name:
1007
+ entry = env.lookup(function.name)
1008
+ if not entry or entry.is_builtin:
1009
+ if function.name == 'reversed' and len(sequence.args) == 1:
1010
+ sequence = sequence.args[0]
1011
+ elif function.name == 'enumerate' and len(sequence.args) == 1:
1012
+ if target.is_sequence_constructor and len(target.args) == 2:
1013
+ iterator = sequence.args[0]
1014
+ if iterator.is_name:
1015
+ iterator_type = iterator.infer_type(env)
1016
+ if iterator_type.is_builtin_type:
1017
+ # assume that builtin types have a length within Py_ssize_t
1018
+ self.mark_assignment(
1019
+ target.args[0],
1020
+ ExprNodes.IntNode(target.pos, value='PY_SSIZE_T_MAX',
1021
+ type=PyrexTypes.c_py_ssize_t_type),
1022
+ rhs_scope=node.iterator.expr_scope)
1023
+ target = target.args[1]
1024
+ sequence = sequence.args[0]
1025
+ if isinstance(sequence, ExprNodes.SimpleCallNode):
1026
+ function = sequence.function
1027
+ if sequence.self is None and function.is_name:
1028
+ entry = env.lookup(function.name)
1029
+ if not entry or entry.is_builtin:
1030
+ if function.name in ('range', 'xrange'):
1031
+ is_special = True
1032
+ for arg in sequence.args[:2]:
1033
+ self.mark_assignment(target, arg, rhs_scope=node.iterator.expr_scope)
1034
+ if len(sequence.args) > 2:
1035
+ self.mark_assignment(target, self.constant_folder(
1036
+ ExprNodes.binop_node(node.pos,
1037
+ '+',
1038
+ sequence.args[0],
1039
+ sequence.args[2])),
1040
+ rhs_scope=node.iterator.expr_scope)
1041
+
1042
+ if not is_special:
1043
+ # A for-loop basically translates to subsequent calls to
1044
+ # __getitem__(), so using an IndexNode here allows us to
1045
+ # naturally infer the base type of pointers, C arrays,
1046
+ # Python strings, etc., while correctly falling back to an
1047
+ # object type when the base type cannot be handled.
1048
+
1049
+ self.mark_assignment(target, node.item, rhs_scope=node.iterator.expr_scope)
1050
+
1051
+ def visit_AsyncForStatNode(self, node):
1052
+ return self.visit_ForInStatNode(node)
1053
+
1054
+ def visit_ForInStatNode(self, node):
1055
+ condition_block = self.flow.nextblock()
1056
+ next_block = self.flow.newblock()
1057
+ # Condition with iterator
1058
+ self.flow.loops.append(LoopDescr(next_block, condition_block))
1059
+ self._visit(node.iterator)
1060
+ # Target assignment
1061
+ self.flow.nextblock()
1062
+
1063
+ if isinstance(node, Nodes.ForInStatNode):
1064
+ self.mark_forloop_target(node)
1065
+ elif isinstance(node, Nodes.AsyncForStatNode):
1066
+ # not entirely correct, but good enough for now
1067
+ self.mark_assignment(node.target, node.item)
1068
+ else: # Parallel
1069
+ self.mark_assignment(node.target)
1070
+
1071
+ # Body block
1072
+ if isinstance(node, Nodes.ParallelRangeNode):
1073
+ # In case of an invalid
1074
+ self._delete_privates(node, exclude=node.target.entry)
1075
+
1076
+ self.flow.nextblock()
1077
+ self._visit(node.body)
1078
+ self.flow.loops.pop()
1079
+
1080
+ # Loop it
1081
+ if self.flow.block:
1082
+ self.flow.block.add_child(condition_block)
1083
+ # Else clause
1084
+ if node.else_clause:
1085
+ self.flow.nextblock(parent=condition_block)
1086
+ self._visit(node.else_clause)
1087
+ if self.flow.block:
1088
+ self.flow.block.add_child(next_block)
1089
+ else:
1090
+ condition_block.add_child(next_block)
1091
+
1092
+ if next_block.parents:
1093
+ self.flow.block = next_block
1094
+ else:
1095
+ self.flow.block = None
1096
+ return node
1097
+
1098
+ def _delete_privates(self, node, exclude=None):
1099
+ for private_node in node.assigned_nodes:
1100
+ if not exclude or private_node.entry is not exclude:
1101
+ self.flow.mark_deletion(private_node, private_node.entry)
1102
+
1103
+ def visit_ParallelRangeNode(self, node):
1104
+ reductions = self.reductions
1105
+
1106
+ # if node.target is None or not a NameNode, an error will have
1107
+ # been previously issued
1108
+ if hasattr(node.target, 'entry'):
1109
+ self.reductions = set(reductions)
1110
+
1111
+ for private_node in node.assigned_nodes:
1112
+ private_node.entry.error_on_uninitialized = True
1113
+ pos, reduction = node.assignments[private_node.entry]
1114
+ if reduction:
1115
+ self.reductions.add(private_node.entry)
1116
+
1117
+ node = self.visit_ForInStatNode(node)
1118
+
1119
+ self.reductions = reductions
1120
+ return node
1121
+
1122
+ def visit_ParallelWithBlockNode(self, node):
1123
+ for private_node in node.assigned_nodes:
1124
+ private_node.entry.error_on_uninitialized = True
1125
+
1126
+ self._delete_privates(node)
1127
+ self.visitchildren(node)
1128
+ self._delete_privates(node)
1129
+
1130
+ return node
1131
+
1132
+ def visit_ForFromStatNode(self, node):
1133
+ condition_block = self.flow.nextblock()
1134
+ next_block = self.flow.newblock()
1135
+ # Condition with iterator
1136
+ self.flow.loops.append(LoopDescr(next_block, condition_block))
1137
+ self._visit(node.bound1)
1138
+ self._visit(node.bound2)
1139
+ if node.step is not None:
1140
+ self._visit(node.step)
1141
+ # Target assignment
1142
+ self.flow.nextblock()
1143
+ self.mark_assignment(node.target, node.bound1)
1144
+ if node.step is not None:
1145
+ self.mark_assignment(node.target, self.constant_folder(
1146
+ ExprNodes.binop_node(node.pos, '+', node.bound1, node.step)))
1147
+ # Body block
1148
+ self.flow.nextblock()
1149
+ self._visit(node.body)
1150
+ self.flow.loops.pop()
1151
+ # Loop it
1152
+ if self.flow.block:
1153
+ self.flow.block.add_child(condition_block)
1154
+ # Else clause
1155
+ if node.else_clause:
1156
+ self.flow.nextblock(parent=condition_block)
1157
+ self._visit(node.else_clause)
1158
+ if self.flow.block:
1159
+ self.flow.block.add_child(next_block)
1160
+ else:
1161
+ condition_block.add_child(next_block)
1162
+
1163
+ if next_block.parents:
1164
+ self.flow.block = next_block
1165
+ else:
1166
+ self.flow.block = None
1167
+ return node
1168
+
1169
+ def visit_LoopNode(self, node):
1170
+ raise InternalError("Generic loops are not supported")
1171
+
1172
+ def visit_WithTargetAssignmentStatNode(self, node):
1173
+ self.mark_assignment(node.lhs, node.with_node.enter_call)
1174
+ return node
1175
+
1176
+ def visit_WithStatNode(self, node):
1177
+ self._visit(node.manager)
1178
+ self._visit(node.enter_call)
1179
+ self._visit(node.body)
1180
+ return node
1181
+
1182
+ def visit_TryExceptStatNode(self, node):
1183
+ # After exception handling
1184
+ next_block = self.flow.newblock()
1185
+ # Body block
1186
+ self.flow.newblock()
1187
+ # Exception entry point
1188
+ entry_point = self.flow.newblock()
1189
+ self.flow.exceptions.append(ExceptionDescr(entry_point))
1190
+ self.flow.nextblock()
1191
+ ## XXX: links to exception handling point should be added by
1192
+ ## XXX: children nodes
1193
+ self.flow.block.add_child(entry_point)
1194
+ self.flow.nextblock()
1195
+ self.flow.in_try_block += 1
1196
+ self._visit(node.body)
1197
+ self.flow.in_try_block -= 1
1198
+ self.flow.exceptions.pop()
1199
+
1200
+ # After exception
1201
+ if self.flow.block:
1202
+ if node.else_clause:
1203
+ self.flow.nextblock()
1204
+ self._visit(node.else_clause)
1205
+ if self.flow.block:
1206
+ self.flow.block.add_child(next_block)
1207
+
1208
+ for clause in node.except_clauses:
1209
+ self.flow.block = entry_point
1210
+ if clause.pattern:
1211
+ for pattern in clause.pattern:
1212
+ self._visit(pattern)
1213
+ else:
1214
+ # TODO: handle * pattern
1215
+ pass
1216
+ entry_point = self.flow.newblock(parent=self.flow.block)
1217
+ self.flow.nextblock()
1218
+ if clause.target:
1219
+ self.mark_assignment(clause.target)
1220
+ self._visit(clause.body)
1221
+ if self.flow.block:
1222
+ self.flow.block.add_child(next_block)
1223
+
1224
+ if self.flow.exceptions:
1225
+ entry_point.add_child(self.flow.exceptions[-1].entry_point)
1226
+
1227
+ if next_block.parents:
1228
+ self.flow.block = next_block
1229
+ else:
1230
+ self.flow.block = None
1231
+ return node
1232
+
1233
+ def visit_TryFinallyStatNode(self, node):
1234
+ body_block = self.flow.nextblock()
1235
+
1236
+ # Exception entry point
1237
+ entry_point = self.flow.newblock()
1238
+ self.flow.block = entry_point
1239
+ self._visit(node.finally_except_clause)
1240
+
1241
+ if self.flow.block and self.flow.exceptions:
1242
+ self.flow.block.add_child(self.flow.exceptions[-1].entry_point)
1243
+
1244
+ # Normal execution
1245
+ finally_enter = self.flow.newblock()
1246
+ self.flow.block = finally_enter
1247
+ self._visit(node.finally_clause)
1248
+ finally_exit = self.flow.block
1249
+
1250
+ descr = ExceptionDescr(entry_point, finally_enter, finally_exit)
1251
+ self.flow.exceptions.append(descr)
1252
+ if self.flow.loops:
1253
+ self.flow.loops[-1].exceptions.append(descr)
1254
+ self.flow.block = body_block
1255
+ body_block.add_child(entry_point)
1256
+ self.flow.nextblock()
1257
+ self.flow.in_try_block += 1
1258
+ self._visit(node.body)
1259
+ self.flow.in_try_block -= 1
1260
+ self.flow.exceptions.pop()
1261
+ if self.flow.loops:
1262
+ self.flow.loops[-1].exceptions.pop()
1263
+
1264
+ if self.flow.block:
1265
+ self.flow.block.add_child(finally_enter)
1266
+ if finally_exit:
1267
+ self.flow.block = self.flow.nextblock(parent=finally_exit)
1268
+ else:
1269
+ self.flow.block = None
1270
+ return node
1271
+
1272
+ def visit_RaiseStatNode(self, node):
1273
+ self.mark_position(node)
1274
+ self.visitchildren(node)
1275
+ if self.flow.exceptions:
1276
+ self.flow.block.add_child(self.flow.exceptions[-1].entry_point)
1277
+ self.flow.block = None
1278
+ if self.flow.in_try_block:
1279
+ node.in_try_block = True
1280
+ return node
1281
+
1282
+ def visit_ReraiseStatNode(self, node):
1283
+ self.mark_position(node)
1284
+ if self.flow.exceptions:
1285
+ self.flow.block.add_child(self.flow.exceptions[-1].entry_point)
1286
+ self.flow.block = None
1287
+ return node
1288
+
1289
+ def visit_ReturnStatNode(self, node):
1290
+ self.mark_position(node)
1291
+ self.visitchildren(node)
1292
+
1293
+ outer_exception_handlers = iter(self.flow.exceptions[::-1])
1294
+ for handler in outer_exception_handlers:
1295
+ if handler.finally_enter:
1296
+ self.flow.block.add_child(handler.finally_enter)
1297
+ if handler.finally_exit:
1298
+ # 'return' goes to function exit, or to the next outer 'finally' clause
1299
+ exit_point = self.flow.exit_point
1300
+ for next_handler in outer_exception_handlers:
1301
+ if next_handler.finally_enter:
1302
+ exit_point = next_handler.finally_enter
1303
+ break
1304
+ handler.finally_exit.add_child(exit_point)
1305
+ break
1306
+ else:
1307
+ if self.flow.block:
1308
+ self.flow.block.add_child(self.flow.exit_point)
1309
+ self.flow.block = None
1310
+ return node
1311
+
1312
+ def visit_BreakStatNode(self, node):
1313
+ if not self.flow.loops:
1314
+ #error(node.pos, "break statement not inside loop")
1315
+ return node
1316
+ loop = self.flow.loops[-1]
1317
+ self.mark_position(node)
1318
+ for exception in loop.exceptions[::-1]:
1319
+ if exception.finally_enter:
1320
+ self.flow.block.add_child(exception.finally_enter)
1321
+ if exception.finally_exit:
1322
+ exception.finally_exit.add_child(loop.next_block)
1323
+ break
1324
+ else:
1325
+ self.flow.block.add_child(loop.next_block)
1326
+ self.flow.block = None
1327
+ return node
1328
+
1329
+ def visit_ContinueStatNode(self, node):
1330
+ if not self.flow.loops:
1331
+ #error(node.pos, "continue statement not inside loop")
1332
+ return node
1333
+ loop = self.flow.loops[-1]
1334
+ self.mark_position(node)
1335
+ for exception in loop.exceptions[::-1]:
1336
+ if exception.finally_enter:
1337
+ self.flow.block.add_child(exception.finally_enter)
1338
+ if exception.finally_exit:
1339
+ exception.finally_exit.add_child(loop.loop_block)
1340
+ break
1341
+ else:
1342
+ self.flow.block.add_child(loop.loop_block)
1343
+ self.flow.block = None
1344
+ return node
1345
+
1346
+ def visit_ComprehensionNode(self, node):
1347
+ if node.expr_scope:
1348
+ self.stack.append((self.env, self.flow))
1349
+ self.env = node.expr_scope
1350
+ # Skip append node here
1351
+ self._visit(node.loop)
1352
+ if node.expr_scope:
1353
+ self.env, _ = self.stack.pop()
1354
+ return node
1355
+
1356
+ def visit_ScopedExprNode(self, node):
1357
+ # currently this is written to deal with these two types
1358
+ # (with comprehensions covered in their own function)
1359
+ assert isinstance(node, (ExprNodes.IteratorNode, ExprNodes.AsyncIteratorNode)), node
1360
+ if node.expr_scope:
1361
+ self.stack.append((self.env, self.flow))
1362
+ self.flow = self.find_in_stack(node.expr_scope)
1363
+ self.env = node.expr_scope
1364
+ self.visitchildren(node)
1365
+ if node.expr_scope:
1366
+ self.env, self.flow = self.stack.pop()
1367
+ return node
1368
+
1369
+ def visit_PyClassDefNode(self, node):
1370
+ self.visitchildren(node, ('dict', 'metaclass',
1371
+ 'mkw', 'bases', 'class_result'))
1372
+ self.flow.mark_assignment(node.target, node.classobj,
1373
+ self.env.lookup(node.target.name))
1374
+ self.stack.append((self.env, self.flow))
1375
+ self.env = node.scope
1376
+ self.flow.nextblock()
1377
+ if node.doc_node:
1378
+ self.flow.mark_assignment(node.doc_node, fake_rhs_expr, node.doc_node.entry)
1379
+ self.visitchildren(node, ('body',))
1380
+ self.flow.nextblock()
1381
+ self.env, _ = self.stack.pop()
1382
+ return node
1383
+
1384
+ def visit_CClassDefNode(self, node):
1385
+ # just make sure the nodes scope is findable in-case there is a list comprehension in it
1386
+ self.stack.append((node.scope, self.flow))
1387
+ self.visitchildren(node)
1388
+ self.stack.pop()
1389
+ return node
1390
+
1391
+ def visit_AmpersandNode(self, node):
1392
+ if node.operand.is_name:
1393
+ # Fake assignment to silence warning
1394
+ self.mark_assignment(node.operand, fake_rhs_expr)
1395
+ self.visitchildren(node)
1396
+ return node
1397
+
1398
+ def visit_BoolBinopNode(self, node):
1399
+ # Note - I don't believe BoolBinopResultNode needs special handling beyond this
1400
+ assert len(node.subexprs) == 2 # operand1 and operand2 only
1401
+
1402
+ next_block = self.flow.newblock()
1403
+ parent = self.flow.block
1404
+
1405
+ self._visit(node.operand1)
1406
+
1407
+ self.flow.nextblock()
1408
+ self._visit(node.operand2)
1409
+ if self.flow.block:
1410
+ self.flow.block.add_child(next_block)
1411
+
1412
+ parent.add_child(next_block)
1413
+
1414
+ if next_block.parents:
1415
+ self.flow.block = next_block
1416
+ else:
1417
+ self.flow.block = None
1418
+ return node
1419
+
1420
+ def visit_CondExprNode(self, node):
1421
+ assert len(node.subexprs) == 3
1422
+ self._visit(node.test)
1423
+ parent = self.flow.block
1424
+ next_block = self.flow.newblock()
1425
+ self.flow.nextblock()
1426
+ self._visit(node.true_val)
1427
+ if self.flow.block:
1428
+ self.flow.block.add_child(next_block)
1429
+ self.flow.nextblock(parent=parent)
1430
+ self._visit(node.false_val)
1431
+ if self.flow.block:
1432
+ self.flow.block.add_child(next_block)
1433
+
1434
+ if next_block.parents:
1435
+ self.flow.block = next_block
1436
+ else:
1437
+ self.flow.block = None
1438
+ return node