Cython 3.3.0__cp315-cp315-win_amd64.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 (339) hide show
  1. Cython/Build/BuildExecutable.py +156 -0
  2. Cython/Build/Cache.py +199 -0
  3. Cython/Build/Cythonize.py +349 -0
  4. Cython/Build/Dependencies.py +1281 -0
  5. Cython/Build/Distutils.py +1 -0
  6. Cython/Build/Inline.py +467 -0
  7. Cython/Build/IpythonMagic.py +559 -0
  8. Cython/Build/SharedModule.py +165 -0
  9. Cython/Build/Tests/TestCyCache.py +195 -0
  10. Cython/Build/Tests/TestCythonizeArgsParser.py +480 -0
  11. Cython/Build/Tests/TestDependencies.py +133 -0
  12. Cython/Build/Tests/TestInline.py +177 -0
  13. Cython/Build/Tests/TestIpythonMagic.py +303 -0
  14. Cython/Build/Tests/TestRecythonize.py +212 -0
  15. Cython/Build/Tests/TestStripLiterals.py +155 -0
  16. Cython/Build/Tests/__init__.py +1 -0
  17. Cython/Build/__init__.py +11 -0
  18. Cython/CodeWriter.py +825 -0
  19. Cython/Compiler/AnalysedTreeTransforms.py +97 -0
  20. Cython/Compiler/Annotate.py +328 -0
  21. Cython/Compiler/AutoDocTransforms.py +320 -0
  22. Cython/Compiler/Buffer.py +679 -0
  23. Cython/Compiler/Builtin.py +1102 -0
  24. Cython/Compiler/CmdLine.py +373 -0
  25. Cython/Compiler/Code.cp315-win_amd64.pyd +0 -0
  26. Cython/Compiler/Code.pxd +154 -0
  27. Cython/Compiler/Code.py +3760 -0
  28. Cython/Compiler/CodeGeneration.py +33 -0
  29. Cython/Compiler/CythonScope.py +208 -0
  30. Cython/Compiler/Dataclass.py +890 -0
  31. Cython/Compiler/DebugFlags.py +24 -0
  32. Cython/Compiler/Errors.py +310 -0
  33. Cython/Compiler/ExprNodes.py +16273 -0
  34. Cython/Compiler/FlowControl.cp315-win_amd64.pyd +0 -0
  35. Cython/Compiler/FlowControl.pxd +112 -0
  36. Cython/Compiler/FlowControl.py +1573 -0
  37. Cython/Compiler/FusedNode.cp315-win_amd64.pyd +0 -0
  38. Cython/Compiler/FusedNode.py +978 -0
  39. Cython/Compiler/Future.py +16 -0
  40. Cython/Compiler/Interpreter.py +57 -0
  41. Cython/Compiler/Lexicon.py +422 -0
  42. Cython/Compiler/LineTable.cp315-win_amd64.pyd +0 -0
  43. Cython/Compiler/LineTable.py +114 -0
  44. Cython/Compiler/Main.py +856 -0
  45. Cython/Compiler/MatchCaseNodes.py +2200 -0
  46. Cython/Compiler/MemoryView.py +930 -0
  47. Cython/Compiler/ModuleNode.py +4548 -0
  48. Cython/Compiler/Naming.py +370 -0
  49. Cython/Compiler/Nodes.py +11304 -0
  50. Cython/Compiler/Optimize.py +5564 -0
  51. Cython/Compiler/Options.py +840 -0
  52. Cython/Compiler/ParseTreeTransforms.pxd +80 -0
  53. Cython/Compiler/ParseTreeTransforms.py +4808 -0
  54. Cython/Compiler/Parsing.cp315-win_amd64.pyd +0 -0
  55. Cython/Compiler/Parsing.pxd +9 -0
  56. Cython/Compiler/Parsing.py +4809 -0
  57. Cython/Compiler/Pipeline.py +439 -0
  58. Cython/Compiler/PyrexTypes.py +6588 -0
  59. Cython/Compiler/Pythran.py +232 -0
  60. Cython/Compiler/Scanning.cp315-win_amd64.pyd +0 -0
  61. Cython/Compiler/Scanning.pxd +70 -0
  62. Cython/Compiler/Scanning.py +720 -0
  63. Cython/Compiler/StringEncoding.cp315-win_amd64.pyd +0 -0
  64. Cython/Compiler/StringEncoding.py +354 -0
  65. Cython/Compiler/Symtab.py +3121 -0
  66. Cython/Compiler/Tests/TestBuffer.py +105 -0
  67. Cython/Compiler/Tests/TestBuiltin.py +196 -0
  68. Cython/Compiler/Tests/TestCmdLine.py +652 -0
  69. Cython/Compiler/Tests/TestCode.py +145 -0
  70. Cython/Compiler/Tests/TestFlowControl.py +65 -0
  71. Cython/Compiler/Tests/TestGrammar.py +202 -0
  72. Cython/Compiler/Tests/TestMemView.py +71 -0
  73. Cython/Compiler/Tests/TestParseTreeTransforms.py +285 -0
  74. Cython/Compiler/Tests/TestScanning.py +132 -0
  75. Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
  76. Cython/Compiler/Tests/TestStringEncoding.py +20 -0
  77. Cython/Compiler/Tests/TestTreeFragment.py +63 -0
  78. Cython/Compiler/Tests/TestTreePath.py +103 -0
  79. Cython/Compiler/Tests/TestTypes.py +119 -0
  80. Cython/Compiler/Tests/TestUtilityLoad.py +112 -0
  81. Cython/Compiler/Tests/TestVisitor.py +119 -0
  82. Cython/Compiler/Tests/Utils.py +36 -0
  83. Cython/Compiler/Tests/__init__.py +1 -0
  84. Cython/Compiler/TreeFragment.py +279 -0
  85. Cython/Compiler/TreePath.py +303 -0
  86. Cython/Compiler/TypeInference.py +611 -0
  87. Cython/Compiler/TypeSlots.py +1329 -0
  88. Cython/Compiler/UFuncs.py +317 -0
  89. Cython/Compiler/UtilNodes.py +389 -0
  90. Cython/Compiler/UtilityCode.py +354 -0
  91. Cython/Compiler/Version.py +8 -0
  92. Cython/Compiler/Visitor.cp315-win_amd64.pyd +0 -0
  93. Cython/Compiler/Visitor.pxd +52 -0
  94. Cython/Compiler/Visitor.py +914 -0
  95. Cython/Compiler/__init__.py +1 -0
  96. Cython/Coverage.py +448 -0
  97. Cython/Debugger/Cygdb.py +214 -0
  98. Cython/Debugger/DebugWriter.py +82 -0
  99. Cython/Debugger/Tests/TestLibCython.py +280 -0
  100. Cython/Debugger/Tests/__init__.py +1 -0
  101. Cython/Debugger/Tests/cfuncs.c +8 -0
  102. Cython/Debugger/Tests/codefile +49 -0
  103. Cython/Debugger/Tests/test_libcython_in_gdb.py +580 -0
  104. Cython/Debugger/Tests/test_libpython_in_gdb.py +90 -0
  105. Cython/Debugger/__init__.py +1 -0
  106. Cython/Debugger/libcython.py +1548 -0
  107. Cython/Debugger/libpython.py +2821 -0
  108. Cython/Debugging.py +20 -0
  109. Cython/Distutils/__init__.py +2 -0
  110. Cython/Distutils/build_ext.py +143 -0
  111. Cython/Distutils/extension.py +96 -0
  112. Cython/Distutils/old_build_ext.py +351 -0
  113. Cython/Includes/cpython/__init__.pxd +173 -0
  114. Cython/Includes/cpython/array.pxd +152 -0
  115. Cython/Includes/cpython/bool.pxd +37 -0
  116. Cython/Includes/cpython/buffer.pxd +112 -0
  117. Cython/Includes/cpython/bytearray.pxd +33 -0
  118. Cython/Includes/cpython/bytes.pxd +200 -0
  119. Cython/Includes/cpython/cellobject.pxd +35 -0
  120. Cython/Includes/cpython/ceval.pxd +8 -0
  121. Cython/Includes/cpython/codecs.pxd +121 -0
  122. Cython/Includes/cpython/complex.pxd +60 -0
  123. Cython/Includes/cpython/contextvars.pxd +145 -0
  124. Cython/Includes/cpython/conversion.pxd +36 -0
  125. Cython/Includes/cpython/datetime.pxd +395 -0
  126. Cython/Includes/cpython/descr.pxd +26 -0
  127. Cython/Includes/cpython/dict.pxd +268 -0
  128. Cython/Includes/cpython/exc.pxd +263 -0
  129. Cython/Includes/cpython/fileobject.pxd +57 -0
  130. Cython/Includes/cpython/float.pxd +56 -0
  131. Cython/Includes/cpython/frozendict.pxd +37 -0
  132. Cython/Includes/cpython/function.pxd +65 -0
  133. Cython/Includes/cpython/genobject.pxd +25 -0
  134. Cython/Includes/cpython/getargs.pxd +12 -0
  135. Cython/Includes/cpython/instance.pxd +25 -0
  136. Cython/Includes/cpython/iterator.pxd +36 -0
  137. Cython/Includes/cpython/iterobject.pxd +24 -0
  138. Cython/Includes/cpython/list.pxd +144 -0
  139. Cython/Includes/cpython/long.pxd +180 -0
  140. Cython/Includes/cpython/longintrepr.pxd +14 -0
  141. Cython/Includes/cpython/mapping.pxd +63 -0
  142. Cython/Includes/cpython/marshal.pxd +66 -0
  143. Cython/Includes/cpython/mem.pxd +120 -0
  144. Cython/Includes/cpython/memoryview.pxd +50 -0
  145. Cython/Includes/cpython/method.pxd +49 -0
  146. Cython/Includes/cpython/module.pxd +208 -0
  147. Cython/Includes/cpython/number.pxd +258 -0
  148. Cython/Includes/cpython/object.pxd +430 -0
  149. Cython/Includes/cpython/pycapsule.pxd +143 -0
  150. Cython/Includes/cpython/pylifecycle.pxd +68 -0
  151. Cython/Includes/cpython/pyport.pxd +8 -0
  152. Cython/Includes/cpython/pystate.pxd +95 -0
  153. Cython/Includes/cpython/pythread.pxd +53 -0
  154. Cython/Includes/cpython/ref.pxd +141 -0
  155. Cython/Includes/cpython/sentinel.pxd +17 -0
  156. Cython/Includes/cpython/sequence.pxd +134 -0
  157. Cython/Includes/cpython/set.pxd +119 -0
  158. Cython/Includes/cpython/slice.pxd +70 -0
  159. Cython/Includes/cpython/time.pxd +129 -0
  160. Cython/Includes/cpython/tuple.pxd +72 -0
  161. Cython/Includes/cpython/type.pxd +146 -0
  162. Cython/Includes/cpython/unicode.pxd +639 -0
  163. Cython/Includes/cpython/version.pxd +32 -0
  164. Cython/Includes/cpython/weakref.pxd +78 -0
  165. Cython/Includes/libc/__init__.pxd +1 -0
  166. Cython/Includes/libc/complex.pxd +35 -0
  167. Cython/Includes/libc/errno.pxd +127 -0
  168. Cython/Includes/libc/float.pxd +43 -0
  169. Cython/Includes/libc/limits.pxd +28 -0
  170. Cython/Includes/libc/locale.pxd +46 -0
  171. Cython/Includes/libc/math.pxd +209 -0
  172. Cython/Includes/libc/setjmp.pxd +10 -0
  173. Cython/Includes/libc/signal.pxd +64 -0
  174. Cython/Includes/libc/stddef.pxd +9 -0
  175. Cython/Includes/libc/stdint.pxd +105 -0
  176. Cython/Includes/libc/stdio.pxd +80 -0
  177. Cython/Includes/libc/stdlib.pxd +72 -0
  178. Cython/Includes/libc/string.pxd +50 -0
  179. Cython/Includes/libc/threads.pxd +234 -0
  180. Cython/Includes/libc/time.pxd +52 -0
  181. Cython/Includes/libcpp/__init__.pxd +4 -0
  182. Cython/Includes/libcpp/algorithm.pxd +320 -0
  183. Cython/Includes/libcpp/any.pxd +16 -0
  184. Cython/Includes/libcpp/atomic.pxd +59 -0
  185. Cython/Includes/libcpp/barrier.pxd +22 -0
  186. Cython/Includes/libcpp/bit.pxd +29 -0
  187. Cython/Includes/libcpp/cast.pxd +12 -0
  188. Cython/Includes/libcpp/cmath.pxd +518 -0
  189. Cython/Includes/libcpp/complex.pxd +106 -0
  190. Cython/Includes/libcpp/condition_variable.pxd +322 -0
  191. Cython/Includes/libcpp/deque.pxd +165 -0
  192. Cython/Includes/libcpp/exception.pxd +216 -0
  193. Cython/Includes/libcpp/execution.pxd +15 -0
  194. Cython/Includes/libcpp/forward_list.pxd +63 -0
  195. Cython/Includes/libcpp/functional.pxd +26 -0
  196. Cython/Includes/libcpp/future.pxd +103 -0
  197. Cython/Includes/libcpp/iterator.pxd +34 -0
  198. Cython/Includes/libcpp/latch.pxd +17 -0
  199. Cython/Includes/libcpp/limits.pxd +61 -0
  200. Cython/Includes/libcpp/list.pxd +117 -0
  201. Cython/Includes/libcpp/map.pxd +252 -0
  202. Cython/Includes/libcpp/memory.pxd +115 -0
  203. Cython/Includes/libcpp/mutex.pxd +387 -0
  204. Cython/Includes/libcpp/numbers.pxd +15 -0
  205. Cython/Includes/libcpp/numeric.pxd +131 -0
  206. Cython/Includes/libcpp/optional.pxd +34 -0
  207. Cython/Includes/libcpp/pair.pxd +1 -0
  208. Cython/Includes/libcpp/queue.pxd +25 -0
  209. Cython/Includes/libcpp/random.pxd +166 -0
  210. Cython/Includes/libcpp/semaphore.pxd +43 -0
  211. Cython/Includes/libcpp/set.pxd +228 -0
  212. Cython/Includes/libcpp/shared_mutex.pxd +96 -0
  213. Cython/Includes/libcpp/span.pxd +87 -0
  214. Cython/Includes/libcpp/stack.pxd +11 -0
  215. Cython/Includes/libcpp/stop_token.pxd +117 -0
  216. Cython/Includes/libcpp/string.pxd +355 -0
  217. Cython/Includes/libcpp/string_view.pxd +183 -0
  218. Cython/Includes/libcpp/typeindex.pxd +15 -0
  219. Cython/Includes/libcpp/typeinfo.pxd +10 -0
  220. Cython/Includes/libcpp/unordered_map.pxd +193 -0
  221. Cython/Includes/libcpp/unordered_set.pxd +152 -0
  222. Cython/Includes/libcpp/utility.pxd +30 -0
  223. Cython/Includes/libcpp/vector.pxd +186 -0
  224. Cython/Includes/numpy/math.pxd +150 -0
  225. Cython/Includes/openmp.pxd +50 -0
  226. Cython/Includes/posix/__init__.pxd +1 -0
  227. Cython/Includes/posix/dlfcn.pxd +14 -0
  228. Cython/Includes/posix/fcntl.pxd +86 -0
  229. Cython/Includes/posix/ioctl.pxd +4 -0
  230. Cython/Includes/posix/mman.pxd +101 -0
  231. Cython/Includes/posix/resource.pxd +57 -0
  232. Cython/Includes/posix/select.pxd +21 -0
  233. Cython/Includes/posix/signal.pxd +73 -0
  234. Cython/Includes/posix/stat.pxd +98 -0
  235. Cython/Includes/posix/stdio.pxd +37 -0
  236. Cython/Includes/posix/stdlib.pxd +29 -0
  237. Cython/Includes/posix/strings.pxd +9 -0
  238. Cython/Includes/posix/time.pxd +71 -0
  239. Cython/Includes/posix/types.pxd +30 -0
  240. Cython/Includes/posix/uio.pxd +26 -0
  241. Cython/Includes/posix/unistd.pxd +271 -0
  242. Cython/Includes/posix/wait.pxd +38 -0
  243. Cython/LZSS.cp315-win_amd64.pyd +0 -0
  244. Cython/LZSS.py +184 -0
  245. Cython/Plex/Actions.cp315-win_amd64.pyd +0 -0
  246. Cython/Plex/Actions.pxd +24 -0
  247. Cython/Plex/Actions.py +119 -0
  248. Cython/Plex/DFA.cp315-win_amd64.pyd +0 -0
  249. Cython/Plex/DFA.pxd +14 -0
  250. Cython/Plex/DFA.py +164 -0
  251. Cython/Plex/Errors.py +48 -0
  252. Cython/Plex/Lexicons.py +178 -0
  253. Cython/Plex/Machines.cp315-win_amd64.pyd +0 -0
  254. Cython/Plex/Machines.pxd +36 -0
  255. Cython/Plex/Machines.py +238 -0
  256. Cython/Plex/Regexps.py +535 -0
  257. Cython/Plex/Scanners.cp315-win_amd64.pyd +0 -0
  258. Cython/Plex/Scanners.pxd +45 -0
  259. Cython/Plex/Scanners.py +328 -0
  260. Cython/Plex/Transitions.cp315-win_amd64.pyd +0 -0
  261. Cython/Plex/Transitions.pxd +14 -0
  262. Cython/Plex/Transitions.py +239 -0
  263. Cython/Plex/__init__.py +34 -0
  264. Cython/Runtime/__init__.py +1 -0
  265. Cython/Runtime/refnanny.cp315-win_amd64.pyd +0 -0
  266. Cython/Runtime/refnanny.pyx +237 -0
  267. Cython/Shadow.py +1174 -0
  268. Cython/StringIOTree.cp315-win_amd64.pyd +0 -0
  269. Cython/StringIOTree.py +169 -0
  270. Cython/Tempita/__init__.py +4 -0
  271. Cython/Tempita/_looper.py +154 -0
  272. Cython/Tempita/_tempita.cp315-win_amd64.pyd +0 -0
  273. Cython/Tempita/_tempita.py +1087 -0
  274. Cython/TestUtils.py +472 -0
  275. Cython/Tests/TestCodeWriter.py +128 -0
  276. Cython/Tests/TestCythonUtils.py +202 -0
  277. Cython/Tests/TestJediTyper.py +223 -0
  278. Cython/Tests/TestShadow.py +125 -0
  279. Cython/Tests/TestStringIOTree.py +68 -0
  280. Cython/Tests/TestTestUtils.py +89 -0
  281. Cython/Tests/__init__.py +1 -0
  282. Cython/Tests/xmlrunner.py +390 -0
  283. Cython/Utility/AsyncGen.c +1152 -0
  284. Cython/Utility/Buffer.c +866 -0
  285. Cython/Utility/BufferFormatFromTypeInfo.pxd +2 -0
  286. Cython/Utility/Builtins.c +1068 -0
  287. Cython/Utility/CConvert.pyx +153 -0
  288. Cython/Utility/CMath.c +104 -0
  289. Cython/Utility/CommonStructures.c +244 -0
  290. Cython/Utility/Complex.c +378 -0
  291. Cython/Utility/Coroutine.c +2344 -0
  292. Cython/Utility/CpdefEnums.pyx +119 -0
  293. Cython/Utility/CppConvert.pyx +282 -0
  294. Cython/Utility/CppSupport.cpp +151 -0
  295. Cython/Utility/CythonFunction.c +2185 -0
  296. Cython/Utility/Dataclasses.c +101 -0
  297. Cython/Utility/Embed.c +129 -0
  298. Cython/Utility/Exceptions.c +1331 -0
  299. Cython/Utility/Exceptions_Cy.pyx +109 -0
  300. Cython/Utility/ExtensionTypes.c +1199 -0
  301. Cython/Utility/FunctionArguments.c +1052 -0
  302. Cython/Utility/FusedFunction.pyx +44 -0
  303. Cython/Utility/ImportExport.c +972 -0
  304. Cython/Utility/MatchCase.c +981 -0
  305. Cython/Utility/MatchCase_Cy.pyx +12 -0
  306. Cython/Utility/MemoryView.pxd +108 -0
  307. Cython/Utility/MemoryView.pyx +1499 -0
  308. Cython/Utility/MemoryView_C.c +1056 -0
  309. Cython/Utility/ModuleSetupCode.c +3319 -0
  310. Cython/Utility/NumpyImportArray.c +46 -0
  311. Cython/Utility/ObjectHandling.c +3404 -0
  312. Cython/Utility/Optimize.c +2564 -0
  313. Cython/Utility/Overflow.c +378 -0
  314. Cython/Utility/Profile.c +736 -0
  315. Cython/Utility/StringTools.c +1534 -0
  316. Cython/Utility/Synchronization.c +438 -0
  317. Cython/Utility/TString.c +369 -0
  318. Cython/Utility/TestCyUtilityLoader.pyx +8 -0
  319. Cython/Utility/TestCythonScope.pyx +75 -0
  320. Cython/Utility/TestUtilityLoader.c +12 -0
  321. Cython/Utility/TypeConversion.c +1588 -0
  322. Cython/Utility/UFuncs.pyx +50 -0
  323. Cython/Utility/UFuncs_C.c +89 -0
  324. Cython/Utility/__init__.py +28 -0
  325. Cython/Utility/arrayarray.h +172 -0
  326. Cython/Utils.cp315-win_amd64.pyd +0 -0
  327. Cython/Utils.py +680 -0
  328. Cython/__init__.py +12 -0
  329. Cython/_shared.cp315-win_amd64.pyd +0 -0
  330. Cython/py.typed +0 -0
  331. cython-3.3.0.dist-info/METADATA +555 -0
  332. cython-3.3.0.dist-info/RECORD +339 -0
  333. cython-3.3.0.dist-info/WHEEL +5 -0
  334. cython-3.3.0.dist-info/entry_points.txt +4 -0
  335. cython-3.3.0.dist-info/top_level.txt +3 -0
  336. cython.py +29 -0
  337. pyximport/__init__.py +4 -0
  338. pyximport/pyxbuild.py +160 -0
  339. pyximport/pyximport.py +482 -0
@@ -0,0 +1,4809 @@
1
+ # cython: binding=False, auto_cpdef=True, infer_types=True, py2_import=True
2
+ #
3
+ # Parser
4
+ #
5
+
6
+
7
+ # This should be done automatically
8
+ import cython
9
+ cython.declare(Nodes=object, ExprNodes=object, EncodedString=object,
10
+ bytes_literal=object, StringEncoding=object,
11
+ FileSourceDescriptor=object, lookup_unicodechar=object,
12
+ Future=object, Options=object, error=object, warning=object,
13
+ Builtin=object, ModuleNode=object, _unicode=object, _bytes=object,
14
+ re=object, _parse_escape_sequences=object, _parse_escape_sequences_raw=object,
15
+ partial=object, reduce=object,
16
+ _CDEF_MODIFIERS=tuple, COMMON_BINOP_MISTAKES=dict)
17
+
18
+ from io import StringIO
19
+ import re
20
+ from unicodedata import lookup as lookup_unicodechar
21
+ from functools import partial, reduce
22
+
23
+ from .Scanning import PyrexScanner, FileSourceDescriptor, tentatively_scan
24
+ from . import Nodes
25
+ from . import ExprNodes
26
+ from . import MatchCaseNodes
27
+ from . import Builtin
28
+ from . import StringEncoding
29
+ from .StringEncoding import EncodedString, bytes_literal
30
+ from .ModuleNode import ModuleNode
31
+ from .Errors import error, warning
32
+ from . import Future
33
+ from . import Options
34
+
35
+
36
+ _CDEF_MODIFIERS = ('inline', 'nogil', 'api')
37
+ statement_terminators = cython.declare(frozenset, frozenset((
38
+ ';', 'NEWLINE', 'EOF')))
39
+
40
+ class Ctx:
41
+ # Parsing context
42
+ level = 'other'
43
+ visibility = 'private'
44
+ cdef_flag = False
45
+ typedef_flag = False
46
+ api = False
47
+ overridable = False
48
+ nogil = False
49
+ namespace = None
50
+ templates = None
51
+ allow_struct_enum_decorator = False
52
+
53
+ def __init__(self, **kwds):
54
+ self.__dict__.update(kwds)
55
+
56
+ def __call__(self, **kwds):
57
+ ctx = Ctx()
58
+ d = ctx.__dict__
59
+ d.update(self.__dict__)
60
+ d.update(kwds)
61
+ return ctx
62
+
63
+
64
+ @cython.cfunc
65
+ def p_ident(s: PyrexScanner, message="Expected an identifier"):
66
+ if s.sy == 'IDENT':
67
+ name = s.context.intern_ustring(s.systring)
68
+ s.next()
69
+ return name
70
+ else:
71
+ s.error(message)
72
+
73
+
74
+ @cython.cfunc
75
+ def p_ident_list(s: PyrexScanner) -> list:
76
+ names = []
77
+ while s.sy == 'IDENT':
78
+ names.append(s.context.intern_ustring(s.systring))
79
+ s.next()
80
+ if s.sy != ',':
81
+ break
82
+ s.next()
83
+ return names
84
+
85
+ #------------------------------------------
86
+ #
87
+ # Expressions
88
+ #
89
+ #------------------------------------------
90
+
91
+ @cython.cfunc
92
+ def p_binop_operator(s: PyrexScanner) -> tuple[str, object]:
93
+ pos = s.position()
94
+ op = s.sy
95
+ s.next()
96
+ return op, pos
97
+
98
+
99
+ # signature is currently overridden in pxd file
100
+ def p_binop_expr(s: PyrexScanner, ops, p_sub_expr):
101
+ n1 = p_sub_expr(s)
102
+ while s.sy in ops:
103
+ op, pos = p_binop_operator(s)
104
+ n2 = p_sub_expr(s)
105
+ n1 = ExprNodes.binop_node(pos, op, n1, n2)
106
+ if op == '/':
107
+ if Future.division in s.context.future_directives:
108
+ n1.truedivision = True
109
+ else:
110
+ n1.truedivision = None # unknown
111
+ return n1
112
+
113
+
114
+ #lambdef: 'lambda' [varargslist] ':' test
115
+
116
+ @cython.cfunc
117
+ def p_lambdef(s: PyrexScanner):
118
+ # s.sy == 'lambda'
119
+ pos = s.position()
120
+ s.next()
121
+ if s.sy == ':':
122
+ args = []
123
+ star_arg = starstar_arg = None
124
+ else:
125
+ args, star_arg, starstar_arg = p_varargslist(
126
+ s, terminator=':', annotated=False)
127
+ s.expect(':')
128
+ expr = p_test(s)
129
+ return ExprNodes.LambdaNode(
130
+ pos, args = args,
131
+ star_arg = star_arg, starstar_arg = starstar_arg,
132
+ result_expr = expr)
133
+
134
+
135
+ #test: or_test ['if' or_test 'else' test] | lambdef
136
+
137
+ @cython.cfunc
138
+ def p_test(s: PyrexScanner):
139
+ # The check for a following ':=' is only for error reporting purposes.
140
+ # It simply changes a
141
+ # expected ')', found ':='
142
+ # message into something a bit more descriptive.
143
+ # It is close to what the PEG parser does in CPython, where an expression has
144
+ # a lookahead assertion that it isn't followed by ':='
145
+ expr = p_test_allow_walrus_after(s)
146
+ if s.sy == ':=':
147
+ s.error("invalid syntax: assignment expression not allowed in this context")
148
+ return expr
149
+
150
+
151
+ @cython.cfunc
152
+ def p_test_allow_walrus_after(s: PyrexScanner):
153
+ if s.sy == 'lambda':
154
+ return p_lambdef(s)
155
+ pos = s.position()
156
+ expr = p_or_test(s)
157
+ if s.sy == 'if':
158
+ s.next()
159
+ test = p_or_test(s)
160
+ s.expect('else')
161
+ other = p_test(s)
162
+ return ExprNodes.CondExprNode(pos, condition=test, true_val=expr, false_val=other)
163
+ else:
164
+ return expr
165
+
166
+
167
+ @cython.cfunc
168
+ def p_namedexpr_test(s: PyrexScanner):
169
+ # defined in the LL parser as
170
+ # namedexpr_test: test [':=' test]
171
+ # The requirement that the LHS is a name is not enforced in the grammar.
172
+ # For comparison the PEG parser does:
173
+ # 1. look for "name :=", if found it's definitely a named expression
174
+ # so look for expression
175
+ # 2. Otherwise, look for expression
176
+ lhs = p_test_allow_walrus_after(s)
177
+ if s.sy == ':=':
178
+ position = s.position()
179
+ if not lhs.is_name:
180
+ s.error("Left-hand side of assignment expression must be an identifier", fatal=False)
181
+ s.next()
182
+ rhs = p_test(s)
183
+ return ExprNodes.AssignmentExpressionNode(position, lhs=lhs, rhs=rhs)
184
+ return lhs
185
+
186
+
187
+ #or_test: and_test ('or' and_test)*
188
+
189
+ COMMON_BINOP_MISTAKES = {'||': 'or', '&&': 'and'}
190
+
191
+ @cython.cfunc
192
+ def p_or_test(s: PyrexScanner):
193
+ return p_rassoc_binop_expr(s, 'or', p_and_test)
194
+
195
+
196
+ # signature is currently overridden in pxd file
197
+ def p_rassoc_binop_expr(s: PyrexScanner, op, p_subexpr):
198
+ n1 = p_subexpr(s)
199
+ if s.sy == op:
200
+ pos = s.position()
201
+ op = s.sy
202
+ s.next()
203
+ n2 = p_rassoc_binop_expr(s, op, p_subexpr)
204
+ n1 = ExprNodes.binop_node(pos, op, n1, n2)
205
+ elif s.sy in COMMON_BINOP_MISTAKES and COMMON_BINOP_MISTAKES[s.sy] == op:
206
+ # Only report this for the current operator since we pass through here twice for 'and' and 'or'.
207
+ warning(s.position(),
208
+ "Found the C operator '%s', did you mean the Python operator '%s'?" % (s.sy, op),
209
+ level=1)
210
+ return n1
211
+
212
+
213
+ #and_test: not_test ('and' not_test)*
214
+
215
+ @cython.cfunc
216
+ def p_and_test(s: PyrexScanner):
217
+ #return p_binop_expr(s, ('and',), p_not_test)
218
+ return p_rassoc_binop_expr(s, 'and', p_not_test)
219
+
220
+
221
+ #not_test: 'not' not_test | comparison
222
+
223
+ @cython.cfunc
224
+ def p_not_test(s: PyrexScanner):
225
+ if s.sy == 'not':
226
+ pos = s.position()
227
+ s.next()
228
+ return ExprNodes.NotNode(pos, operand = p_not_test(s))
229
+ else:
230
+ return p_comparison(s)
231
+
232
+
233
+ #comparison: expr (comp_op expr)*
234
+ #comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
235
+
236
+ @cython.cfunc
237
+ def p_comparison(s: PyrexScanner):
238
+ n1 = p_starred_expr(s)
239
+ if s.sy in comparison_ops:
240
+ pos = s.position()
241
+ op = p_cmp_op(s)
242
+ n2 = p_starred_expr(s)
243
+ n1 = ExprNodes.PrimaryCmpNode(pos,
244
+ operator = op, operand1 = n1, operand2 = n2)
245
+ if s.sy in comparison_ops:
246
+ n1.cascade = p_cascaded_cmp(s)
247
+ return n1
248
+
249
+
250
+ @cython.cfunc
251
+ def p_test_or_starred_expr(s: PyrexScanner):
252
+ if s.sy == '*':
253
+ return p_starred_expr(s)
254
+ else:
255
+ return p_test(s)
256
+
257
+
258
+ @cython.cfunc
259
+ def p_namedexpr_test_or_starred_expr(s: PyrexScanner):
260
+ if s.sy == '*':
261
+ return p_starred_expr(s)
262
+ else:
263
+ return p_namedexpr_test(s)
264
+
265
+
266
+ @cython.cfunc
267
+ def p_starred_expr(s: PyrexScanner):
268
+ pos = s.position()
269
+ if s.sy == '*':
270
+ starred = True
271
+ s.next()
272
+ else:
273
+ starred = False
274
+ expr = p_bit_expr(s)
275
+ if starred:
276
+ expr = ExprNodes.StarredUnpackingNode(pos, expr)
277
+ return expr
278
+
279
+
280
+ @cython.cfunc
281
+ def p_cascaded_cmp(s: PyrexScanner):
282
+ pos = s.position()
283
+ op = p_cmp_op(s)
284
+ n2 = p_starred_expr(s)
285
+ result = ExprNodes.CascadedCmpNode(pos,
286
+ operator = op, operand2 = n2)
287
+ if s.sy in comparison_ops:
288
+ result.cascade = p_cascaded_cmp(s)
289
+ return result
290
+
291
+
292
+ @cython.cfunc
293
+ def p_cmp_op(s: PyrexScanner):
294
+ if s.sy == 'not':
295
+ s.next()
296
+ s.expect('in')
297
+ op = 'not_in'
298
+ elif s.sy == 'is':
299
+ s.next()
300
+ if s.sy == 'not':
301
+ s.next()
302
+ op = 'is_not'
303
+ else:
304
+ op = 'is'
305
+ else:
306
+ op = s.sy
307
+ s.next()
308
+ if op == '<>':
309
+ op = '!='
310
+ return op
311
+
312
+
313
+ comparison_ops = cython.declare(frozenset, frozenset((
314
+ '<', '>', '==', '>=', '<=', '<>', '!=',
315
+ 'in', 'is', 'not'
316
+ )))
317
+
318
+
319
+ #expr: xor_expr ('|' xor_expr)*
320
+
321
+ @cython.cfunc
322
+ def p_bit_expr(s: PyrexScanner):
323
+ return p_binop_expr(s, ('|',), p_xor_expr)
324
+
325
+
326
+ #xor_expr: and_expr ('^' and_expr)*
327
+
328
+ @cython.cfunc
329
+ def p_xor_expr(s: PyrexScanner):
330
+ return p_binop_expr(s, ('^',), p_and_expr)
331
+
332
+
333
+ #and_expr: shift_expr ('&' shift_expr)*
334
+
335
+ @cython.cfunc
336
+ def p_and_expr(s: PyrexScanner):
337
+ return p_binop_expr(s, ('&',), p_shift_expr)
338
+
339
+
340
+ #shift_expr: arith_expr (('<<'|'>>') arith_expr)*
341
+
342
+ @cython.cfunc
343
+ def p_shift_expr(s: PyrexScanner):
344
+ return p_binop_expr(s, ('<<', '>>'), p_arith_expr)
345
+
346
+
347
+ #arith_expr: term (('+'|'-') term)*
348
+
349
+ @cython.cfunc
350
+ def p_arith_expr(s: PyrexScanner):
351
+ return p_binop_expr(s, ('+', '-'), p_term)
352
+
353
+
354
+ #term: factor (('*'|'@'|'/'|'%'|'//') factor)*
355
+
356
+ @cython.cfunc
357
+ def p_term(s: PyrexScanner):
358
+ return p_binop_expr(s, ('*', '@', '/', '%', '//'), p_factor)
359
+
360
+
361
+ #factor: ('+'|'-'|'~'|'&'|typecast|sizeof) factor | power
362
+
363
+ @cython.cfunc
364
+ def p_factor(s: PyrexScanner):
365
+ # little indirection for C-ification purposes
366
+ return _p_factor(s)
367
+
368
+
369
+ @cython.cfunc
370
+ def _p_factor(s: PyrexScanner):
371
+ sy = s.sy
372
+ if sy in ('+', '-', '~'):
373
+ op = s.sy
374
+ pos = s.position()
375
+ s.next()
376
+ return ExprNodes.unop_node(pos, op, p_factor(s))
377
+ elif not s.in_python_file:
378
+ if sy == '&':
379
+ pos = s.position()
380
+ s.next()
381
+ arg = p_factor(s)
382
+ return ExprNodes.AmpersandNode(pos, operand = arg)
383
+ elif sy == "<":
384
+ return p_typecast(s)
385
+ elif sy == 'IDENT' and s.systring == "sizeof":
386
+ return p_sizeof(s)
387
+ return p_power(s)
388
+
389
+
390
+ @cython.cfunc
391
+ def p_typecast(s: PyrexScanner):
392
+ # s.sy == "<"
393
+ pos = s.position()
394
+ s.next()
395
+ base_type = p_c_base_type(s)
396
+ is_memslice = isinstance(base_type, Nodes.MemoryViewSliceTypeNode)
397
+ is_other_unnamed_type = isinstance(base_type, (
398
+ Nodes.TemplatedTypeNode,
399
+ Nodes.CQualifierTypeNode,
400
+ Nodes.CTupleBaseTypeNode,
401
+ ))
402
+ if not (is_memslice or is_other_unnamed_type) and base_type.name is None:
403
+ s.error("Unknown type")
404
+ declarator = p_c_declarator(s, empty=True)
405
+ if s.sy == '?':
406
+ s.next()
407
+ typecheck = True
408
+ else:
409
+ typecheck = False
410
+ s.expect(">")
411
+ operand = p_factor(s)
412
+ if is_memslice:
413
+ return ExprNodes.CythonArrayNode(pos, base_type_node=base_type, operand=operand)
414
+
415
+ return ExprNodes.TypecastNode(pos,
416
+ base_type = base_type,
417
+ declarator = declarator,
418
+ operand = operand,
419
+ typecheck = typecheck)
420
+
421
+
422
+ @cython.cfunc
423
+ def p_sizeof(s: PyrexScanner):
424
+ # s.sy == ident "sizeof"
425
+ pos = s.position()
426
+ s.next()
427
+ s.expect('(')
428
+ # Here we decide if we are looking at an expression or type
429
+ # If it is actually a type, but parsable as an expression,
430
+ # we treat it as an expression here.
431
+ if looking_at_expr(s):
432
+ operand = p_test(s)
433
+ node = ExprNodes.SizeofVarNode(pos, operand = operand)
434
+ else:
435
+ base_type = p_c_base_type(s)
436
+ declarator = p_c_declarator(s, empty=True)
437
+ node = ExprNodes.SizeofTypeNode(pos,
438
+ base_type = base_type, declarator = declarator)
439
+ s.expect(')')
440
+ return node
441
+
442
+
443
+ @cython.cfunc
444
+ def p_yield_expression(s: PyrexScanner, statement_terminators: frozenset = statement_terminators):
445
+ # s.sy == "yield"
446
+ pos = s.position()
447
+ s.next()
448
+ is_yield_from = False
449
+ if s.sy == 'from':
450
+ is_yield_from = True
451
+ s.next()
452
+ if s.sy != ')' and s.sy not in statement_terminators:
453
+ # "yield from" does not support implicit tuples, but "yield" does ("yield 1,2")
454
+ arg = p_test(s) if is_yield_from else p_testlist(s)
455
+ else:
456
+ if is_yield_from:
457
+ s.error("'yield from' requires a source argument",
458
+ pos=pos, fatal=False)
459
+ arg = None
460
+ if is_yield_from:
461
+ return ExprNodes.YieldFromExprNode(pos, arg=arg)
462
+ else:
463
+ return ExprNodes.YieldExprNode(pos, arg=arg)
464
+
465
+
466
+ @cython.cfunc
467
+ def p_yield_statement(s: PyrexScanner):
468
+ # s.sy == "yield"
469
+ yield_expr = p_yield_expression(s)
470
+ return Nodes.ExprStatNode(yield_expr.pos, expr=yield_expr)
471
+
472
+
473
+ @cython.cfunc
474
+ def p_async_statement(s: PyrexScanner, ctx, decorators):
475
+ # s.sy >> 'async' ...
476
+ if s.sy == 'def':
477
+ # 'async def' statements aren't allowed in pxd files
478
+ if 'pxd' in ctx.level:
479
+ s.error('def statement not allowed here')
480
+ s.level = ctx.level
481
+ return p_def_statement(s, decorators, is_async_def=True)
482
+ elif decorators:
483
+ s.error("Decorators can only be followed by functions or classes")
484
+ elif s.sy == 'for':
485
+ return p_for_statement(s, is_async=True)
486
+ elif s.sy == 'with':
487
+ s.next()
488
+ return p_with_items(s, is_async=True)
489
+ else:
490
+ s.error("expected one of 'def', 'for', 'with' after 'async'")
491
+
492
+
493
+ #power: atom_expr ('**' factor)*
494
+ #atom_expr: ['await'] atom trailer*
495
+
496
+ @cython.cfunc
497
+ def p_power(s: PyrexScanner):
498
+ if s.systring == 'new' and s.peek()[0] == 'IDENT':
499
+ return p_new_expr(s)
500
+ await_pos = None
501
+ if s.sy == 'await':
502
+ await_pos = s.position()
503
+ s.next()
504
+ n1 = p_atom(s)
505
+ while s.sy in ('(', '[', '.'):
506
+ n1 = p_trailer(s, n1)
507
+ if await_pos:
508
+ n1 = ExprNodes.AwaitExprNode(await_pos, arg=n1)
509
+ if s.sy == '**':
510
+ pos = s.position()
511
+ s.next()
512
+ n2 = p_factor(s)
513
+ n1 = ExprNodes.binop_node(pos, '**', n1, n2)
514
+ return n1
515
+
516
+
517
+ @cython.cfunc
518
+ def p_new_expr(s: PyrexScanner):
519
+ # s.systring == 'new'.
520
+ pos = s.position()
521
+ s.next()
522
+ cppclass = p_c_base_type(s)
523
+ return p_call(s, ExprNodes.NewExprNode(pos, cppclass = cppclass))
524
+
525
+
526
+ #trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
527
+
528
+ @cython.cfunc
529
+ def p_trailer(s: PyrexScanner, node1):
530
+ pos = s.position()
531
+ if s.sy == '(':
532
+ return p_call(s, node1)
533
+ elif s.sy == '[':
534
+ return p_index(s, node1)
535
+ else: # s.sy == '.'
536
+ s.next()
537
+ name = p_ident(s)
538
+ return ExprNodes.AttributeNode(pos,
539
+ obj=node1, attribute=name)
540
+
541
+
542
+ # arglist: argument (',' argument)* [',']
543
+ # argument: [test '='] test # Really [keyword '='] test
544
+
545
+ # since PEP 448:
546
+ # argument: ( test [comp_for] |
547
+ # test '=' test |
548
+ # '**' expr |
549
+ # star_expr )
550
+
551
+ @cython.cfunc
552
+ def p_call_parse_args(s: PyrexScanner, allow_genexp: cython.bint = True) -> tuple[list, list]:
553
+ # s.sy == '('
554
+ s.next()
555
+ positional_args = []
556
+ keyword_args = []
557
+ starstar_seen = False
558
+ last_was_tuple_unpack = False
559
+ while s.sy != ')':
560
+ if s.sy == '*':
561
+ if starstar_seen:
562
+ s.error("Non-keyword arg following keyword arg")
563
+ s.next()
564
+ positional_args.append(p_test(s))
565
+ last_was_tuple_unpack = True
566
+ elif s.sy == '**':
567
+ s.next()
568
+ keyword_args.append(p_test(s))
569
+ starstar_seen = True
570
+ else:
571
+ arg = p_namedexpr_test(s)
572
+ if s.sy == '=':
573
+ s.next()
574
+ if not arg.is_name:
575
+ s.error("Expected an identifier before '='",
576
+ pos=arg.pos)
577
+ encoded_name = s.context.intern_ustring(arg.name)
578
+ keyword = ExprNodes.IdentifierStringNode(
579
+ arg.pos, value=encoded_name)
580
+ arg = p_test(s)
581
+ keyword_args.append((keyword, arg))
582
+ else:
583
+ if keyword_args:
584
+ s.error("Non-keyword arg following keyword arg", pos=arg.pos)
585
+ if positional_args and not last_was_tuple_unpack:
586
+ positional_args[-1].append(arg)
587
+ else:
588
+ positional_args.append([arg])
589
+ last_was_tuple_unpack = False
590
+ if s.sy != ',':
591
+ break
592
+ s.next()
593
+
594
+ if s.sy in ('for', 'async') and allow_genexp:
595
+ if not keyword_args and not last_was_tuple_unpack:
596
+ if len(positional_args) == 1 and len(positional_args[0]) == 1:
597
+ positional_args = [[p_genexp(s, positional_args[0][0])]]
598
+ s.expect(')')
599
+ return positional_args or [[]], keyword_args
600
+
601
+
602
+ @cython.cfunc
603
+ def p_call_build_packed_args(pos, positional_args: list, keyword_args: list) -> tuple:
604
+ keyword_dict = None
605
+
606
+ subtuples = [
607
+ ExprNodes.TupleNode(pos, args=arg) if isinstance(arg, list) else ExprNodes.AsTupleNode(pos, arg=arg)
608
+ for arg in positional_args
609
+ ]
610
+ # TODO: implement a faster way to join tuples than creating each one and adding them
611
+ arg_tuple = reduce(partial(ExprNodes.binop_node, pos, '+'), subtuples)
612
+
613
+ if keyword_args:
614
+ kwargs = []
615
+ dict_items = []
616
+ for item in keyword_args:
617
+ if isinstance(item, tuple):
618
+ key, value = item
619
+ dict_items.append(ExprNodes.DictItemNode(pos=key.pos, key=key, value=value))
620
+ elif item.is_dict_literal:
621
+ # unpack "**{a:b}" directly
622
+ dict_items.extend(item.key_value_pairs)
623
+ else:
624
+ if dict_items:
625
+ kwargs.append(ExprNodes.DictNode(
626
+ dict_items[0].pos, key_value_pairs=dict_items, reject_duplicates=True))
627
+ dict_items = []
628
+ kwargs.append(item)
629
+
630
+ if dict_items:
631
+ kwargs.append(ExprNodes.DictNode(
632
+ dict_items[0].pos, key_value_pairs=dict_items, reject_duplicates=True))
633
+
634
+ if kwargs:
635
+ if len(kwargs) == 1 and kwargs[0].is_dict_literal:
636
+ # only simple keyword arguments found -> one dict
637
+ keyword_dict = kwargs[0]
638
+ else:
639
+ # at least one **kwargs
640
+ keyword_dict = ExprNodes.MergedDictNode(pos, keyword_args=kwargs)
641
+
642
+ return arg_tuple, keyword_dict
643
+
644
+
645
+ @cython.cfunc
646
+ def p_call(s: PyrexScanner, function):
647
+ # s.sy == '('
648
+ pos = s.position()
649
+ positional_args, keyword_args = p_call_parse_args(s)
650
+
651
+ if not keyword_args and len(positional_args) == 1 and isinstance(positional_args[0], list):
652
+ return ExprNodes.SimpleCallNode(pos, function=function, args=positional_args[0])
653
+ else:
654
+ arg_tuple, keyword_dict = p_call_build_packed_args(pos, positional_args, keyword_args)
655
+ return ExprNodes.GeneralCallNode(
656
+ pos, function=function, positional_args=arg_tuple, keyword_args=keyword_dict)
657
+
658
+
659
+ #lambdef: 'lambda' [varargslist] ':' test
660
+
661
+ #subscriptlist: subscript (',' subscript)* [',']
662
+
663
+ @cython.cfunc
664
+ def p_index(s: PyrexScanner, base):
665
+ # s.sy == '['
666
+ pos = s.position()
667
+ s.next()
668
+ subscripts, is_single_value = p_subscript_list(s)
669
+ if is_single_value and len(subscripts[0]) == 2:
670
+ start, stop = subscripts[0]
671
+ result = ExprNodes.SliceIndexNode(pos,
672
+ base = base, start = start, stop = stop)
673
+ else:
674
+ indexes = make_slice_nodes(pos, subscripts)
675
+ if is_single_value:
676
+ index = indexes[0]
677
+ else:
678
+ index = ExprNodes.TupleNode(pos, args = indexes)
679
+ result = ExprNodes.IndexNode(pos,
680
+ base = base, index = index)
681
+ s.expect(']')
682
+ return result
683
+
684
+
685
+ @cython.cfunc
686
+ def p_subscript_list(s: PyrexScanner) -> tuple[list[list], cython.bint]:
687
+ is_single_value = True
688
+ items = [p_subscript(s)]
689
+ while s.sy == ',':
690
+ is_single_value = False
691
+ s.next()
692
+ if s.sy == ']':
693
+ break
694
+ items.append(p_subscript(s))
695
+ return items, is_single_value
696
+
697
+
698
+ #subscript: '.' '.' '.' | test | [test] ':' [test] [':' [test]]
699
+
700
+ @cython.cfunc
701
+ def p_subscript(s: PyrexScanner) -> list:
702
+ # Parse a subscript and return a list of
703
+ # 1, 2 or 3 ExprNodes, depending on how
704
+ # many slice elements were encountered.
705
+ start = p_slice_element(s, (':',))
706
+ if s.sy != ':':
707
+ return [start]
708
+ s.next()
709
+ stop = p_slice_element(s, (':', ',', ']'))
710
+ if s.sy != ':':
711
+ return [start, stop]
712
+ s.next()
713
+ step = p_slice_element(s, (':', ',', ']'))
714
+ return [start, stop, step]
715
+
716
+
717
+ @cython.cfunc
718
+ def p_slice_element(s: PyrexScanner, follow_set):
719
+ # Simple expression which may be missing iff
720
+ # it is followed by something in follow_set.
721
+ if s.sy not in follow_set:
722
+ return p_test(s)
723
+ else:
724
+ return None
725
+
726
+
727
+ @cython.cfunc
728
+ def expect_ellipsis(s: PyrexScanner):
729
+ s.expect('...')
730
+
731
+
732
+ @cython.cfunc
733
+ def make_slice_nodes(pos, subscripts) -> list:
734
+ # Convert a list of subscripts as returned
735
+ # by p_subscript_list into a list of ExprNodes,
736
+ # creating SliceNodes for elements with 2 or
737
+ # more components.
738
+ result = []
739
+ for subscript in subscripts:
740
+ if len(subscript) == 1:
741
+ result.append(subscript[0])
742
+ else:
743
+ result.append(make_slice_node(pos, *subscript))
744
+ return result
745
+
746
+
747
+ @cython.ccall
748
+ def make_slice_node(pos, start, stop = None, step = None):
749
+ if not start:
750
+ start = ExprNodes.NoneNode(pos)
751
+ if not stop:
752
+ stop = ExprNodes.NoneNode(pos)
753
+ if not step:
754
+ step = ExprNodes.NoneNode(pos)
755
+ return ExprNodes.SliceNode(pos,
756
+ start = start, stop = stop, step = step)
757
+
758
+
759
+ #atom: '(' [yield_expr|testlist_comp] ')' | '[' [listmaker] ']' | '{' [dict_or_set_maker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
760
+
761
+ @cython.cfunc
762
+ def p_atom(s: PyrexScanner):
763
+ pos = s.position()
764
+ sy = s.sy
765
+ if sy == '(':
766
+ s.next()
767
+ if s.sy == ')':
768
+ result = ExprNodes.TupleNode(pos, args = [])
769
+ elif s.sy == 'yield':
770
+ result = p_yield_expression(s)
771
+ else:
772
+ result = p_testlist_comp(s)
773
+ s.expect(')')
774
+ return result
775
+ elif sy == '[':
776
+ return p_list_maker(s)
777
+ elif sy == '{':
778
+ return p_dict_or_set_maker(s)
779
+ elif sy == '`':
780
+ return p_backquote_expr(s)
781
+ elif sy == '...':
782
+ expect_ellipsis(s)
783
+ return ExprNodes.EllipsisNode(pos)
784
+ elif sy == 'INT':
785
+ return p_int_literal(s)
786
+ elif sy == 'FLOAT':
787
+ value = s.systring
788
+ s.next()
789
+ return ExprNodes.FloatNode(pos, value = value)
790
+ elif sy == 'IMAG':
791
+ value = s.systring[:-1]
792
+ s.next()
793
+ return ExprNodes.ImagNode(pos, value = value)
794
+ elif sy == 'BEGIN_STRING' or sy == 'BEGIN_FT_STRING':
795
+ return p_atom_string(s)
796
+ elif sy == 'IDENT':
797
+ result = p_atom_ident_constants(s)
798
+ if result is None:
799
+ result = p_name(s, s.systring)
800
+ s.next()
801
+ return result
802
+ else:
803
+ s.error("Expected an identifier or literal")
804
+
805
+
806
+ @cython.cfunc
807
+ def p_atom_string(s: PyrexScanner):
808
+ # s.sy == 'BEGIN_STRING' or s.sy == 'BEGIN_FT_STRING'
809
+ pos = s.position()
810
+ kind, bytes_value, unicode_value = p_cat_string_literal(s)
811
+ if not kind:
812
+ return ExprNodes.UnicodeNode(pos, value=unicode_value, bytes_value=bytes_value)
813
+ kind_char: cython.Py_UCS4 = kind
814
+ if kind_char == 'c':
815
+ return ExprNodes.CharNode(pos, value=bytes_value)
816
+ elif kind_char == 'u':
817
+ return ExprNodes.UnicodeNode(pos, value=unicode_value, bytes_value=bytes_value)
818
+ elif kind_char == 'b':
819
+ return ExprNodes.BytesNode(pos, value=bytes_value)
820
+ elif kind_char == 'f':
821
+ return ExprNodes.JoinedStrNode(pos, values=unicode_value)
822
+ elif kind_char == 't':
823
+ # TODO
824
+ return ExprNodes.TemplateStringNode(pos, values=unicode_value)
825
+ else:
826
+ # This is actually prevented by the scanner (Lexicon.py).
827
+ s.error(f"invalid string kind '{kind}'")
828
+
829
+
830
+ @cython.cfunc
831
+ def p_atom_ident_constants(s: PyrexScanner):
832
+ """
833
+ Returns None if it isn't a special-cased named constant.
834
+ Only calls s.next() if it successfully matches a named constant.
835
+ """
836
+ # s.sy == 'IDENT'
837
+ pos = s.position()
838
+ name = s.systring
839
+ result = None
840
+ if name == "None":
841
+ result = ExprNodes.NoneNode(pos)
842
+ elif name == "True":
843
+ result = ExprNodes.BoolNode(pos, value=True)
844
+ elif name == "False":
845
+ result = ExprNodes.BoolNode(pos, value=False)
846
+ elif name == "NULL" and not s.in_python_file:
847
+ result = ExprNodes.NullNode(pos)
848
+ else:
849
+ return None
850
+ s.next()
851
+ return result
852
+
853
+
854
+ @cython.cfunc
855
+ def p_int_literal(s: PyrexScanner):
856
+ pos = s.position()
857
+ value: str = cython.cast(str, s.systring)
858
+ s.next()
859
+ unsigned = ""
860
+ longness = ""
861
+ while value[-1] in "UuLl":
862
+ if value[-1] in "Ll":
863
+ longness += "L"
864
+ else:
865
+ unsigned += "U"
866
+ value = value[:-1]
867
+ # '3L' is ambiguous in Py2 but not in Py3. '3U' and '3LL' are
868
+ # illegal in Py2 Python files. All suffixes are illegal in Py3
869
+ # Python files.
870
+ is_c_literal = None
871
+ if unsigned:
872
+ is_c_literal = True
873
+ elif longness:
874
+ if longness == 'LL' or s.context.language_level >= 3:
875
+ is_c_literal = True
876
+ if s.in_python_file:
877
+ if is_c_literal:
878
+ error(pos, "illegal integer literal syntax in Python source file")
879
+ is_c_literal = False
880
+ return ExprNodes.IntNode(pos,
881
+ is_c_literal = is_c_literal,
882
+ value = value,
883
+ unsigned = unsigned,
884
+ longness = longness)
885
+
886
+
887
+ @cython.cfunc
888
+ def p_name(s: PyrexScanner, name):
889
+ pos = s.position()
890
+ if not s.compile_time_expr and name in s.compile_time_env:
891
+ value = s.compile_time_env.lookup_here(name)
892
+ node = wrap_compile_time_constant(pos, value)
893
+ if node is not None:
894
+ return node
895
+ return ExprNodes.NameNode(pos, name=name)
896
+
897
+
898
+ @cython.cfunc
899
+ def wrap_compile_time_constant(pos, value):
900
+ if value is None:
901
+ return ExprNodes.NoneNode(pos)
902
+ elif value is Ellipsis:
903
+ return ExprNodes.EllipsisNode(pos)
904
+ elif isinstance(value, bool):
905
+ return ExprNodes.BoolNode(pos, value=value)
906
+ elif isinstance(value, int):
907
+ return ExprNodes.IntNode(pos, value=repr(value), constant_result=value)
908
+ elif isinstance(value, float):
909
+ return ExprNodes.FloatNode(pos, value=repr(value), constant_result=value)
910
+ elif isinstance(value, complex):
911
+ node = ExprNodes.ImagNode(pos, value=repr(value.imag), constant_result=complex(0.0, value.imag))
912
+ if value.real:
913
+ # FIXME: should we care about -0.0 ?
914
+ # probably not worth using the '-' operator for negative imag values
915
+ node = ExprNodes.binop_node(
916
+ pos, '+', ExprNodes.FloatNode(pos, value=repr(value.real), constant_result=value.real), node,
917
+ constant_result=value)
918
+ return node
919
+ elif isinstance(value, str):
920
+ return ExprNodes.UnicodeNode(pos, value=EncodedString(value))
921
+ elif isinstance(value, bytes):
922
+ bvalue = bytes_literal(value, 'ascii') # actually: unknown encoding, but BytesLiteral requires one
923
+ return ExprNodes.BytesNode(pos, value=bvalue, constant_result=value)
924
+ elif isinstance(value, tuple):
925
+ args = [wrap_compile_time_constant(pos, arg) for arg in value]
926
+ if None in args:
927
+ # error already reported
928
+ return None
929
+ return ExprNodes.TupleNode(pos, args=args)
930
+
931
+ error(pos, "Invalid type for compile-time constant: %r (type %s)"
932
+ % (value, value.__class__.__name__))
933
+ return None
934
+
935
+
936
+ @cython.cfunc
937
+ def p_cat_string_literal(s: PyrexScanner) -> tuple[str, object, object]:
938
+ # A sequence of one or more adjacent string literals.
939
+ # Returns (kind, bytes_value, unicode_value)
940
+ # where kind in ('b', 'c', 'u', 'f', 't', '')
941
+ pos = s.position()
942
+ kind, bytes_value, unicode_value = p_string_literal(s)
943
+ if kind == 'c' or (s.sy != 'BEGIN_STRING' and s.sy != 'BEGIN_FT_STRING'):
944
+ return kind, bytes_value, unicode_value
945
+ bstrings, ustrings, positions = [bytes_value], [unicode_value], [pos]
946
+ bytes_value = unicode_value = None
947
+ while s.sy == 'BEGIN_STRING' or s.sy == 'BEGIN_FT_STRING':
948
+ pos = s.position()
949
+ next_kind, next_bytes_value, next_unicode_value = p_string_literal(s)
950
+ if next_kind == 'c':
951
+ error(pos, "Cannot concatenate char literal with another string or char literal")
952
+ continue
953
+ elif next_kind != kind:
954
+ # concatenating f strings and normal strings is allowed and leads to an f string
955
+ if {kind, next_kind} in ({'f', 'u'}, {'f', ''}):
956
+ kind = 'f'
957
+ elif kind == 't' or next_kind == 't':
958
+ error(pos, "cannot mix t-string literals with string or bytes literals")
959
+ continue
960
+ else:
961
+ error(pos, "Cannot mix string literals of different types, expected %s'', got %s''" % (
962
+ kind, next_kind))
963
+ continue
964
+ bstrings.append(next_bytes_value)
965
+ ustrings.append(next_unicode_value)
966
+ positions.append(pos)
967
+ # join and rewrap the partial literals
968
+ if kind in ('b', 'c', '') or kind == 'u' and None not in bstrings:
969
+ # Py3 enforced unicode literals are parsed as bytes/unicode combination
970
+ bytes_value = bytes_literal(b''.join(bstrings), s.source_encoding)
971
+ if kind in ('u', ''):
972
+ unicode_value = EncodedString(''.join([u for u in ustrings if u is not None]))
973
+ if kind == 'f':
974
+ unicode_value = []
975
+ for u, pos in zip(ustrings, positions):
976
+ if isinstance(u, list):
977
+ unicode_value += u
978
+ else:
979
+ # non-f-string concatenated into the f-string
980
+ unicode_value.append(ExprNodes.UnicodeNode(pos, value=EncodedString(u)))
981
+ if kind == 't':
982
+ unicode_value = []
983
+ for u in ustrings:
984
+ unicode_value.extend(u)
985
+ return kind, bytes_value, unicode_value
986
+
987
+
988
+ @cython.cfunc
989
+ def p_opt_string_literal(s: PyrexScanner, required_type: str = 'u'):
990
+ if s.sy != 'BEGIN_STRING':
991
+ return None
992
+ pos = s.position()
993
+ kind, bytes_value, unicode_value = p_string_literal(s, required_type)
994
+ if required_type == 'u':
995
+ if kind == 'f':
996
+ s.error("f-string not allowed here", pos)
997
+ return unicode_value
998
+ elif required_type == 'b':
999
+ return bytes_value
1000
+ else:
1001
+ s.error("internal parser configuration error")
1002
+
1003
+
1004
+ @cython.cfunc
1005
+ def check_for_non_ascii_characters(string) -> cython.bint:
1006
+ s = cython.cast(str, string) # EncodedString
1007
+ for c in s:
1008
+ if c >= '\x80':
1009
+ return True
1010
+ return False
1011
+
1012
+
1013
+ @cython.cfunc
1014
+ def p_string_literal_shared_read(
1015
+ s: PyrexScanner, pos, chars, kind: str,
1016
+ is_raw: cython.bint):
1017
+ """
1018
+ Returns a string of non-escaped characters (if handled) or none.
1019
+ If passed an escape sequence returns an empty string.
1020
+ """
1021
+ sy = s.sy
1022
+ systr = s.systring
1023
+ result = systr
1024
+ is_python3_source: cython.bint = s.context.language_level >= 3
1025
+ # print "p_string_literal: sy =", sy, repr(s.systring) ###
1026
+ if sy == 'CHARS':
1027
+ chars.append(systr)
1028
+ elif sy == 'ESCAPE':
1029
+ # in Py2, 'ur' raw unicode strings resolve unicode escapes but nothing else
1030
+ if is_raw and (is_python3_source or kind != 'u' or len(systr) < 2 or systr[1] not in 'Uu'):
1031
+ chars.append(systr)
1032
+ else:
1033
+ result = ""
1034
+ _append_escape_sequence(kind, chars, systr, s)
1035
+ elif sy == 'NEWLINE':
1036
+ chars.append('\n')
1037
+ elif sy == 'EOF':
1038
+ s.error("Unclosed string literal", pos=pos)
1039
+ else:
1040
+ return None
1041
+ return result
1042
+
1043
+ @cython.cfunc
1044
+ def _validate_kind_string(pos, systring: str) -> str:
1045
+ kind_string = systring.rstrip('"\'').lower()
1046
+ if len(kind_string) <= 1 or (len(kind_string) == 2 and kind_string in "rbrurfrtr"):
1047
+ return kind_string
1048
+ # Otherwise an error of some sort
1049
+ unique_string_prefixes = set(kind_string)
1050
+ if len(unique_string_prefixes) != len(kind_string):
1051
+ error(pos, 'Duplicate string prefix character')
1052
+ unique_string_prefixes.discard('r')
1053
+ unique_string_prefixes = sorted(unique_string_prefixes)
1054
+ if len(unique_string_prefixes) >= 2:
1055
+ error(pos, f'String prefixes {unique_string_prefixes[0]} and {unique_string_prefixes[1]} cannot be combined')
1056
+ else:
1057
+ error(pos, f'Invalid string prefix {kind_string}')
1058
+ return ''
1059
+
1060
+ @cython.cfunc
1061
+ def p_string_literal(s: PyrexScanner, kind_override=None) -> tuple[str, object, object]:
1062
+ # A single string or char literal. Returns (kind, bvalue, uvalue)
1063
+ # where kind in ('b', 'c', 'u', 'f', ''). The 'bvalue' is the source
1064
+ # code byte sequence of the string literal, 'uvalue' is the
1065
+ # decoded Unicode string. Either of the two may be None depending
1066
+ # on the 'kind' of string, only unprefixed strings have both
1067
+ # representations. In f-strings, the uvalue is a list of the Unicode
1068
+ # strings and f-string expressions that make up the f-string.
1069
+ # s.sy == 'BEGIN_STRING' or s.sy == 'BEGIN_FT_STRING'
1070
+ if s.sy == 'BEGIN_FT_STRING':
1071
+ assert kind_override is None
1072
+ return p_ft_string_literal(s)
1073
+ pos = s.position()
1074
+ is_python3_source: cython.bint = s.context.language_level >= 3
1075
+ has_non_ascii_literal_characters = False
1076
+ kind_string = _validate_kind_string(pos, s.systring)
1077
+
1078
+ is_raw: cython.bint = 'r' in kind_string
1079
+
1080
+ if 'c' in kind_string:
1081
+ # this should never happen, since the lexer does not allow combining c
1082
+ # with other prefix characters
1083
+ if len(kind_string) != 1:
1084
+ error(pos, 'Invalid string prefix for character literal')
1085
+ kind = 'c'
1086
+ elif 'b' in kind_string:
1087
+ kind = 'b'
1088
+ elif 'u' in kind_string:
1089
+ kind = 'u'
1090
+ else:
1091
+ kind = ''
1092
+
1093
+ if kind == '' and kind_override is None and Future.unicode_literals in s.context.future_directives:
1094
+ chars = StringEncoding.StrLiteralBuilder(s.source_encoding)
1095
+ kind = 'u'
1096
+ else:
1097
+ if kind_override is not None and kind_override in 'ub':
1098
+ kind = kind_override
1099
+ if kind in ('u', 'f'): # f-strings are scanned exactly like Unicode literals, but are parsed further later
1100
+ chars = StringEncoding.UnicodeLiteralBuilder()
1101
+ elif kind == '':
1102
+ chars = StringEncoding.StrLiteralBuilder(s.source_encoding)
1103
+ else:
1104
+ chars = StringEncoding.BytesLiteralBuilder(s.source_encoding)
1105
+
1106
+ while 1:
1107
+ s.next()
1108
+ handled_chars = p_string_literal_shared_read(
1109
+ s, pos, chars, kind,
1110
+ is_raw=is_raw)
1111
+ if handled_chars is not None:
1112
+ if (not has_non_ascii_literal_characters and
1113
+ is_python3_source and Future.unicode_literals in s.context.future_directives):
1114
+ has_non_ascii_literal_characters = check_for_non_ascii_characters(handled_chars)
1115
+ continue
1116
+ if s.sy == 'END_STRING':
1117
+ break
1118
+ else:
1119
+ s.error("Unexpected token %r:%r in string literal" % (
1120
+ s.sy, s.systring))
1121
+
1122
+ if kind == 'c':
1123
+ unicode_value = None
1124
+ bytes_value = chars.getchar()
1125
+ if len(bytes_value) != 1:
1126
+ error(pos, "invalid character literal: %r" % bytes_value)
1127
+ else:
1128
+ bytes_value, unicode_value = chars.getstrings()
1129
+ if (has_non_ascii_literal_characters
1130
+ and is_python3_source and Future.unicode_literals in s.context.future_directives):
1131
+ # Python 3 forbids literal non-ASCII characters in byte strings
1132
+ if kind == 'b':
1133
+ s.error("bytes can only contain ASCII literal characters.", pos=pos)
1134
+ bytes_value = None
1135
+ s.next()
1136
+ return (kind, bytes_value, unicode_value)
1137
+
1138
+
1139
+ @cython.cfunc
1140
+ def p_read_ft_string_expression(s: PyrexScanner) -> str:
1141
+ strings = []
1142
+ while True:
1143
+ s.next()
1144
+ sy = s.sy
1145
+ if sy in ["END_FT_STRING_EXPR",
1146
+ # probably an error, but handle it elsewhere
1147
+ "EOF", None]:
1148
+ if sy == "END_FT_STRING_EXPR":
1149
+ s.next()
1150
+ return ''.join(strings)
1151
+ strings.append(s.systring)
1152
+
1153
+
1154
+ @cython.cfunc
1155
+ def p_ft_string_replacement_field(s: PyrexScanner,
1156
+ is_raw: cython.bint, is_single_quoted: cython.bint,
1157
+ tf_string_kind: cython.Py_UCS4) -> list:
1158
+ result = []
1159
+ conversion_char = format_spec = expr = None
1160
+ t_string_expression = None
1161
+ self_documenting = False
1162
+
1163
+ bracket_pos = s.position()
1164
+ expr_pos = (bracket_pos[0], bracket_pos[1], bracket_pos[2]+1)
1165
+ expr_string = p_read_ft_string_expression(s)
1166
+ if not expr_string.strip():
1167
+ error(bracket_pos,
1168
+ f"empty expression not allowed in {tf_string_kind}-string")
1169
+ result = []
1170
+ else:
1171
+ original_scanner = s
1172
+ s = PyrexScanner(
1173
+ StringIO(expr_string),
1174
+ bracket_pos[0],
1175
+ parent_scanner=s,
1176
+ source_encoding=s.source_encoding,
1177
+ initial_pos=expr_pos
1178
+ )
1179
+ s.bracket_nesting_level += 1
1180
+ if s.sy == "INDENT":
1181
+ s.next()
1182
+ if s.sy == 'yield':
1183
+ expr = p_yield_expression(
1184
+ s,
1185
+ statement_terminators=statement_terminators | {':', '}', '!'})
1186
+ else:
1187
+ expr = p_testlist_star_expr(s)
1188
+
1189
+ if s.sy == "=":
1190
+ self_documenting = True
1191
+ s.next()
1192
+
1193
+ if s.sy == "!":
1194
+ # format conversion
1195
+ previous_pos = s.position()
1196
+ s.next()
1197
+ conversion_char = s.systring
1198
+ # validate the conversion char
1199
+ if conversion_char in ['}', ':', '']:
1200
+ error(s.position(), "missing conversion character")
1201
+ elif ExprNodes.FormattedValueNode.find_conversion_func(conversion_char) is None:
1202
+ error(s.position(), "invalid conversion character '%s'" % conversion_char)
1203
+ s.next()
1204
+ elif s.position()[2] != (previous_pos[2] + 1):
1205
+ error(s.position(), "f-string: conversion type must come right after the exclamation mark")
1206
+ s.next()
1207
+ else:
1208
+ s.next()
1209
+
1210
+ if self_documenting or tf_string_kind == 't':
1211
+ if conversion_char is not None:
1212
+ expr_string, _ = expr_string.rsplit('!', 1)
1213
+ if tf_string_kind == 't':
1214
+ t_string_expression = ExprNodes.UnicodeNode(
1215
+ pos=expr_pos,
1216
+ value=StringEncoding.EncodedString(expr_string.rstrip().rstrip('=').rstrip())
1217
+ )
1218
+ if self_documenting:
1219
+ result.append(
1220
+ ExprNodes.UnicodeNode(
1221
+ pos=expr_pos,
1222
+ value=StringEncoding.EncodedString(expr_string)
1223
+ )
1224
+ )
1225
+
1226
+ # Validate that the expression string has actually ended
1227
+ while s.sy == "NEWLINE" or s.sy == "DEDENT":
1228
+ s.next()
1229
+ if s.sy != "EOF":
1230
+ error(
1231
+ s.position(),
1232
+ f"Unexpected characters after {tf_string_kind}-string expression: {s.systring}")
1233
+
1234
+ s = original_scanner
1235
+
1236
+ if s.sy == ":":
1237
+ # full format spec
1238
+ pos = s.position()
1239
+ # Contents of format spec are handled closer to an f-string than a t-string
1240
+ # (even for t-strings).
1241
+ format_spec_contents = p_ft_string_middles(s, is_raw, is_single_quoted, is_format_string=True, tf_string_kind='f')
1242
+ format_spec = ExprNodes.JoinedStrNode(
1243
+ pos,
1244
+ values=format_spec_contents
1245
+ )
1246
+ if self_documenting and conversion_char is None and format_spec is None:
1247
+ conversion_char = 'r'
1248
+
1249
+ if conversion_char is not None:
1250
+ conversion_char = StringEncoding.EncodedString(conversion_char)
1251
+ if tf_string_kind == 't':
1252
+ result.append(ExprNodes.TStringInterpolationNode(
1253
+ bracket_pos, value=expr, conversion_char=conversion_char,
1254
+ format_spec=format_spec, expression_str=t_string_expression
1255
+ ))
1256
+ else:
1257
+ result.append(ExprNodes.FormattedValueNode(
1258
+ bracket_pos, value=expr, conversion_char=conversion_char,
1259
+ format_spec=format_spec
1260
+ ))
1261
+ return result
1262
+
1263
+ @cython.cfunc
1264
+ def p_ft_string_middles(s: PyrexScanner,
1265
+ is_raw: cython.bint, is_single_quoted: cython.bint,
1266
+ is_format_string: cython.bint,
1267
+ tf_string_kind: cython.Py_UCS4) -> list:
1268
+ middles: list = []
1269
+ builder = StringEncoding.UnicodeLiteralBuilder()
1270
+ pos = s.position()
1271
+ while True:
1272
+ s.next()
1273
+ sy = s.sy
1274
+
1275
+ handled_chars = p_string_literal_shared_read(
1276
+ s, pos, builder, "u",
1277
+ is_raw=is_raw)
1278
+ if handled_chars is not None:
1279
+ continue
1280
+
1281
+ if builder.chars:
1282
+ middles.append(ExprNodes.UnicodeNode(pos, value=builder.getstring()))
1283
+ builder = StringEncoding.UnicodeLiteralBuilder()
1284
+ if sy == "{":
1285
+ fields = p_ft_string_replacement_field(
1286
+ s, is_raw, is_single_quoted, tf_string_kind=tf_string_kind)
1287
+ middles.extend(fields)
1288
+ if not s.sy == '}':
1289
+ s.expected('}')
1290
+ continue
1291
+ elif sy == "END_FT_STRING":
1292
+ break
1293
+ elif s.sy == '}':
1294
+ if is_format_string:
1295
+ break
1296
+ # otherwise it's an error, but the scanner has reported it
1297
+ else:
1298
+ error(
1299
+ s.position(),
1300
+ "Unexpected token %r:%r in %s-string literal" % (
1301
+ s.sy, s.systring, tf_string_kind))
1302
+ return middles
1303
+
1304
+ @cython.cfunc
1305
+ def p_ft_string_literal(s: PyrexScanner) -> tuple[cython.Py_UCS4, object, object]:
1306
+ # s.sy == BEGIN_FT_STRING
1307
+ kind_string = _validate_kind_string(s.position(), s.systring)
1308
+ tf_string_kind: cython.Py_UCS4 = 't' if 't' in kind_string else 'f'
1309
+ is_raw: cython.bint = 'r' in kind_string
1310
+ quotes = s.systring.lstrip("rRbBuUfFtT")
1311
+ is_single_quoted: cython.bint = len(quotes) != 3
1312
+ middles = p_ft_string_middles(s, is_raw, is_single_quoted, is_format_string=False, tf_string_kind=tf_string_kind)
1313
+ if s.sy != "END_FT_STRING":
1314
+ s.expected(quotes)
1315
+ s.next()
1316
+ return tf_string_kind, None, middles
1317
+
1318
+
1319
+ @cython.cfunc
1320
+ def _append_escape_sequence(kind: str, builder, escape_sequence: str, s: PyrexScanner):
1321
+ if len(escape_sequence) < 2:
1322
+ builder.append("\\") # invalid escape sequence, warned earlier
1323
+ return
1324
+ c = escape_sequence[1]
1325
+ if c in "01234567":
1326
+ builder.append_charval(int(escape_sequence[1:], 8))
1327
+ elif c in "'\"\\":
1328
+ builder.append(c)
1329
+ elif c in "abfnrtv":
1330
+ builder.append(StringEncoding.char_from_escape_sequence(escape_sequence))
1331
+ elif c == '\n':
1332
+ pass # line continuation
1333
+ elif c == 'x': # \xXX
1334
+ if len(escape_sequence) == 4:
1335
+ builder.append_charval(int(escape_sequence[2:], 16))
1336
+ else:
1337
+ s.error("Invalid hex escape '%s'" % escape_sequence, fatal=False)
1338
+ elif c in 'NUu' and kind in ('u', 'f', ''): # \uxxxx, \Uxxxxxxxx, \N{...}
1339
+ chrval: cython.py_int = -1
1340
+ if c == 'N':
1341
+ uchar = None
1342
+ try:
1343
+ uchar = lookup_unicodechar(escape_sequence[3:-1])
1344
+ chrval = ord(uchar)
1345
+ except KeyError:
1346
+ s.error("Unknown Unicode character name %s" %
1347
+ repr(escape_sequence[3:-1]).lstrip('u'), fatal=False)
1348
+ elif len(escape_sequence) in (6, 10):
1349
+ chrval = int(escape_sequence[2:], 16)
1350
+ if chrval > 1114111: # sys.maxunicode:
1351
+ s.error("Invalid unicode escape '%s'" % escape_sequence)
1352
+ chrval = -1
1353
+ else:
1354
+ s.error("Invalid unicode escape '%s'" % escape_sequence, fatal=False)
1355
+ if chrval >= 0:
1356
+ builder.append_uescape(chrval, escape_sequence)
1357
+ else:
1358
+ builder.append(escape_sequence)
1359
+
1360
+
1361
+ # since PEP 448:
1362
+ # list_display ::= "[" [listmaker] "]"
1363
+ # listmaker ::= (named_test|star_expr) ( comp_for | (',' (named_test|star_expr))* [','] )
1364
+ # comp_iter ::= comp_for | comp_if
1365
+ # comp_for ::= ["async"] "for" expression_list "in" testlist [comp_iter]
1366
+ # comp_if ::= "if" test [comp_iter]
1367
+
1368
+ @cython.cfunc
1369
+ def p_list_maker(s: PyrexScanner):
1370
+ # s.sy == '['
1371
+ pos = s.position()
1372
+ s.next()
1373
+ if s.sy == ']':
1374
+ s.expect(']')
1375
+ return ExprNodes.ListNode(pos, args=[])
1376
+
1377
+ expr = p_namedexpr_test_or_starred_expr(s)
1378
+ if s.sy in ('for', 'async'):
1379
+ append = ExprNodes.ComprehensionAppendNode(pos, expr=expr)
1380
+ loop = p_comp_for(s, append)
1381
+ s.expect(']')
1382
+ return ExprNodes.ComprehensionNode(
1383
+ pos, loop=loop, append=append, type=Builtin.list_type,
1384
+ # list comprehensions leak their loop variable in Py2
1385
+ has_local_scope=s.context.language_level >= 3)
1386
+
1387
+ # (merged) list literal
1388
+ if s.sy == ',':
1389
+ s.next()
1390
+ exprs = p_namedexpr_test_or_starred_expr_list(s, expr)
1391
+ else:
1392
+ exprs = [expr]
1393
+ s.expect(']')
1394
+ return ExprNodes.ListNode(pos, args=exprs)
1395
+
1396
+
1397
+ @cython.cfunc
1398
+ def p_comp_iter(s: PyrexScanner, body):
1399
+ if s.sy in ('for', 'async'):
1400
+ return p_comp_for(s, body)
1401
+ elif s.sy == 'if':
1402
+ return p_comp_if(s, body)
1403
+ else:
1404
+ # insert the 'append' operation into the loop
1405
+ return body
1406
+
1407
+
1408
+ @cython.cfunc
1409
+ def p_comp_for(s: PyrexScanner, body):
1410
+ pos = s.position()
1411
+ # [async] for ...
1412
+ is_async = False
1413
+ if s.sy == 'async':
1414
+ is_async = True
1415
+ s.next()
1416
+
1417
+ # s.sy == 'for'
1418
+ s.expect('for')
1419
+ kw = p_for_bounds(s, allow_testlist=False, is_async=is_async)
1420
+ kw.update(else_clause=None, body=p_comp_iter(s, body), is_async=is_async)
1421
+ return Nodes.ForStatNode(pos, **kw)
1422
+
1423
+
1424
+ @cython.cfunc
1425
+ def p_comp_if(s: PyrexScanner, body):
1426
+ # s.sy == 'if'
1427
+ pos = s.position()
1428
+ s.next()
1429
+ # Note that Python 3.9+ is actually more restrictive here and Cython now follows
1430
+ # the Python 3.9+ behaviour: https://github.com/python/cpython/issues/86014
1431
+ # On Python <3.9 `[i for i in range(10) if lambda: i if True else 1]` was disallowed
1432
+ # but `[i for i in range(10) if lambda: i]` was allowed.
1433
+ # On Python >=3.9 they're both disallowed.
1434
+ test = p_or_test(s)
1435
+ return Nodes.IfStatNode(pos,
1436
+ if_clauses = [Nodes.IfClauseNode(pos, condition = test,
1437
+ body = p_comp_iter(s, body))],
1438
+ else_clause = None )
1439
+
1440
+
1441
+ # since PEP 448:
1442
+ #dictorsetmaker: ( ((test ':' test | '**' expr)
1443
+ # (comp_for | (',' (test ':' test | '**' expr))* [','])) |
1444
+ # ((test | star_expr)
1445
+ # (comp_for | (',' (test | star_expr))* [','])) )
1446
+
1447
+ @cython.cfunc
1448
+ def p_dict_or_set_maker(s: PyrexScanner):
1449
+ # s.sy == '{'
1450
+ pos = s.position()
1451
+ s.next()
1452
+ if s.sy == '}':
1453
+ s.next()
1454
+ return ExprNodes.DictNode(pos, key_value_pairs=[])
1455
+
1456
+ target_type: cython.int = 0
1457
+
1458
+ if s.sy == '*':
1459
+ last_was_simple_item = False
1460
+ target_type = 1 # set
1461
+ item = p_starred_expr(s)
1462
+ elif s.sy == '**':
1463
+ last_was_simple_item = False
1464
+ target_type = 2 # dict
1465
+ s.next()
1466
+ if s.sy == '*':
1467
+ s.error("expected expression, found '*'")
1468
+ item = p_starred_expr(s)
1469
+ else:
1470
+ last_was_simple_item = True
1471
+ target_type = 1 # set
1472
+ item = p_test(s)
1473
+ if s.sy == ':':
1474
+ target_type = 2 # dict
1475
+ key = item
1476
+ s.next()
1477
+ value = p_test(s)
1478
+ item = ExprNodes.DictItemNode(key.pos, key=key, value=value)
1479
+
1480
+ if s.sy in ('for', 'async'):
1481
+ # set/dict comprehension
1482
+ if target_type == 2:
1483
+ comprehension_type = Builtin.dict_type
1484
+ append = ExprNodes.DictComprehensionAppendNode(item.pos, dict_item=item)
1485
+ else:
1486
+ comprehension_type = Builtin.set_type
1487
+ append = ExprNodes.ComprehensionAppendNode(item.pos, expr=item)
1488
+
1489
+ loop = p_comp_for(s, append)
1490
+ s.expect('}')
1491
+ return ExprNodes.ComprehensionNode(pos, loop=loop, append=append, type=comprehension_type)
1492
+
1493
+ # set/dict literal
1494
+ merged_items = []
1495
+ simple_items = []
1496
+
1497
+ if last_was_simple_item:
1498
+ simple_items.append(item)
1499
+ else:
1500
+ merged_items.append(item.target if item.is_starred else item)
1501
+
1502
+ while s.sy == ',':
1503
+ s.next()
1504
+ if s.sy == '}':
1505
+ break
1506
+
1507
+ if s.sy in ('*', '**'):
1508
+ if target_type != len(s.sy):
1509
+ s.error(f"unexpected {s.sy}item found in {'set' if target_type == 1 else 'dict'} literal")
1510
+
1511
+ if simple_items:
1512
+ if target_type == 1:
1513
+ item = ExprNodes.SetNode(simple_items[0].pos, args=simple_items)
1514
+ else:
1515
+ item = ExprNodes.DictNode(simple_items[0].pos, key_value_pairs=simple_items)
1516
+ merged_items.append(item)
1517
+ simple_items = []
1518
+
1519
+ s.next()
1520
+ if s.sy == '*':
1521
+ s.error("expected expression, found '*'")
1522
+ item = p_starred_expr(s)
1523
+ merged_items.append(item)
1524
+
1525
+ else:
1526
+ item = p_test(s)
1527
+ if target_type == 2:
1528
+ # dict literal
1529
+ s.expect(':')
1530
+ key = item
1531
+ value = p_test(s)
1532
+ item = ExprNodes.DictItemNode(key.pos, key=key, value=value)
1533
+
1534
+ simple_items.append(item)
1535
+
1536
+ s.expect('}')
1537
+
1538
+ if target_type == 1:
1539
+ if simple_items:
1540
+ merged_items.append(ExprNodes.SetNode(simple_items[0].pos, args=simple_items))
1541
+ if len(merged_items) == 1 and merged_items[0].is_set_literal:
1542
+ return merged_items[0]
1543
+ return ExprNodes.MergedSequenceNode(pos, args=merged_items, type=Builtin.set_type)
1544
+ else:
1545
+ if simple_items:
1546
+ merged_items.append(ExprNodes.DictNode(simple_items[0].pos, key_value_pairs=simple_items))
1547
+ if len(merged_items) == 1 and merged_items[0].is_dict_literal:
1548
+ return merged_items[0]
1549
+ return ExprNodes.MergedDictNode(pos, keyword_args=merged_items, reject_duplicates=False)
1550
+
1551
+
1552
+ # NOTE: no longer in Py3 :)
1553
+ @cython.cfunc
1554
+ def p_backquote_expr(s: PyrexScanner):
1555
+ # s.sy == '`'
1556
+ pos = s.position()
1557
+ s.next()
1558
+ args = [p_test(s)]
1559
+ while s.sy == ',':
1560
+ s.next()
1561
+ args.append(p_test(s))
1562
+ s.expect('`')
1563
+ if len(args) == 1:
1564
+ arg = args[0]
1565
+ else:
1566
+ arg = ExprNodes.TupleNode(pos, args = args)
1567
+ return ExprNodes.BackquoteNode(pos, arg = arg)
1568
+
1569
+
1570
+ @cython.cfunc
1571
+ def p_simple_expr_list(s: PyrexScanner, expr=None) -> list:
1572
+ exprs: list = [expr] if expr is not None else []
1573
+ while s.sy not in expr_terminators:
1574
+ exprs.append( p_test(s) )
1575
+ if s.sy != ',':
1576
+ break
1577
+ s.next()
1578
+ return exprs
1579
+
1580
+
1581
+ @cython.cfunc
1582
+ def p_test_or_starred_expr_list(s: PyrexScanner, expr=None) -> list:
1583
+ exprs: list = [expr] if expr is not None else []
1584
+ while s.sy not in expr_terminators:
1585
+ exprs.append(p_test_or_starred_expr(s))
1586
+ if s.sy != ',':
1587
+ break
1588
+ s.next()
1589
+ return exprs
1590
+
1591
+
1592
+ @cython.cfunc
1593
+ def p_namedexpr_test_or_starred_expr_list(s: PyrexScanner, expr=None) -> list:
1594
+ exprs: list = [expr] if expr is not None else []
1595
+ while s.sy not in expr_terminators:
1596
+ exprs.append(p_namedexpr_test_or_starred_expr(s))
1597
+ if s.sy != ',':
1598
+ break
1599
+ s.next()
1600
+ return exprs
1601
+
1602
+
1603
+ #testlist: test (',' test)* [',']
1604
+
1605
+ @cython.cfunc
1606
+ def p_testlist(s: PyrexScanner):
1607
+ pos = s.position()
1608
+ expr = p_test(s)
1609
+ if s.sy == ',':
1610
+ s.next()
1611
+ exprs = p_simple_expr_list(s, expr)
1612
+ return ExprNodes.TupleNode(pos, args = exprs)
1613
+ else:
1614
+ return expr
1615
+
1616
+
1617
+ # testlist_star_expr: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
1618
+
1619
+ @cython.cfunc
1620
+ def p_testlist_star_expr(s: PyrexScanner):
1621
+ pos = s.position()
1622
+ expr = p_test_or_starred_expr(s)
1623
+ if s.sy == ',':
1624
+ s.next()
1625
+ exprs = p_test_or_starred_expr_list(s, expr)
1626
+ return ExprNodes.TupleNode(pos, args = exprs)
1627
+ else:
1628
+ return expr
1629
+
1630
+
1631
+ # testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
1632
+
1633
+ @cython.cfunc
1634
+ def p_testlist_comp(s: PyrexScanner):
1635
+ pos = s.position()
1636
+ expr = p_namedexpr_test_or_starred_expr(s)
1637
+ if s.sy == ',':
1638
+ s.next()
1639
+ exprs = p_namedexpr_test_or_starred_expr_list(s, expr)
1640
+ return ExprNodes.TupleNode(pos, args = exprs)
1641
+ elif s.sy in ('for', 'async'):
1642
+ return p_genexp(s, expr)
1643
+ else:
1644
+ return expr
1645
+
1646
+
1647
+ @cython.cfunc
1648
+ def p_genexp(s: PyrexScanner, expr):
1649
+ # s.sy == 'async' | 'for'
1650
+ loop = p_comp_for(s, Nodes.ExprStatNode(
1651
+ expr.pos, expr = ExprNodes.YieldExprNode(expr.pos, arg=expr)))
1652
+ return ExprNodes.GeneratorExpressionNode(expr.pos, loop=loop)
1653
+
1654
+
1655
+ expr_terminators = cython.declare(frozenset, frozenset((
1656
+ ')', ']', '}', ':', '=', 'NEWLINE', 'EOF')))
1657
+
1658
+
1659
+ #-------------------------------------------------------
1660
+ #
1661
+ # Statements
1662
+ #
1663
+ #-------------------------------------------------------
1664
+
1665
+ @cython.cfunc
1666
+ def p_global_statement(s: PyrexScanner):
1667
+ # assume s.sy == 'global'
1668
+ pos = s.position()
1669
+ s.next()
1670
+ names = p_ident_list(s)
1671
+ return Nodes.GlobalNode(pos, names = names)
1672
+
1673
+
1674
+ @cython.cfunc
1675
+ def p_nonlocal_statement(s: PyrexScanner):
1676
+ pos = s.position()
1677
+ s.next()
1678
+ names = p_ident_list(s)
1679
+ return Nodes.NonlocalNode(pos, names = names)
1680
+
1681
+
1682
+ @cython.cfunc
1683
+ def p_expression_or_assignment(s: PyrexScanner):
1684
+ expr = p_testlist_star_expr(s)
1685
+ has_annotation = False
1686
+ if s.sy == ':' and (expr.is_name or expr.is_subscript or expr.is_attribute):
1687
+ has_annotation = True
1688
+ s.next()
1689
+ expr.annotation = p_annotation(s)
1690
+
1691
+ if s.sy == '=' and expr.is_starred:
1692
+ # This is a common enough error to make when learning Cython to let
1693
+ # it fail as early as possible and give a very clear error message.
1694
+ s.error("a starred assignment target must be in a list or tuple"
1695
+ " - maybe you meant to use an index assignment: var[0] = ...",
1696
+ pos=expr.pos)
1697
+
1698
+ expr_list = [expr]
1699
+ while s.sy == '=':
1700
+ s.next()
1701
+ if s.sy == 'yield':
1702
+ expr = p_yield_expression(s)
1703
+ else:
1704
+ expr = p_testlist_star_expr(s)
1705
+ expr_list.append(expr)
1706
+ if len(expr_list) == 1:
1707
+ if re.match(r"([-+*/%^&|]|<<|>>|\*\*|//|@)=", s.sy):
1708
+ lhs = expr_list[0]
1709
+ if isinstance(lhs, ExprNodes.SliceIndexNode):
1710
+ # implementation requires IndexNode
1711
+ lhs = ExprNodes.IndexNode(
1712
+ lhs.pos,
1713
+ base=lhs.base,
1714
+ index=make_slice_node(lhs.pos, lhs.start, lhs.stop))
1715
+ elif not isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode, ExprNodes.NameNode)):
1716
+ error(lhs.pos, "Illegal operand for inplace operation.")
1717
+ operator = s.sy[:-1]
1718
+ s.next()
1719
+ if s.sy == 'yield':
1720
+ rhs = p_yield_expression(s)
1721
+ else:
1722
+ rhs = p_testlist(s)
1723
+ return Nodes.InPlaceAssignmentNode(lhs.pos, operator=operator, lhs=lhs, rhs=rhs)
1724
+ expr = expr_list[0]
1725
+ return Nodes.ExprStatNode(expr.pos, expr=expr)
1726
+
1727
+ rhs = expr_list[-1]
1728
+ if len(expr_list) == 2:
1729
+ return Nodes.SingleAssignmentNode(rhs.pos, lhs=expr_list[0], rhs=rhs, first=has_annotation)
1730
+ else:
1731
+ return Nodes.CascadedAssignmentNode(rhs.pos, lhs_list=expr_list[:-1], rhs=rhs)
1732
+
1733
+
1734
+ @cython.cfunc
1735
+ def p_print_statement(s: PyrexScanner):
1736
+ # s.sy == 'print'
1737
+ pos = s.position()
1738
+ ends_with_comma: cython.bint = False
1739
+ s.next()
1740
+ if s.sy == '>>':
1741
+ s.next()
1742
+ stream = p_test(s)
1743
+ if s.sy == ',':
1744
+ s.next()
1745
+ ends_with_comma = s.sy in ('NEWLINE', 'EOF')
1746
+ else:
1747
+ stream = None
1748
+ args = []
1749
+ if s.sy not in ('NEWLINE', 'EOF'):
1750
+ args.append(p_test(s))
1751
+ while s.sy == ',':
1752
+ s.next()
1753
+ if s.sy in ('NEWLINE', 'EOF'):
1754
+ ends_with_comma = True
1755
+ break
1756
+ args.append(p_test(s))
1757
+ arg_tuple = ExprNodes.TupleNode(pos, args=args)
1758
+ return Nodes.PrintStatNode(pos,
1759
+ arg_tuple=arg_tuple, stream=stream,
1760
+ append_newline=not ends_with_comma)
1761
+
1762
+
1763
+ @cython.cfunc
1764
+ def p_exec_statement(s: PyrexScanner):
1765
+ # s.sy == 'exec'
1766
+ pos = s.position()
1767
+ s.next()
1768
+ code = p_bit_expr(s)
1769
+ if isinstance(code, ExprNodes.TupleNode):
1770
+ # Py3 compatibility syntax
1771
+ tuple_variant = True
1772
+ args = code.args
1773
+ if len(args) not in (2, 3):
1774
+ s.error("expected tuple of length 2 or 3, got length %d" % len(args),
1775
+ pos=pos, fatal=False)
1776
+ args = [code]
1777
+ else:
1778
+ tuple_variant = False
1779
+ args = [code]
1780
+ if s.sy == 'in':
1781
+ if tuple_variant:
1782
+ s.error("tuple variant of exec does not support additional 'in' arguments",
1783
+ fatal=False)
1784
+ s.next()
1785
+ args.append(p_test(s))
1786
+ if s.sy == ',':
1787
+ s.next()
1788
+ args.append(p_test(s))
1789
+ return Nodes.ExecStatNode(pos, args=args)
1790
+
1791
+
1792
+ @cython.cfunc
1793
+ def p_del_statement(s: PyrexScanner):
1794
+ # s.sy == 'del'
1795
+ pos = s.position()
1796
+ s.next()
1797
+ # FIXME: 'exprlist' in Python
1798
+ args = p_simple_expr_list(s)
1799
+ return Nodes.DelStatNode(pos, args = args)
1800
+
1801
+
1802
+ @cython.cfunc
1803
+ def p_pass_statement(s: PyrexScanner, with_newline: cython.bint = False):
1804
+ pos = s.position()
1805
+ s.expect('pass')
1806
+ if with_newline:
1807
+ s.expect_newline("Expected a newline", ignore_semicolon=True)
1808
+ return Nodes.PassStatNode(pos)
1809
+
1810
+
1811
+ @cython.cfunc
1812
+ def p_break_statement(s: PyrexScanner):
1813
+ # s.sy == 'break'
1814
+ pos = s.position()
1815
+ s.next()
1816
+ return Nodes.BreakStatNode(pos)
1817
+
1818
+
1819
+ @cython.cfunc
1820
+ def p_continue_statement(s: PyrexScanner):
1821
+ # s.sy == 'continue'
1822
+ pos = s.position()
1823
+ s.next()
1824
+ return Nodes.ContinueStatNode(pos)
1825
+
1826
+
1827
+ @cython.cfunc
1828
+ def p_return_statement(s: PyrexScanner):
1829
+ # s.sy == 'return'
1830
+ pos = s.position()
1831
+ s.next()
1832
+ if s.sy not in statement_terminators:
1833
+ value = p_testlist(s)
1834
+ else:
1835
+ value = None
1836
+ return Nodes.ReturnStatNode(pos, value = value)
1837
+
1838
+
1839
+ @cython.cfunc
1840
+ def p_raise_statement(s: PyrexScanner):
1841
+ # s.sy == 'raise'
1842
+ pos = s.position()
1843
+ s.next()
1844
+ exc_type = None
1845
+ exc_value = None
1846
+ exc_tb = None
1847
+ cause = None
1848
+ if s.sy not in statement_terminators:
1849
+ exc_type = p_test(s)
1850
+ if s.sy == ',':
1851
+ s.next()
1852
+ exc_value = p_test(s)
1853
+ if s.sy == ',':
1854
+ s.next()
1855
+ exc_tb = p_test(s)
1856
+ elif s.sy == 'from':
1857
+ s.next()
1858
+ cause = p_test(s)
1859
+ if exc_type or exc_value or exc_tb:
1860
+ return Nodes.RaiseStatNode(pos,
1861
+ exc_type = exc_type,
1862
+ exc_value = exc_value,
1863
+ exc_tb = exc_tb,
1864
+ cause = cause)
1865
+ else:
1866
+ return Nodes.ReraiseStatNode(pos)
1867
+
1868
+
1869
+ @cython.cfunc
1870
+ def p_import_statement(s: PyrexScanner):
1871
+ # s.sy in ('import', 'cimport')
1872
+ pos = s.position()
1873
+ kind = s.sy
1874
+ s.next()
1875
+ items = [p_dotted_name(s, as_allowed=True)]
1876
+ while s.sy == ',':
1877
+ s.next()
1878
+ items.append(p_dotted_name(s, as_allowed=True))
1879
+ stats = []
1880
+ is_absolute = Future.absolute_import in s.context.future_directives
1881
+ for pos, target_name, dotted_name, as_name in items:
1882
+ if kind == 'cimport':
1883
+ stat = Nodes.CImportStatNode(
1884
+ pos,
1885
+ module_name=dotted_name,
1886
+ as_name=as_name,
1887
+ is_absolute=is_absolute)
1888
+ else:
1889
+ stat = Nodes.SingleAssignmentNode(
1890
+ pos,
1891
+ lhs=ExprNodes.NameNode(pos, name=as_name or target_name),
1892
+ rhs=ExprNodes.ImportNode(
1893
+ pos,
1894
+ module_name=ExprNodes.IdentifierStringNode(pos, value=dotted_name),
1895
+ is_import_as_name=bool(as_name),
1896
+ level=0 if is_absolute else None,
1897
+ imported_names=None))
1898
+ stats.append(stat)
1899
+ return Nodes.StatListNode(pos, stats=stats)
1900
+
1901
+
1902
+ @cython.cfunc
1903
+ def p_from_import_statement(s: PyrexScanner, first_statement: cython.bint = 0):
1904
+ # s.sy == 'from'
1905
+ pos = s.position()
1906
+ s.next()
1907
+ if s.sy in ('.', '...'):
1908
+ # count relative import level
1909
+ level = 0
1910
+ while s.sy in ('.', '...'):
1911
+ level += len(s.sy)
1912
+ s.next()
1913
+ else:
1914
+ level = None
1915
+ if level is not None and s.sy in ('import', 'cimport'):
1916
+ # we are dealing with "from .. import foo, bar"
1917
+ dotted_name_pos, dotted_name = s.position(), s.context.intern_ustring('')
1918
+ else:
1919
+ if level is None and Future.absolute_import in s.context.future_directives:
1920
+ level = 0
1921
+ (dotted_name_pos, _, dotted_name, _) = p_dotted_name(s, as_allowed=False)
1922
+ if s.sy not in ('import', 'cimport'):
1923
+ s.error("Expected 'import' or 'cimport'")
1924
+ kind = s.sy
1925
+ s.next()
1926
+
1927
+ is_cimport = kind == 'cimport'
1928
+ is_parenthesized = False
1929
+ if s.sy == '*':
1930
+ imported_names = [(s.position(), s.context.intern_ustring("*"), None)]
1931
+ s.next()
1932
+ else:
1933
+ if s.sy == '(':
1934
+ is_parenthesized = True
1935
+ s.next()
1936
+ imported_names = [p_imported_name(s)]
1937
+ while s.sy == ',':
1938
+ s.next()
1939
+ if is_parenthesized and s.sy == ')':
1940
+ break
1941
+ imported_names.append(p_imported_name(s))
1942
+ if is_parenthesized:
1943
+ s.expect(')')
1944
+ if dotted_name == '__future__':
1945
+ if not first_statement:
1946
+ s.error("from __future__ imports must occur at the beginning of the file")
1947
+ elif level:
1948
+ s.error("invalid syntax")
1949
+ else:
1950
+ for (name_pos, name, as_name) in imported_names:
1951
+ if name == "braces":
1952
+ s.error("not a chance", name_pos)
1953
+ break
1954
+ try:
1955
+ directive = getattr(Future, name)
1956
+ except AttributeError:
1957
+ s.error("future feature %s is not defined" % name, name_pos)
1958
+ break
1959
+ s.context.future_directives.add(directive)
1960
+ return Nodes.PassStatNode(pos)
1961
+ elif is_cimport:
1962
+ return Nodes.FromCImportStatNode(
1963
+ pos, module_name=dotted_name,
1964
+ relative_level=level,
1965
+ imported_names=imported_names)
1966
+ else:
1967
+ imported_name_strings = []
1968
+ items = []
1969
+ for (name_pos, name, as_name) in imported_names:
1970
+ imported_name_strings.append(
1971
+ ExprNodes.IdentifierStringNode(name_pos, value=name))
1972
+ items.append(
1973
+ (name, ExprNodes.NameNode(name_pos, name=as_name or name)))
1974
+ return Nodes.FromImportStatNode(pos,
1975
+ module = ExprNodes.ImportNode(dotted_name_pos,
1976
+ module_name = ExprNodes.IdentifierStringNode(pos, value = dotted_name),
1977
+ is_import_as_name = False,
1978
+ level = level,
1979
+ imported_names = imported_name_strings),
1980
+ items = items)
1981
+
1982
+
1983
+ @cython.cfunc
1984
+ def p_imported_name(s: PyrexScanner) -> tuple:
1985
+ pos = s.position()
1986
+ name = p_ident(s)
1987
+ as_name = p_as_name(s)
1988
+ return (pos, name, as_name)
1989
+
1990
+
1991
+ @cython.cfunc
1992
+ def p_dotted_name(s: PyrexScanner, as_allowed: cython.bint) -> tuple:
1993
+ pos = s.position()
1994
+ target_name = p_ident(s)
1995
+ as_name = None
1996
+ names = [target_name]
1997
+ while s.sy == '.':
1998
+ s.next()
1999
+ names.append(p_ident(s))
2000
+ if as_allowed:
2001
+ as_name = p_as_name(s)
2002
+ return (pos, target_name, s.context.intern_ustring('.'.join(names)), as_name)
2003
+
2004
+
2005
+ @cython.cfunc
2006
+ def p_as_name(s: PyrexScanner):
2007
+ if s.sy == 'IDENT' and s.systring == 'as':
2008
+ s.next()
2009
+ return p_ident(s)
2010
+ else:
2011
+ return None
2012
+
2013
+
2014
+ @cython.cfunc
2015
+ def p_assert_statement(s: PyrexScanner):
2016
+ # s.sy == 'assert'
2017
+ pos = s.position()
2018
+ s.next()
2019
+ cond = p_test(s)
2020
+ if s.sy == ',':
2021
+ s.next()
2022
+ value = p_test(s)
2023
+ else:
2024
+ value = None
2025
+ return Nodes.AssertStatNode(pos, condition=cond, value=value)
2026
+
2027
+
2028
+ @cython.cfunc
2029
+ def p_if_statement(s: PyrexScanner):
2030
+ # s.sy == 'if'
2031
+ pos = s.position()
2032
+ s.next()
2033
+ if_clauses = [p_if_clause(s)]
2034
+ while s.sy == 'elif':
2035
+ s.next()
2036
+ if_clauses.append(p_if_clause(s))
2037
+ else_clause = p_else_clause(s)
2038
+ return Nodes.IfStatNode(pos,
2039
+ if_clauses = if_clauses, else_clause = else_clause)
2040
+
2041
+
2042
+ @cython.cfunc
2043
+ def p_if_clause(s: PyrexScanner):
2044
+ pos = s.position()
2045
+ test = p_namedexpr_test(s)
2046
+ body = p_suite(s)
2047
+ return Nodes.IfClauseNode(pos,
2048
+ condition = test, body = body)
2049
+
2050
+
2051
+ @cython.cfunc
2052
+ def p_else_clause(s: PyrexScanner):
2053
+ if s.sy == 'else':
2054
+ s.next()
2055
+ return p_suite(s)
2056
+ else:
2057
+ return None
2058
+
2059
+
2060
+ @cython.cfunc
2061
+ def p_while_statement(s: PyrexScanner):
2062
+ # s.sy == 'while'
2063
+ pos = s.position()
2064
+ s.next()
2065
+ test = p_namedexpr_test(s)
2066
+ body = p_suite(s)
2067
+ else_clause = p_else_clause(s)
2068
+ return Nodes.WhileStatNode(pos,
2069
+ condition = test, body = body,
2070
+ else_clause = else_clause)
2071
+
2072
+
2073
+ @cython.cfunc
2074
+ def p_for_statement(s: PyrexScanner, is_async: cython.bint = False):
2075
+ # s.sy == 'for'
2076
+ pos = s.position()
2077
+ s.next()
2078
+ kw = p_for_bounds(s, allow_testlist=True, is_async=is_async)
2079
+ body = p_suite(s)
2080
+ else_clause = p_else_clause(s)
2081
+ kw.update(body=body, else_clause=else_clause, is_async=is_async)
2082
+ return Nodes.ForStatNode(pos, **kw)
2083
+
2084
+
2085
+ @cython.cfunc
2086
+ def p_for_bounds(s: PyrexScanner, allow_testlist: cython.bint = True, is_async: cython.bint = False) -> dict:
2087
+ target = p_for_target(s)
2088
+ if s.sy == 'in':
2089
+ s.next()
2090
+ iterator = p_for_iterator(s, allow_testlist, is_async=is_async)
2091
+ return dict(target=target, iterator=iterator)
2092
+ elif not s.in_python_file and not is_async:
2093
+ if s.sy == 'from':
2094
+ s.next()
2095
+ bound1 = p_bit_expr(s)
2096
+ else:
2097
+ # Support shorter "for a <= x < b" syntax
2098
+ bound1, target = target, None
2099
+ rel1 = p_for_from_relation(s)
2100
+ name2_pos = s.position()
2101
+ name2 = p_ident(s)
2102
+ rel2_pos = s.position()
2103
+ rel2 = p_for_from_relation(s)
2104
+ bound2 = p_bit_expr(s)
2105
+ step = p_for_from_step(s)
2106
+ if target is None:
2107
+ target = ExprNodes.NameNode(name2_pos, name = name2)
2108
+ else:
2109
+ if not target.is_name:
2110
+ error(target.pos,
2111
+ "Target of for-from statement must be a variable name")
2112
+ elif name2 != target.name:
2113
+ error(name2_pos,
2114
+ "Variable name in for-from range does not match target")
2115
+ if rel1[0] != rel2[0]:
2116
+ error(rel2_pos,
2117
+ "Relation directions in for-from do not match")
2118
+ return dict(target = target,
2119
+ bound1 = bound1,
2120
+ relation1 = rel1,
2121
+ relation2 = rel2,
2122
+ bound2 = bound2,
2123
+ step = step,
2124
+ )
2125
+ else:
2126
+ s.expect('in')
2127
+ return {}
2128
+
2129
+
2130
+ @cython.cfunc
2131
+ def p_for_from_relation(s: PyrexScanner):
2132
+ if s.sy in inequality_relations:
2133
+ op = s.sy
2134
+ s.next()
2135
+ return op
2136
+ else:
2137
+ s.error("Expected one of '<', '<=', '>' '>='")
2138
+
2139
+
2140
+ @cython.cfunc
2141
+ def p_for_from_step(s: PyrexScanner):
2142
+ if s.sy == 'IDENT' and s.systring == 'by':
2143
+ s.next()
2144
+ step = p_bit_expr(s)
2145
+ return step
2146
+ else:
2147
+ return None
2148
+
2149
+
2150
+ inequality_relations = cython.declare(frozenset, frozenset((
2151
+ '<', '<=', '>', '>=')))
2152
+
2153
+
2154
+ @cython.cfunc
2155
+ def p_target(s: PyrexScanner, terminator: str):
2156
+ pos = s.position()
2157
+ expr = p_starred_expr(s)
2158
+ if s.sy == ',':
2159
+ s.next()
2160
+ exprs = [expr]
2161
+ while s.sy != terminator:
2162
+ exprs.append(p_starred_expr(s))
2163
+ if s.sy != ',':
2164
+ break
2165
+ s.next()
2166
+ return ExprNodes.TupleNode(pos, args = exprs)
2167
+ else:
2168
+ return expr
2169
+
2170
+
2171
+ @cython.cfunc
2172
+ def p_for_target(s: PyrexScanner):
2173
+ return p_target(s, 'in')
2174
+
2175
+
2176
+ @cython.cfunc
2177
+ def p_for_iterator(s: PyrexScanner, allow_testlist: cython.bint = True, is_async: cython.bint = False):
2178
+ pos = s.position()
2179
+ if allow_testlist:
2180
+ expr = p_testlist(s)
2181
+ else:
2182
+ expr = p_or_test(s)
2183
+ return (ExprNodes.AsyncIteratorNode if is_async else ExprNodes.IteratorNode)(pos, sequence=expr)
2184
+
2185
+
2186
+ @cython.cfunc
2187
+ def p_try_statement(s: PyrexScanner):
2188
+ # s.sy == 'try'
2189
+ pos = s.position()
2190
+ s.next()
2191
+ body = p_suite(s)
2192
+ except_clauses = []
2193
+ else_clause = None
2194
+ if s.sy in ('except', 'else'):
2195
+ while s.sy == 'except':
2196
+ except_clauses.append(p_except_clause(s))
2197
+ if s.sy == 'else':
2198
+ s.next()
2199
+ else_clause = p_suite(s)
2200
+
2201
+ for clause in except_clauses[1:]:
2202
+ if clause.is_except_star != except_clauses[0].is_except_star:
2203
+ s.error("cannot have both 'except' and 'except*' on the same 'try'", pos=clause.pos)
2204
+ break
2205
+
2206
+ if except_clauses and except_clauses[0].is_except_star:
2207
+ except_body = Nodes.ExceptStarChainNode(pos, except_clauses=except_clauses)
2208
+ except_clauses = [
2209
+ Nodes.ExceptClauseNode(
2210
+ pos,
2211
+ pattern=[],
2212
+ body=except_body, target=None)
2213
+ ]
2214
+
2215
+ body = Nodes.TryExceptStatNode(pos,
2216
+ body = body, except_clauses = except_clauses,
2217
+ else_clause = else_clause)
2218
+ if s.sy != 'finally':
2219
+ return body
2220
+ # try-except-finally is equivalent to nested try-except/try-finally
2221
+ if s.sy == 'finally':
2222
+ s.next()
2223
+ finally_clause = p_suite(s)
2224
+ return Nodes.TryFinallyStatNode(pos,
2225
+ body = body, finally_clause = finally_clause)
2226
+ else:
2227
+ s.error("Expected 'except' or 'finally'")
2228
+
2229
+
2230
+ @cython.cfunc
2231
+ def p_except_clause(s: PyrexScanner):
2232
+ # Share as much implementation as possible between except and except*
2233
+ # s.sy == 'except'
2234
+ pos = s.position()
2235
+ s.next()
2236
+ is_except_star = s.sy == '*'
2237
+ if is_except_star:
2238
+ s.next()
2239
+ exc_type = None
2240
+ exc_value = None
2241
+ is_except_as = False
2242
+ if s.sy != ':':
2243
+ exc_type = p_test(s)
2244
+ # normalise into list of single exception tests
2245
+ if isinstance(exc_type, ExprNodes.TupleNode):
2246
+ exc_type = exc_type.args
2247
+ else:
2248
+ exc_type = [exc_type]
2249
+ # Don't allow old , syntax at all for except*
2250
+ if not is_except_star and s.sy == ',' or (
2251
+ s.sy == 'IDENT' and s.systring == 'as'
2252
+ and s.context.language_level == 2):
2253
+ s.next()
2254
+ exc_value = p_test(s)
2255
+ elif s.sy == 'IDENT' and s.systring == 'as':
2256
+ # Py3 syntax requires a name here
2257
+ s.next()
2258
+ pos2 = s.position()
2259
+ name = p_ident(s)
2260
+ exc_value = ExprNodes.NameNode(pos2, name = name)
2261
+ is_except_as = True
2262
+ elif is_except_star:
2263
+ s.error("Expected exception type after except*")
2264
+ body = p_suite(s)
2265
+ return Nodes.ExceptClauseNode(pos,
2266
+ pattern = exc_type, target = exc_value,
2267
+ body = body, is_except_as=is_except_as,
2268
+ is_except_star = is_except_star)
2269
+
2270
+
2271
+ @cython.cfunc
2272
+ def p_include_statement(s: PyrexScanner, ctx):
2273
+ pos = s.position()
2274
+ s.next() # 'include'
2275
+ unicode_include_file_name = p_string_literal(s, 'u')[2]
2276
+ s.expect_newline("Syntax error in include statement")
2277
+ if s.compile_time_eval:
2278
+ include_file_name = unicode_include_file_name
2279
+ include_file_path = s.context.find_include_file(include_file_name, pos)
2280
+ if include_file_path:
2281
+ s.included_files.append(include_file_name)
2282
+ source_desc = FileSourceDescriptor(include_file_path)
2283
+ with source_desc.get_file_object() as f:
2284
+ s2 = PyrexScanner(f, source_desc, s, source_encoding=f.encoding, parse_comments=s.parse_comments)
2285
+ tree = p_statement_list(s2, ctx)
2286
+ return tree
2287
+ else:
2288
+ return None
2289
+ else:
2290
+ return Nodes.PassStatNode(pos)
2291
+
2292
+
2293
+ @cython.cfunc
2294
+ def p_with_statement(s: PyrexScanner):
2295
+ s.next() # 'with'
2296
+ if s.systring == 'template' and not s.in_python_file:
2297
+ node = p_with_template(s)
2298
+ else:
2299
+ node = p_with_items(s)
2300
+ return node
2301
+
2302
+
2303
+ @cython.cfunc
2304
+ def p_with_items(s: PyrexScanner, is_async: cython.bint = False):
2305
+ """
2306
+ Copied from CPython:
2307
+ | 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' b=block {
2308
+ _PyAST_With(a, b, NULL, EXTRA) }
2309
+ | 'with' a[asdl_withitem_seq*]=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
2310
+ _PyAST_With(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2311
+ Therefore the first thing to try is the bracket-enclosed
2312
+ version and if that fails try the regular version
2313
+ """
2314
+ brackets_succeeded = False
2315
+ items = () # unused, but static analysis fails to track that below
2316
+ if s.sy == '(':
2317
+ with tentatively_scan(s) as errors:
2318
+ s.next()
2319
+ items = p_with_items_list(s, is_async)
2320
+ s.expect(")")
2321
+ if s.sy != ":":
2322
+ # Fail - the message doesn't matter because we'll try the
2323
+ # non-bracket version so it'll never be shown
2324
+ s.error("")
2325
+ brackets_succeeded = not errors
2326
+ if not brackets_succeeded:
2327
+ # try the non-bracket version
2328
+ items = p_with_items_list(s, is_async)
2329
+ body = p_suite(s)
2330
+ for cls, pos, kwds in reversed(items):
2331
+ # construct the actual nodes now that we know what the body is
2332
+ body = cls(pos, body=body, **kwds)
2333
+ return body
2334
+
2335
+
2336
+ @cython.cfunc
2337
+ def p_with_items_list(s: PyrexScanner, is_async: cython.bint) -> list[tuple]:
2338
+ items = []
2339
+ while True:
2340
+ items.append(p_with_item(s, is_async))
2341
+ if s.sy != ",":
2342
+ break
2343
+ s.next()
2344
+ if s.sy == ")":
2345
+ # trailing commas allowed
2346
+ break
2347
+ return items
2348
+
2349
+
2350
+ @cython.cfunc
2351
+ def p_with_item(s: PyrexScanner, is_async: cython.bint) -> tuple:
2352
+ # In contrast to most parsing functions, this returns a tuple of
2353
+ # class, pos, kwd_dict
2354
+ # This is because GILStatNode does a reasonable amount of initialization in its
2355
+ # constructor, and requires "body" to be set, which we don't currently have
2356
+ pos = s.position()
2357
+ if not s.in_python_file and s.sy == 'IDENT' and s.systring in ('nogil', 'gil'):
2358
+ if is_async:
2359
+ s.error("with gil/nogil cannot be async")
2360
+ state = s.systring
2361
+ s.next()
2362
+
2363
+ # support conditional gil/nogil
2364
+ condition = None
2365
+ if s.sy == '(':
2366
+ s.next()
2367
+ condition = p_test(s)
2368
+ s.expect(')')
2369
+
2370
+ return Nodes.GILStatNode, pos, {"state": state, "condition": condition}
2371
+ else:
2372
+ manager = p_test(s)
2373
+ target = None
2374
+ if s.sy == 'IDENT' and s.systring == 'as':
2375
+ s.next()
2376
+ target = p_starred_expr(s)
2377
+ return Nodes.WithStatNode, pos, {"manager": manager, "target": target, "is_async": is_async}
2378
+
2379
+
2380
+ @cython.cfunc
2381
+ def p_with_template(s: PyrexScanner):
2382
+ pos = s.position()
2383
+ templates = []
2384
+ s.next()
2385
+ s.expect('[')
2386
+ templates.append(s.systring)
2387
+ s.next()
2388
+ while s.systring == ',':
2389
+ s.next()
2390
+ templates.append(s.systring)
2391
+ s.next()
2392
+ s.expect(']')
2393
+ if s.sy == ':':
2394
+ s.next()
2395
+ s.expect_newline("Syntax error in template function declaration")
2396
+ s.expect_indent()
2397
+ body_ctx = Ctx()
2398
+ body_ctx.templates = templates
2399
+ func_or_var = p_c_func_or_var_declaration(s, pos, body_ctx)
2400
+ s.expect_dedent()
2401
+ return func_or_var
2402
+ else:
2403
+ error(pos, "Syntax error in template function declaration")
2404
+
2405
+
2406
+ @cython.cfunc
2407
+ def p_simple_statement(s: PyrexScanner, first_statement: cython.bint = 0):
2408
+ #print "p_simple_statement:", s.sy, s.systring ###
2409
+ if s.sy == 'global':
2410
+ node = p_global_statement(s)
2411
+ elif s.sy == 'nonlocal':
2412
+ node = p_nonlocal_statement(s)
2413
+ elif s.sy == 'print':
2414
+ node = p_print_statement(s)
2415
+ elif s.sy == 'exec':
2416
+ node = p_exec_statement(s)
2417
+ elif s.sy == 'del':
2418
+ node = p_del_statement(s)
2419
+ elif s.sy == 'break':
2420
+ node = p_break_statement(s)
2421
+ elif s.sy == 'continue':
2422
+ node = p_continue_statement(s)
2423
+ elif s.sy == 'return':
2424
+ node = p_return_statement(s)
2425
+ elif s.sy == 'raise':
2426
+ node = p_raise_statement(s)
2427
+ elif s.sy in ('import', 'cimport'):
2428
+ node = p_import_statement(s)
2429
+ elif s.sy == 'from':
2430
+ node = p_from_import_statement(s, first_statement = first_statement)
2431
+ elif s.sy == 'yield':
2432
+ node = p_yield_statement(s)
2433
+ elif s.sy == 'assert':
2434
+ node = p_assert_statement(s)
2435
+ elif s.sy == 'pass':
2436
+ node = p_pass_statement(s)
2437
+ else:
2438
+ node = p_expression_or_assignment(s)
2439
+ return node
2440
+
2441
+
2442
+ @cython.cfunc
2443
+ def p_simple_statement_list(s: PyrexScanner, ctx, first_statement: cython.bint = 0):
2444
+ # Parse a series of simple statements on one line
2445
+ # separated by semicolons.
2446
+ stat = p_simple_statement(s, first_statement = first_statement)
2447
+ pos = stat.pos
2448
+ stats = []
2449
+ if not isinstance(stat, Nodes.PassStatNode):
2450
+ stats.append(stat)
2451
+ while s.sy == ';':
2452
+ #print "p_simple_statement_list: maybe more to follow" ###
2453
+ s.next()
2454
+ if s.sy in ('NEWLINE', 'EOF'):
2455
+ break
2456
+ stat = p_simple_statement(s, first_statement = first_statement)
2457
+ if isinstance(stat, Nodes.PassStatNode):
2458
+ continue
2459
+ stats.append(stat)
2460
+ first_statement = False
2461
+
2462
+ if not stats:
2463
+ stat = Nodes.PassStatNode(pos)
2464
+ elif len(stats) == 1:
2465
+ stat = stats[0]
2466
+ else:
2467
+ stat = Nodes.StatListNode(pos, stats = stats)
2468
+
2469
+ if s.sy not in ('NEWLINE', 'EOF'):
2470
+ # provide a better error message for users who accidentally write Cython code in .py files
2471
+ if isinstance(stat, Nodes.ExprStatNode):
2472
+ if stat.expr.is_name and stat.expr.name == 'cdef':
2473
+ s.error("The 'cdef' keyword is only allowed in Cython files (pyx/pxi/pxd)", pos)
2474
+ s.expect_newline("Syntax error in simple statement list")
2475
+
2476
+ return stat
2477
+
2478
+
2479
+ @cython.cfunc
2480
+ def p_compile_time_expr(s: PyrexScanner):
2481
+ old = s.compile_time_expr
2482
+ s.compile_time_expr = 1
2483
+ expr = p_testlist(s)
2484
+ s.compile_time_expr = old
2485
+ return expr
2486
+
2487
+
2488
+ @cython.cfunc
2489
+ def p_DEF_statement(s: PyrexScanner):
2490
+ pos = s.position()
2491
+ denv = s.compile_time_env
2492
+ s.next() # 'DEF'
2493
+ name = p_ident(s)
2494
+ s.expect('=')
2495
+ expr = p_compile_time_expr(s)
2496
+ if s.compile_time_eval:
2497
+ value = expr.compile_time_value(denv)
2498
+ #print "p_DEF_statement: %s = %r" % (name, value) ###
2499
+ denv.declare(name, value)
2500
+ s.expect_newline("Expected a newline", ignore_semicolon=True)
2501
+ return Nodes.PassStatNode(pos)
2502
+
2503
+
2504
+ @cython.cfunc
2505
+ def p_IF_statement(s: PyrexScanner, ctx):
2506
+ pos = s.position()
2507
+ saved_eval = s.compile_time_eval
2508
+ current_eval = saved_eval
2509
+ denv = s.compile_time_env
2510
+ result = None
2511
+ while 1:
2512
+ s.next() # 'IF' or 'ELIF'
2513
+ expr = p_compile_time_expr(s)
2514
+ s.compile_time_eval = current_eval and bool(expr.compile_time_value(denv))
2515
+ body = p_suite(s, ctx)
2516
+ if s.compile_time_eval:
2517
+ result = body
2518
+ current_eval = 0
2519
+ if s.sy != 'ELIF':
2520
+ break
2521
+ if s.sy == 'ELSE':
2522
+ s.next()
2523
+ s.compile_time_eval = current_eval
2524
+ body = p_suite(s, ctx)
2525
+ if current_eval:
2526
+ result = body
2527
+ if not result:
2528
+ result = Nodes.PassStatNode(pos)
2529
+ s.compile_time_eval = saved_eval
2530
+ return result
2531
+
2532
+
2533
+ @cython.cfunc
2534
+ def p_statement(s: PyrexScanner, ctx, first_statement: cython.bint = False):
2535
+ cdef_flag: cython.bint = ctx.cdef_flag
2536
+ pos = s.position()
2537
+ decorators = None
2538
+ if s.sy == 'ctypedef':
2539
+ if ctx.level not in ('module', 'module_pxd'):
2540
+ s.error("ctypedef statement not allowed here")
2541
+ #if ctx.api:
2542
+ # error(pos, "'api' not allowed with 'ctypedef'")
2543
+ return p_ctypedef_statement(s, ctx)
2544
+ elif s.sy == 'DEF':
2545
+ # We used to dep-warn about this but removed the warning again since
2546
+ # we don't have a good answer yet for all use cases.
2547
+ if s.context.compiler_directives.get("warn.deprecated.DEF", False):
2548
+ warning(pos,
2549
+ "The 'DEF' statement will be removed in a future Cython version. "
2550
+ "Consider using global variables, constants, and in-place literals instead. "
2551
+ "See https://github.com/cython/cython/issues/4310", level=1)
2552
+ return p_DEF_statement(s)
2553
+ elif s.sy == 'IF':
2554
+ if s.context.compiler_directives.get("warn.deprecated.IF", True):
2555
+ warning(pos,
2556
+ "The 'IF' statement is deprecated and will be removed in a future Cython version. "
2557
+ "Consider using runtime conditions or C macros instead. "
2558
+ "See https://github.com/cython/cython/issues/4310", level=1)
2559
+ return p_IF_statement(s, ctx)
2560
+ elif s.sy == '@':
2561
+ if ctx.level not in ('module', 'class', 'c_class', 'function', 'property', 'module_pxd', 'c_class_pxd', 'other'):
2562
+ s.error('decorator not allowed here')
2563
+ s.level = ctx.level
2564
+ decorators = p_decorators(s)
2565
+ if not ctx.allow_struct_enum_decorator and s.sy not in ('def', 'cdef', 'cpdef', 'class', 'async'):
2566
+ if s.sy == 'IDENT' and s.systring == 'async':
2567
+ pass # handled below
2568
+ else:
2569
+ s.error("Decorators can only be followed by functions or classes")
2570
+ elif s.sy == 'pass' and cdef_flag:
2571
+ # empty cdef block
2572
+ return p_pass_statement(s, with_newline=True)
2573
+
2574
+ overridable = False
2575
+ if s.sy == 'cdef':
2576
+ cdef_flag = True
2577
+ s.next()
2578
+ elif s.sy == 'cpdef':
2579
+ cdef_flag = True
2580
+ overridable = True
2581
+ s.next()
2582
+ if cdef_flag:
2583
+ if ctx.level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'):
2584
+ s.error('cdef statement not allowed here')
2585
+ s.level = ctx.level
2586
+ node = p_cdef_statement(s, pos, ctx(overridable=overridable))
2587
+ if decorators is not None:
2588
+ tup = (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode)
2589
+ if ctx.allow_struct_enum_decorator:
2590
+ tup += (Nodes.CStructOrUnionDefNode, Nodes.CEnumDefNode)
2591
+ if not isinstance(node, tup):
2592
+ s.error("Decorators can only be followed by functions or classes")
2593
+ node.decorators = decorators
2594
+ return node
2595
+ else:
2596
+ if ctx.api:
2597
+ s.error("'api' not allowed with this statement", fatal=False)
2598
+ elif s.sy == 'def':
2599
+ # def statements aren't allowed in pxd files, except
2600
+ # as part of a cdef class
2601
+ if ('pxd' in ctx.level) and (ctx.level != 'c_class_pxd'):
2602
+ s.error('def statement not allowed here')
2603
+ s.level = ctx.level
2604
+ return p_def_statement(s, decorators)
2605
+ elif s.sy == 'class':
2606
+ if ctx.level not in ('module', 'function', 'class', 'other'):
2607
+ s.error("class definition not allowed here")
2608
+ return p_class_statement(s, decorators)
2609
+ elif s.sy == 'include':
2610
+ if ctx.level not in ('module', 'module_pxd'):
2611
+ s.error("include statement not allowed here")
2612
+ return p_include_statement(s, ctx)
2613
+ elif ctx.level == 'c_class' and s.sy == 'IDENT' and s.systring == 'property':
2614
+ return p_property_decl(s)
2615
+ elif s.sy == 'pass' and ctx.level != 'property':
2616
+ return p_pass_statement(s, with_newline=True)
2617
+ else:
2618
+ if ctx.level in ('c_class_pxd', 'property'):
2619
+ node = p_ignorable_statement(s)
2620
+ if node is not None:
2621
+ return node
2622
+ s.error("Executable statement not allowed here")
2623
+ if s.sy == 'if':
2624
+ return p_if_statement(s)
2625
+ elif s.sy == 'while':
2626
+ return p_while_statement(s)
2627
+ elif s.sy == 'for':
2628
+ return p_for_statement(s)
2629
+ elif s.sy == 'try':
2630
+ return p_try_statement(s)
2631
+ elif s.sy == 'with':
2632
+ return p_with_statement(s)
2633
+ elif s.sy == 'async':
2634
+ s.next()
2635
+ return p_async_statement(s, ctx, decorators)
2636
+ else:
2637
+ if s.sy == 'IDENT' and s.systring == 'async':
2638
+ ident_name = s.systring
2639
+ ident_pos = s.position()
2640
+ # PEP 492 enables the async/await keywords when it spots "async def ..."
2641
+ s.next()
2642
+ if s.sy == 'def':
2643
+ return p_async_statement(s, ctx, decorators)
2644
+ elif decorators:
2645
+ s.error("Decorators can only be followed by functions or classes")
2646
+ s.put_back('IDENT', ident_name, ident_pos) # re-insert original token
2647
+ if s.sy == 'IDENT' and s.systring == 'match':
2648
+ # p_match_statement returns None on a "soft" initial failure
2649
+ match_statement = p_match_statement(s, ctx)
2650
+ if match_statement is not None:
2651
+ return match_statement
2652
+ return p_simple_statement_list(s, ctx, first_statement=first_statement)
2653
+
2654
+
2655
+ @cython.cfunc
2656
+ def p_statement_list(s: PyrexScanner, ctx, first_statement: cython.bint = 0):
2657
+ # Parse a series of statements separated by newlines.
2658
+ pos = s.position()
2659
+ stats = []
2660
+ while s.sy not in ('DEDENT', 'EOF'):
2661
+ stat = p_statement(s, ctx, first_statement = first_statement)
2662
+ if isinstance(stat, Nodes.PassStatNode):
2663
+ continue
2664
+ stats.append(stat)
2665
+ first_statement = False
2666
+ if not stats:
2667
+ return Nodes.PassStatNode(pos)
2668
+ elif len(stats) == 1:
2669
+ return stats[0]
2670
+ else:
2671
+ return Nodes.StatListNode(pos, stats = stats)
2672
+
2673
+
2674
+ @cython.cfunc
2675
+ def p_suite(s: PyrexScanner, ctx=Ctx()):
2676
+ return p_suite_with_docstring(s, ctx, with_doc_only=False)[1]
2677
+
2678
+
2679
+ @cython.cfunc
2680
+ def p_suite_with_docstring(s: PyrexScanner, ctx, with_doc_only: cython.bint = False) -> tuple:
2681
+ s.expect(':')
2682
+ doc = None
2683
+ if s.sy == 'NEWLINE':
2684
+ s.next()
2685
+ s.expect_indent()
2686
+ if with_doc_only:
2687
+ doc = p_doc_string(s)
2688
+ body = p_statement_list(s, ctx)
2689
+ s.expect_dedent()
2690
+ else:
2691
+ if ctx.api:
2692
+ s.error("'api' not allowed with this statement", fatal=False)
2693
+ if ctx.level in ('module', 'class', 'function', 'other'):
2694
+ body = p_simple_statement_list(s, ctx)
2695
+ else:
2696
+ body = p_pass_statement(s)
2697
+ s.expect_newline("Syntax error in declarations", ignore_semicolon=True)
2698
+ if not with_doc_only:
2699
+ doc, body = _extract_docstring(body)
2700
+ return doc, body
2701
+
2702
+
2703
+ @cython.cfunc
2704
+ def p_positional_and_keyword_args(s: PyrexScanner, end_sy_set, templates = None) -> tuple[list, list]:
2705
+ """
2706
+ Parses positional and keyword arguments. end_sy_set
2707
+ should contain any s.sy that terminate the argument list.
2708
+ Argument expansion (* and **) are not allowed.
2709
+
2710
+ Returns: (positional_args, keyword_args)
2711
+ """
2712
+ positional_args = []
2713
+ keyword_args = []
2714
+ pos_idx = 0
2715
+
2716
+ while s.sy not in end_sy_set:
2717
+ if s.sy == '*' or s.sy == '**':
2718
+ s.error('Argument expansion not allowed here.', fatal=False)
2719
+
2720
+ parsed_type = False
2721
+ if s.sy == 'IDENT' and s.peek()[0] == '=':
2722
+ ident = s.systring
2723
+ s.next() # s.sy is '='
2724
+ s.next()
2725
+ if looking_at_expr(s):
2726
+ arg = p_test(s)
2727
+ else:
2728
+ base_type = p_c_base_type(s, templates = templates)
2729
+ declarator = p_c_declarator(s, empty=True)
2730
+ arg = Nodes.CComplexBaseTypeNode(base_type.pos,
2731
+ base_type = base_type, declarator = declarator)
2732
+ parsed_type = True
2733
+ keyword_node = ExprNodes.IdentifierStringNode(arg.pos, value=ident)
2734
+ keyword_args.append((keyword_node, arg))
2735
+ was_keyword = True
2736
+
2737
+ else:
2738
+ if looking_at_expr(s):
2739
+ arg = p_test(s)
2740
+ else:
2741
+ base_type = p_c_base_type(s, templates = templates)
2742
+ declarator = p_c_declarator(s, empty=True)
2743
+ arg = Nodes.CComplexBaseTypeNode(base_type.pos,
2744
+ base_type = base_type, declarator = declarator)
2745
+ parsed_type = True
2746
+ positional_args.append(arg)
2747
+ pos_idx += 1
2748
+ if len(keyword_args) > 0:
2749
+ s.error("Non-keyword arg following keyword arg",
2750
+ pos=arg.pos)
2751
+
2752
+ if s.sy != ',':
2753
+ if s.sy not in end_sy_set:
2754
+ if parsed_type:
2755
+ s.error("Unmatched %s" % " or ".join(end_sy_set))
2756
+ break
2757
+ s.next()
2758
+ return positional_args, keyword_args
2759
+
2760
+
2761
+ @cython.ccall
2762
+ def p_c_base_type(s: PyrexScanner, nonempty: cython.bint = False, templates=None):
2763
+ if s.sy == '(':
2764
+ return p_c_complex_base_type(s, templates = templates)
2765
+ else:
2766
+ return p_c_simple_base_type(s, nonempty=nonempty, templates=templates)
2767
+
2768
+
2769
+ @cython.cfunc
2770
+ def p_calling_convention(s: PyrexScanner):
2771
+ if s.sy == 'IDENT' and s.systring in calling_convention_words:
2772
+ result = s.systring
2773
+ s.next()
2774
+ return result
2775
+ else:
2776
+ return EncodedString("")
2777
+
2778
+
2779
+ calling_convention_words = cython.declare(frozenset, frozenset((
2780
+ "__stdcall", "__cdecl", "__fastcall")))
2781
+
2782
+
2783
+ @cython.cfunc
2784
+ def p_c_complex_base_type(s: PyrexScanner, templates = None):
2785
+ # s.sy == '('
2786
+ pos = s.position()
2787
+ s.next()
2788
+ base_type = p_c_base_type(s, templates=templates)
2789
+ declarator = p_c_declarator(s, empty=True)
2790
+ type_node = Nodes.CComplexBaseTypeNode(
2791
+ pos, base_type=base_type, declarator=declarator)
2792
+ if s.sy == ',':
2793
+ components = [type_node]
2794
+ while s.sy == ',':
2795
+ s.next()
2796
+ if s.sy == ')':
2797
+ break
2798
+ base_type = p_c_base_type(s, templates=templates)
2799
+ declarator = p_c_declarator(s, empty=True)
2800
+ components.append(Nodes.CComplexBaseTypeNode(
2801
+ pos, base_type=base_type, declarator=declarator))
2802
+ type_node = Nodes.CTupleBaseTypeNode(pos, components = components)
2803
+
2804
+ s.expect(')')
2805
+ if s.sy == '[':
2806
+ if is_memoryviewslice_access(s):
2807
+ type_node = p_memoryviewslice_access(s, type_node)
2808
+ else:
2809
+ type_node = p_buffer_or_template(s, type_node, templates)
2810
+ return type_node
2811
+
2812
+
2813
+ @cython.cfunc
2814
+ def p_c_simple_base_type(s: PyrexScanner, nonempty: cython.bint, templates=None):
2815
+ is_basic = False
2816
+ signed = 1
2817
+ longness = 0
2818
+ complex = False
2819
+ module_path = []
2820
+ pos = s.position()
2821
+
2822
+ # Handle const/volatile
2823
+ is_const = is_volatile = False
2824
+ while s.sy == 'IDENT':
2825
+ if s.systring == 'const':
2826
+ if is_const: error(pos, "Duplicate 'const'")
2827
+ is_const = True
2828
+ elif s.systring == 'volatile':
2829
+ if is_volatile: error(pos, "Duplicate 'volatile'")
2830
+ is_volatile = True
2831
+ else:
2832
+ break
2833
+ s.next()
2834
+ if is_const or is_volatile:
2835
+ base_type = p_c_base_type(s, nonempty=nonempty, templates=templates)
2836
+ if isinstance(base_type, Nodes.MemoryViewSliceTypeNode):
2837
+ # reverse order to avoid having to write "(const int)[:]"
2838
+ base_type.base_type_node = Nodes.CQualifierTypeNode(pos,
2839
+ base_type=base_type.base_type_node, is_const=is_const, is_volatile=is_volatile)
2840
+ return base_type
2841
+ return Nodes.CQualifierTypeNode(pos,
2842
+ base_type=base_type, is_const=is_const, is_volatile=is_volatile)
2843
+
2844
+ if s.sy != 'IDENT':
2845
+ error(pos, "Expected an identifier, found '%s'" % s.sy)
2846
+ if looking_at_base_type(s):
2847
+ #print "p_c_simple_base_type: looking_at_base_type at", s.position()
2848
+ is_basic = True
2849
+ if s.sy == 'IDENT' and s.systring in special_basic_c_types:
2850
+ signed, longness = special_basic_c_types[s.systring]
2851
+ name = s.systring
2852
+ s.next()
2853
+ else:
2854
+ signed, longness = p_sign_and_longness(s)
2855
+ if s.sy == 'IDENT' and s.systring in basic_c_type_names:
2856
+ name = s.systring
2857
+ s.next()
2858
+ else:
2859
+ name = 'int' # long [int], short [int], long [int] complex, etc.
2860
+ if s.sy == 'IDENT' and s.systring == 'complex':
2861
+ complex = True
2862
+ s.next()
2863
+ elif looking_at_dotted_name(s):
2864
+ #print "p_c_simple_base_type: looking_at_type_name at", s.position()
2865
+ name = s.systring
2866
+ s.next()
2867
+ while s.sy == '.':
2868
+ module_path.append(name)
2869
+ s.next()
2870
+ name = p_ident(s)
2871
+ else:
2872
+ name = s.systring
2873
+ name_pos = s.position()
2874
+ s.next()
2875
+ if nonempty and s.sy != 'IDENT':
2876
+ # Make sure this is not a declaration of a variable or function.
2877
+ if s.sy == '(':
2878
+ old_pos = s.position()
2879
+ s.next()
2880
+ if (s.sy == '*' or s.sy == '**' or s.sy == '&'
2881
+ or (s.sy == 'IDENT' and s.systring in calling_convention_words)):
2882
+ s.put_back('(', '(', old_pos)
2883
+ else:
2884
+ s.put_back('(', '(', old_pos)
2885
+ s.put_back('IDENT', name, name_pos)
2886
+ name = None
2887
+ elif s.sy not in ('*', '**', '[', '&'):
2888
+ s.put_back('IDENT', name, name_pos)
2889
+ name = None
2890
+
2891
+ type_node = Nodes.CSimpleBaseTypeNode(pos,
2892
+ name = name, module_path = module_path,
2893
+ is_basic_c_type = is_basic, signed = signed,
2894
+ complex = complex, longness = longness,
2895
+ templates = templates)
2896
+
2897
+ # declarations here.
2898
+ if s.sy == '[':
2899
+ if is_memoryviewslice_access(s):
2900
+ type_node = p_memoryviewslice_access(s, type_node)
2901
+ else:
2902
+ type_node = p_buffer_or_template(s, type_node, templates)
2903
+
2904
+ if s.sy == '.':
2905
+ s.next()
2906
+ name = p_ident(s)
2907
+ type_node = Nodes.CNestedBaseTypeNode(pos, base_type = type_node, name = name)
2908
+
2909
+ return type_node
2910
+
2911
+
2912
+ @cython.cfunc
2913
+ def p_buffer_or_template(s: PyrexScanner, base_type_node, templates):
2914
+ # s.sy == '['
2915
+ pos = s.position()
2916
+ s.next()
2917
+ # Note that buffer_positional_options_count=1, so the only positional argument is dtype.
2918
+ # For templated types, all parameters are types.
2919
+ positional_args, keyword_args = (
2920
+ p_positional_and_keyword_args(s, (']',), templates)
2921
+ )
2922
+ s.expect(']')
2923
+
2924
+ if s.sy == '[':
2925
+ base_type_node = p_buffer_or_template(s, base_type_node, templates)
2926
+
2927
+ keyword_dict = ExprNodes.DictNode(pos,
2928
+ key_value_pairs = [
2929
+ ExprNodes.DictItemNode(pos=key.pos, key=key, value=value)
2930
+ for key, value in keyword_args
2931
+ ])
2932
+ result = Nodes.TemplatedTypeNode(pos,
2933
+ positional_args = positional_args,
2934
+ keyword_args = keyword_dict,
2935
+ base_type_node = base_type_node)
2936
+ return result
2937
+
2938
+
2939
+ @cython.cfunc
2940
+ def is_memoryviewslice_access(s: PyrexScanner) -> cython.bint:
2941
+ # s.sy == '['
2942
+ # a memoryview slice declaration is distinguishable from a buffer access
2943
+ # declaration by the first entry in the bracketed list. The buffer will
2944
+ # not have an unnested colon in the first entry; the memoryview slice will.
2945
+ saved = [(s.sy, s.systring, s.position())]
2946
+ s.next()
2947
+ retval = False
2948
+ if s.systring == ':':
2949
+ retval = True
2950
+ elif s.sy == 'INT':
2951
+ saved.append((s.sy, s.systring, s.position()))
2952
+ s.next()
2953
+ if s.sy == ':':
2954
+ retval = True
2955
+
2956
+ for sv in saved[::-1]:
2957
+ s.put_back(*sv)
2958
+
2959
+ return retval
2960
+
2961
+
2962
+ @cython.cfunc
2963
+ def p_memoryviewslice_access(s: PyrexScanner, base_type_node):
2964
+ # s.sy == '['
2965
+ pos = s.position()
2966
+ s.next()
2967
+ subscripts, _ = p_subscript_list(s)
2968
+ # make sure each entry in subscripts is a slice
2969
+ for subscript in subscripts:
2970
+ if len(subscript) < 2:
2971
+ s.error("An axis specification in memoryview declaration does not have a ':'.")
2972
+ s.expect(']')
2973
+ indexes = make_slice_nodes(pos, subscripts)
2974
+ result = Nodes.MemoryViewSliceTypeNode(pos,
2975
+ base_type_node = base_type_node,
2976
+ axes = indexes)
2977
+ return result
2978
+
2979
+
2980
+ @cython.cfunc
2981
+ def looking_at_name(s: PyrexScanner) -> cython.bint:
2982
+ return s.sy == 'IDENT' and s.systring not in calling_convention_words
2983
+
2984
+
2985
+ @cython.cfunc
2986
+ def looking_at_expr(s: PyrexScanner) -> cython.bint:
2987
+ if s.systring in base_type_start_words:
2988
+ return False
2989
+ elif s.sy == 'IDENT':
2990
+ is_type = False
2991
+ name = s.systring
2992
+ name_pos = s.position()
2993
+ dotted_path = []
2994
+ s.next()
2995
+
2996
+ while s.sy == '.':
2997
+ s.next()
2998
+ dotted_path.append((s.systring, s.position()))
2999
+ s.expect('IDENT')
3000
+
3001
+ saved = s.sy, s.systring, s.position()
3002
+ if s.sy == 'IDENT':
3003
+ is_type = True
3004
+ elif s.sy == '*' or s.sy == '**':
3005
+ s.next()
3006
+ is_type = s.sy in (')', ']')
3007
+ s.put_back(*saved)
3008
+ elif s.sy == '(':
3009
+ s.next()
3010
+ is_type = s.sy == '*'
3011
+ s.put_back(*saved)
3012
+ elif s.sy == '[':
3013
+ s.next()
3014
+ is_type = s.sy == ']' or not looking_at_expr(s) # could be a nested template type
3015
+ s.put_back(*saved)
3016
+
3017
+ dotted_path.reverse()
3018
+ for p in dotted_path:
3019
+ s.put_back('IDENT', *p)
3020
+ s.put_back('.', '.', p[1]) # gets the position slightly wrong
3021
+
3022
+ s.put_back('IDENT', name, name_pos)
3023
+ return not is_type and saved[0]
3024
+ else:
3025
+ return True
3026
+
3027
+
3028
+ @cython.cfunc
3029
+ def looking_at_base_type(s: PyrexScanner) -> cython.bint:
3030
+ #print "looking_at_base_type?", s.sy, s.systring, s.position()
3031
+ return s.sy == 'IDENT' and s.systring in base_type_start_words
3032
+
3033
+
3034
+ @cython.cfunc
3035
+ def looking_at_dotted_name(s: PyrexScanner) -> cython.bint:
3036
+ if s.sy == 'IDENT':
3037
+ name = s.systring
3038
+ name_pos = s.position()
3039
+ s.next()
3040
+ result: cython.bint = s.sy == '.'
3041
+ s.put_back('IDENT', name, name_pos)
3042
+ return result
3043
+ else:
3044
+ return False
3045
+
3046
+
3047
+ basic_c_type_names = cython.declare(frozenset, frozenset((
3048
+ "void", "char", "int", "float", "double", "bint")))
3049
+
3050
+ special_basic_c_types = cython.declare(dict, {
3051
+ # name : (signed, longness)
3052
+ "Py_UNICODE" : (0, 0),
3053
+ "Py_UCS4" : (0, 0),
3054
+ "Py_hash_t" : (2, 0),
3055
+ "Py_ssize_t" : (2, 0),
3056
+ "ssize_t" : (2, 0),
3057
+ "size_t" : (0, 0),
3058
+ "ptrdiff_t" : (2, 0),
3059
+ "Py_tss_t" : (1, 0),
3060
+ })
3061
+
3062
+ sign_and_longness_words = cython.declare(frozenset, frozenset((
3063
+ "short", "long", "signed", "unsigned")))
3064
+
3065
+ base_type_start_words = cython.declare(
3066
+ frozenset,
3067
+ basic_c_type_names
3068
+ | sign_and_longness_words
3069
+ | frozenset(special_basic_c_types))
3070
+
3071
+ struct_enum_union = cython.declare(frozenset, frozenset((
3072
+ "struct", "union", "enum", "packed")))
3073
+
3074
+
3075
+ @cython.cfunc
3076
+ def p_sign_and_longness(s: PyrexScanner) -> tuple[cython.int, cython.long]:
3077
+ signed: cython.int = 1
3078
+ longness: cython.long = 0
3079
+ while s.sy == 'IDENT' and s.systring in sign_and_longness_words:
3080
+ if s.systring == 'unsigned':
3081
+ signed = 0
3082
+ elif s.systring == 'signed':
3083
+ signed = 2
3084
+ elif s.systring == 'short':
3085
+ longness = -1
3086
+ elif s.systring == 'long':
3087
+ longness += 1
3088
+ s.next()
3089
+ return signed, longness
3090
+
3091
+
3092
+ @cython.cfunc
3093
+ def p_opt_cname(s: PyrexScanner):
3094
+ literal = p_opt_string_literal(s, 'u')
3095
+ if literal is not None:
3096
+ cname = EncodedString(literal)
3097
+ cname.encoding = s.source_encoding
3098
+ else:
3099
+ cname = None
3100
+ return cname
3101
+
3102
+
3103
+ @cython.ccall
3104
+ def p_c_declarator(s: PyrexScanner, ctx = Ctx(),
3105
+ empty: cython.bint = False, is_type: cython.bint = False, cmethod_flag: cython.bint = False,
3106
+ assignable: cython.bint = False, nonempty: cython.bint = False,
3107
+ calling_convention_allowed: cython.bint = False):
3108
+ # If empty is true, the declarator must be empty. If nonempty is true,
3109
+ # the declarator must be nonempty. Otherwise we don't care.
3110
+ # If cmethod_flag is true, then if this declarator declares
3111
+ # a function, it's a C method of an extension type.
3112
+ pos = s.position()
3113
+ if s.sy == '(':
3114
+ s.next()
3115
+ if s.sy == ')' or looking_at_name(s):
3116
+ base = Nodes.CNameDeclaratorNode(pos, name=s.context.intern_ustring(""), cname=None)
3117
+ result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag)
3118
+ else:
3119
+ result = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
3120
+ cmethod_flag = cmethod_flag,
3121
+ nonempty = nonempty,
3122
+ calling_convention_allowed = True)
3123
+ s.expect(')')
3124
+ else:
3125
+ result = p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
3126
+ assignable, nonempty)
3127
+ if not calling_convention_allowed and result.calling_convention and s.sy != '(':
3128
+ error(s.position(), "%s on something that is not a function"
3129
+ % result.calling_convention)
3130
+ while s.sy in ('[', '('):
3131
+ pos = s.position()
3132
+ if s.sy == '[':
3133
+ result = p_c_array_declarator(s, result)
3134
+ else: # sy == '('
3135
+ s.next()
3136
+ result = p_c_func_declarator(s, pos, ctx, result, cmethod_flag)
3137
+ cmethod_flag = 0
3138
+ return result
3139
+
3140
+
3141
+ @cython.cfunc
3142
+ def p_c_array_declarator(s: PyrexScanner, base):
3143
+ pos = s.position()
3144
+ s.next() # '['
3145
+ if s.sy != ']':
3146
+ dim = p_testlist(s)
3147
+ else:
3148
+ dim = None
3149
+ s.expect(']')
3150
+ return Nodes.CArrayDeclaratorNode(pos, base = base, dimension = dim)
3151
+
3152
+
3153
+ @cython.cfunc
3154
+ def p_c_func_declarator(s: PyrexScanner, pos, ctx, base, cmethod_flag: cython.bint):
3155
+ # Opening paren has already been skipped
3156
+ args = p_c_arg_list(s, ctx, cmethod_flag = cmethod_flag,
3157
+ nonempty_declarators = 0)
3158
+ ellipsis = p_optional_ellipsis(s)
3159
+ s.expect(')')
3160
+ nogil = p_nogil(s)
3161
+ exc_val, exc_check, exc_clause = p_exception_value_clause(s, ctx.visibility == 'extern')
3162
+ if nogil and exc_clause:
3163
+ warning(
3164
+ s.position(),
3165
+ "The keyword 'nogil' should appear at the end of the "
3166
+ "function signature line. Placing it before 'except' "
3167
+ "or 'noexcept' will be disallowed in a future version "
3168
+ "of Cython.",
3169
+ level=2
3170
+ )
3171
+ nogil = nogil or p_nogil(s)
3172
+ with_gil = p_with_gil(s)
3173
+ return Nodes.CFuncDeclaratorNode(pos,
3174
+ base = base, args = args, has_varargs = ellipsis,
3175
+ exception_value = exc_val, exception_check = exc_check,
3176
+ nogil = nogil or ctx.nogil or with_gil, with_gil = with_gil, has_explicit_exc_clause=exc_clause)
3177
+
3178
+
3179
+ supported_overloaded_operators = cython.declare(frozenset, frozenset((
3180
+ '+', '-', '*', '/', '%',
3181
+ '++', '--', '~', '|', '&', '^', '<<', '>>', ',',
3182
+ '==', '!=', '>=', '>', '<=', '<',
3183
+ '[]', '()', '!', '=',
3184
+ 'bool',
3185
+ )))
3186
+
3187
+
3188
+ @cython.cfunc
3189
+ def p_c_simple_declarator(s: PyrexScanner, ctx,
3190
+ empty: cython.bint, is_type: cython.bint, cmethod_flag: cython.bint,
3191
+ assignable: cython.bint, nonempty: cython.bint):
3192
+ pos = s.position()
3193
+ calling_convention = p_calling_convention(s)
3194
+ if s.sy in ('*', '**'):
3195
+ # scanner returns '**' as a single token
3196
+ is_ptrptr = s.sy == '**'
3197
+ s.next()
3198
+
3199
+ const_pos = s.position()
3200
+ is_restrict = is_const = False
3201
+ while s.sy == 'IDENT':
3202
+ if s.systring == 'const':
3203
+ if is_const: error(pos, "Duplicate 'const'")
3204
+ is_const = True
3205
+ elif s.systring == 'restrict':
3206
+ if is_restrict: error(pos, "Duplicate 'restrict'")
3207
+ is_restrict = True
3208
+ else:
3209
+ break
3210
+ s.next()
3211
+
3212
+ base = p_c_declarator(s, ctx, empty=empty, is_type=is_type,
3213
+ cmethod_flag=cmethod_flag,
3214
+ assignable=assignable, nonempty=nonempty)
3215
+ if is_const or is_restrict:
3216
+ base = Nodes.CQualifierDeclaratorNode(const_pos, base=base, is_const=is_const, is_restrict=is_restrict)
3217
+ if is_ptrptr:
3218
+ base = Nodes.CPtrDeclaratorNode(pos, base=base)
3219
+ result = Nodes.CPtrDeclaratorNode(pos, base=base)
3220
+ elif s.sy == '&' or (s.sy == '&&' and s.context.cpp):
3221
+ node_class = Nodes.CppRvalueReferenceDeclaratorNode if s.sy == '&&' else Nodes.CReferenceDeclaratorNode
3222
+ s.next()
3223
+ base = p_c_declarator(s, ctx, empty=empty, is_type=is_type,
3224
+ cmethod_flag=cmethod_flag,
3225
+ assignable=assignable, nonempty=nonempty)
3226
+ result = node_class(pos, base=base)
3227
+ else:
3228
+ rhs = None
3229
+ if s.sy == 'IDENT':
3230
+ name = s.systring
3231
+ if empty:
3232
+ error(s.position(), "Declarator should be empty")
3233
+ s.next()
3234
+ cname = p_opt_cname(s)
3235
+ if name != 'operator' and s.sy == '=' and assignable:
3236
+ s.next()
3237
+ rhs = p_test(s)
3238
+ else:
3239
+ if nonempty:
3240
+ error(s.position(), "Empty declarator")
3241
+ name = ""
3242
+ cname = None
3243
+ if cname is None and ctx.namespace is not None and nonempty:
3244
+ cname = ctx.namespace + "::" + name
3245
+ if name == 'operator' and ctx.visibility == 'extern' and nonempty:
3246
+ op = s.sy
3247
+ if [1 for c in op if c in '+-*/<=>!%&|([^~,']:
3248
+ s.next()
3249
+ # Handle diphthong operators.
3250
+ if op == '(':
3251
+ s.expect(')')
3252
+ op = '()'
3253
+ elif op == '[':
3254
+ s.expect(']')
3255
+ op = '[]'
3256
+ elif op in ('-', '+', '|', '&') and s.sy == op:
3257
+ op *= 2 # ++, --, ...
3258
+ s.next()
3259
+ elif s.sy == '=':
3260
+ op += s.sy # +=, -=, ...
3261
+ s.next()
3262
+ if op not in supported_overloaded_operators:
3263
+ s.error("Overloading operator '%s' not yet supported." % op,
3264
+ fatal=False)
3265
+ name += op
3266
+ elif op == 'IDENT':
3267
+ op = s.systring
3268
+ if op not in supported_overloaded_operators:
3269
+ s.error("Overloading operator '%s' not yet supported." % op,
3270
+ fatal=False)
3271
+ name = name + ' ' + op
3272
+ s.next()
3273
+ result = Nodes.CNameDeclaratorNode(pos,
3274
+ name = name, cname = cname, default = rhs)
3275
+ result.calling_convention = calling_convention
3276
+ return result
3277
+
3278
+
3279
+ @cython.cfunc
3280
+ def p_nogil(s: PyrexScanner) -> cython.bint:
3281
+ if s.sy == 'IDENT' and s.systring == 'nogil':
3282
+ s.next()
3283
+ return True
3284
+ else:
3285
+ return False
3286
+
3287
+
3288
+ @cython.cfunc
3289
+ def p_with_gil(s: PyrexScanner) -> cython.bint:
3290
+ if s.sy == 'with':
3291
+ s.next()
3292
+ s.expect_keyword('gil')
3293
+ return True
3294
+ else:
3295
+ return False
3296
+
3297
+
3298
+ @cython.cfunc
3299
+ def p_exception_value_clause(s: PyrexScanner, is_extern: cython.bint) -> tuple:
3300
+ """
3301
+ Parse exception value clause.
3302
+
3303
+ Maps clauses to exc_check / exc_value / exc_clause as follows:
3304
+ ______________________________________________________________________
3305
+ | | | | |
3306
+ | Clause | exc_check | exc_value | exc_clause |
3307
+ | ___________________________ | ___________ | ___________ | __________ |
3308
+ | | | | |
3309
+ | <nothing> (default func.) | True | None | False |
3310
+ | <nothing> (cdef extern) | False | None | False |
3311
+ | noexcept | False | None | True |
3312
+ | except <val> | False | <val> | True |
3313
+ | except? <val> | True | <val> | True |
3314
+ | except * | True | None | True |
3315
+ | except + | '+' | None | True |
3316
+ | except +* | '+' | '*' | True |
3317
+ | except +<PyErr> | '+' | <PyErr> | True |
3318
+ | ___________________________ | ___________ | ___________ | __________ |
3319
+
3320
+ Note that the only reason we need `exc_clause` is to raise a
3321
+ warning when `'except'` or `'noexcept'` is placed after the
3322
+ `'nogil'` keyword.
3323
+ """
3324
+ exc_clause: cython.bint = False
3325
+ exc_val = None
3326
+ exc_check = False if is_extern else True
3327
+
3328
+ if s.sy == 'IDENT' and s.systring == 'noexcept':
3329
+ exc_clause = True
3330
+ s.next()
3331
+ exc_check = False
3332
+ elif s.sy == 'except':
3333
+ exc_clause = True
3334
+ s.next()
3335
+ if s.sy == '*':
3336
+ exc_check = True
3337
+ s.next()
3338
+ elif s.sy == '+':
3339
+ exc_check = '+'
3340
+ plus_char_pos = s.position()[2]
3341
+ s.next()
3342
+ if s.sy == 'IDENT':
3343
+ name = s.systring
3344
+ if name == 'nogil':
3345
+ if s.position()[2] == plus_char_pos + 1:
3346
+ error(s.position(),
3347
+ "'except +nogil' defines an exception handling function. Use 'except + nogil' for the 'nogil' modifier.")
3348
+ # 'except + nogil' is parsed outside
3349
+ else:
3350
+ exc_val = p_name(s, name)
3351
+ s.next()
3352
+ elif s.sy == '*':
3353
+ exc_val = ExprNodes.CharNode(s.position(), value='*')
3354
+ s.next()
3355
+ else:
3356
+ if s.sy == '?':
3357
+ exc_check = True
3358
+ s.next()
3359
+ else:
3360
+ exc_check = False
3361
+ # exc_val can be non-None even if exc_check is False, c.f. "except -1"
3362
+ exc_val = p_test(s)
3363
+
3364
+ return exc_val, exc_check, exc_clause
3365
+
3366
+
3367
+ c_arg_list_terminators = cython.declare(frozenset, frozenset((
3368
+ '*', '**', '...', ')', ':', '/')))
3369
+
3370
+
3371
+ @cython.ccall
3372
+ def p_c_arg_list(s: PyrexScanner, ctx = Ctx(),
3373
+ in_pyfunc: cython.bint = False, cmethod_flag: cython.bint = False,
3374
+ nonempty_declarators: cython.bint = False, kw_only: cython.bint = False,
3375
+ annotated: cython.bint = True) -> list:
3376
+ # Comma-separated list of C argument declarations, possibly empty.
3377
+ # May have a trailing comma.
3378
+ args = []
3379
+ is_self_arg = cmethod_flag
3380
+ while s.sy not in c_arg_list_terminators:
3381
+ args.append(p_c_arg_decl(s, ctx, in_pyfunc, is_self_arg,
3382
+ nonempty = nonempty_declarators, kw_only = kw_only,
3383
+ annotated = annotated))
3384
+ if s.sy != ',':
3385
+ break
3386
+ s.next()
3387
+ is_self_arg = 0
3388
+ return args
3389
+
3390
+
3391
+ @cython.cfunc
3392
+ def p_optional_ellipsis(s: PyrexScanner) -> cython.bint:
3393
+ if s.sy == '...':
3394
+ expect_ellipsis(s)
3395
+ return True
3396
+ else:
3397
+ return False
3398
+
3399
+
3400
+ @cython.cfunc
3401
+ def p_c_arg_decl(s: PyrexScanner, ctx, in_pyfunc: cython.bint, cmethod_flag: cython.bint = False,
3402
+ nonempty: cython.bint = False,
3403
+ kw_only: cython.bint = False, annotated: cython.bint = True):
3404
+ pos = s.position()
3405
+ not_none = or_none = False
3406
+ default = None
3407
+ annotation = None
3408
+ if s.in_python_file:
3409
+ # empty type declaration
3410
+ base_type = Nodes.CSimpleBaseTypeNode(pos,
3411
+ name = None, module_path = [],
3412
+ is_basic_c_type = False, signed = 0,
3413
+ complex = False, longness = 0,
3414
+ is_self_arg = cmethod_flag, templates = None)
3415
+ else:
3416
+ base_type = p_c_base_type(s, nonempty=nonempty)
3417
+ declarator = p_c_declarator(s, ctx, nonempty = nonempty)
3418
+ if s.sy in ('not', 'or') and not s.in_python_file:
3419
+ kind = s.sy
3420
+ s.next()
3421
+ if s.sy == 'IDENT' and s.systring == 'None':
3422
+ s.next()
3423
+ else:
3424
+ s.error("Expected 'None'")
3425
+ if not in_pyfunc:
3426
+ error(pos, "'%s None' only allowed in Python functions" % kind)
3427
+ or_none = kind == 'or'
3428
+ not_none = kind == 'not'
3429
+ if annotated and s.sy == ':':
3430
+ s.next()
3431
+ annotation = p_annotation(s)
3432
+ if s.sy == '=':
3433
+ s.next()
3434
+ if 'pxd' in ctx.level:
3435
+ if s.sy in ['*', '?']:
3436
+ # TODO(github/1736): Make this an error for inline declarations.
3437
+ default = ExprNodes.NoneNode(pos)
3438
+ s.next()
3439
+ elif 'inline' in ctx.modifiers:
3440
+ default = p_test(s)
3441
+ else:
3442
+ error(pos, "default values cannot be specified in pxd files, use ? or *")
3443
+ else:
3444
+ default = p_test(s)
3445
+ return Nodes.CArgDeclNode(pos,
3446
+ base_type = base_type,
3447
+ declarator = declarator,
3448
+ not_none = not_none,
3449
+ or_none = or_none,
3450
+ default = default,
3451
+ annotation = annotation,
3452
+ kw_only = kw_only)
3453
+
3454
+
3455
+ @cython.cfunc
3456
+ def p_annotation(s: PyrexScanner):
3457
+ """An annotation just has the "test" syntax, but also stores the string it came from
3458
+
3459
+ Note that the string is *allowed* to be changed/processed (although isn't here)
3460
+ so may not exactly match the string generated by Python, and if it doesn't
3461
+ then it is not a bug.
3462
+ """
3463
+ pos = s.position()
3464
+ expr = p_test(s)
3465
+ return ExprNodes.AnnotationNode(pos, expr=expr)
3466
+
3467
+
3468
+ @cython.cfunc
3469
+ def p_api(s: PyrexScanner) -> cython.bint:
3470
+ if s.sy == 'IDENT' and s.systring == 'api':
3471
+ s.next()
3472
+ return True
3473
+ else:
3474
+ return False
3475
+
3476
+
3477
+ @cython.cfunc
3478
+ def p_cdef_statement(s: PyrexScanner, pos, ctx):
3479
+ ctx.visibility = p_visibility(s, ctx.visibility)
3480
+ ctx.api = ctx.api or p_api(s)
3481
+ if ctx.api:
3482
+ if ctx.visibility not in ('private', 'public'):
3483
+ error(pos, "Cannot combine 'api' with '%s'" % ctx.visibility)
3484
+ if (ctx.visibility == 'extern') and s.sy == 'from':
3485
+ return p_cdef_extern_block(s, pos, ctx)
3486
+ elif s.sy == 'import':
3487
+ s.next()
3488
+ return p_cdef_extern_block(s, pos, ctx)
3489
+ elif p_nogil(s):
3490
+ ctx.nogil = True
3491
+ if ctx.overridable:
3492
+ error(pos, "cdef blocks cannot be declared cpdef")
3493
+ return p_cdef_block(s, ctx)
3494
+ elif s.sy == ':':
3495
+ if ctx.overridable:
3496
+ error(pos, "cdef blocks cannot be declared cpdef")
3497
+ return p_cdef_block(s, ctx)
3498
+ elif s.sy == 'class':
3499
+ if ctx.level not in ('module', 'module_pxd'):
3500
+ error(pos, "Extension type definition not allowed here")
3501
+ if ctx.overridable:
3502
+ error(pos, "Extension types cannot be declared cpdef")
3503
+ return p_c_class_definition(s, pos, ctx)
3504
+ elif s.sy == 'IDENT' and s.systring == 'cppclass':
3505
+ return p_cpp_class_definition(s, pos, ctx)
3506
+ elif s.sy == 'IDENT' and s.systring in struct_enum_union:
3507
+ if ctx.level not in ('module', 'module_pxd'):
3508
+ error(pos, "C struct/union/enum definition not allowed here")
3509
+ if ctx.overridable:
3510
+ if s.systring != 'enum':
3511
+ error(pos, "C struct/union cannot be declared cpdef")
3512
+ return p_struct_enum(s, pos, ctx)
3513
+ elif s.sy == 'IDENT' and s.systring == 'fused':
3514
+ return p_fused_definition(s, pos, ctx)
3515
+ else:
3516
+ return p_c_func_or_var_declaration(s, pos, ctx)
3517
+
3518
+
3519
+ @cython.cfunc
3520
+ def p_cdef_block(s: PyrexScanner, ctx):
3521
+ return p_suite(s, ctx(cdef_flag = True))
3522
+
3523
+
3524
+ @cython.cfunc
3525
+ def p_cdef_extern_block(s: PyrexScanner, pos, ctx):
3526
+ if ctx.overridable:
3527
+ error(pos, "cdef extern blocks cannot be declared cpdef")
3528
+ include_file = None
3529
+ s.expect('from')
3530
+ if s.sy == '*':
3531
+ s.next()
3532
+ else:
3533
+ include_file = p_string_literal(s, 'u')[2]
3534
+ ctx = ctx(cdef_flag = True, visibility = 'extern')
3535
+ if s.systring == "namespace":
3536
+ s.next()
3537
+ ctx.namespace = p_string_literal(s, 'u')[2]
3538
+ if p_nogil(s):
3539
+ ctx.nogil = True
3540
+
3541
+ # Use "docstring" as verbatim string to include
3542
+ verbatim_include, body = p_suite_with_docstring(s, ctx, True)
3543
+
3544
+ return Nodes.CDefExternNode(pos,
3545
+ include_file = include_file,
3546
+ verbatim_include = verbatim_include,
3547
+ body = body,
3548
+ namespace = ctx.namespace)
3549
+
3550
+
3551
+ @cython.cfunc
3552
+ def p_c_enum_definition(s: PyrexScanner, pos, ctx):
3553
+ # s.sy == ident 'enum'
3554
+ s.next()
3555
+
3556
+ scoped = False
3557
+ if s.context.cpp and (s.sy == 'class' or (s.sy == 'IDENT' and s.systring == 'struct')):
3558
+ scoped = True
3559
+ s.next()
3560
+
3561
+ if s.sy == 'IDENT':
3562
+ name = s.systring
3563
+ s.next()
3564
+ cname = p_opt_cname(s)
3565
+ if cname is None and ctx.namespace is not None:
3566
+ cname = ctx.namespace + "::" + name
3567
+ else:
3568
+ name = cname = None
3569
+ if scoped:
3570
+ s.error("Unnamed scoped enum not allowed")
3571
+
3572
+ if scoped and s.sy == '(':
3573
+ s.next()
3574
+ underlying_type = p_c_base_type(s)
3575
+ s.expect(')')
3576
+ else:
3577
+ underlying_type = Nodes.CSimpleBaseTypeNode(
3578
+ pos,
3579
+ name="int",
3580
+ module_path = [],
3581
+ is_basic_c_type = True,
3582
+ signed = 1,
3583
+ complex = False,
3584
+ longness = 0
3585
+ )
3586
+
3587
+ s.expect(':')
3588
+ items = []
3589
+
3590
+ doc = None
3591
+ if s.sy != 'NEWLINE':
3592
+ p_c_enum_line(s, ctx, items)
3593
+ else:
3594
+ s.next() # 'NEWLINE'
3595
+ s.expect_indent()
3596
+ doc = p_doc_string(s)
3597
+
3598
+ while s.sy not in ('DEDENT', 'EOF'):
3599
+ p_c_enum_line(s, ctx, items)
3600
+
3601
+ s.expect_dedent()
3602
+
3603
+ if not items and ctx.visibility != "extern":
3604
+ error(pos, "Empty enum definition not allowed outside a 'cdef extern from' block")
3605
+
3606
+ return Nodes.CEnumDefNode(
3607
+ pos, name=name, cname=cname,
3608
+ scoped=scoped, items=items,
3609
+ underlying_type=underlying_type,
3610
+ typedef_flag=ctx.typedef_flag, visibility=ctx.visibility,
3611
+ create_wrapper=ctx.overridable,
3612
+ api=ctx.api, in_pxd=ctx.level == 'module_pxd', doc=doc)
3613
+
3614
+
3615
+ @cython.cfunc
3616
+ def p_c_enum_line(s: PyrexScanner, ctx, items: list):
3617
+ if s.sy != 'pass':
3618
+ p_c_enum_item(s, ctx, items)
3619
+ while s.sy == ',':
3620
+ s.next()
3621
+ if s.sy in ('NEWLINE', 'EOF'):
3622
+ break
3623
+ p_c_enum_item(s, ctx, items)
3624
+ else:
3625
+ s.next()
3626
+ s.expect_newline("Syntax error in enum item list")
3627
+
3628
+
3629
+ @cython.cfunc
3630
+ def p_c_enum_item(s: PyrexScanner, ctx, items: list):
3631
+ pos = s.position()
3632
+ name = p_ident(s)
3633
+ cname = p_opt_cname(s)
3634
+ if cname is None and ctx.namespace is not None:
3635
+ cname = ctx.namespace + "::" + name
3636
+ value = None
3637
+ if s.sy == '=':
3638
+ s.next()
3639
+ value = p_test(s)
3640
+ items.append(Nodes.CEnumDefItemNode(pos,
3641
+ name = name, cname = cname, value = value))
3642
+
3643
+
3644
+ @cython.cfunc
3645
+ def p_c_struct_or_union_definition(s: PyrexScanner, pos, ctx):
3646
+ packed = False
3647
+ if s.systring == 'packed':
3648
+ packed = True
3649
+ s.next()
3650
+ if s.sy != 'IDENT' or s.systring != 'struct':
3651
+ s.expected('struct')
3652
+ # s.sy == ident 'struct' or 'union'
3653
+ kind = s.systring
3654
+ s.next()
3655
+ name = p_ident(s)
3656
+ cname = p_opt_cname(s)
3657
+ if cname is None and ctx.namespace is not None:
3658
+ cname = ctx.namespace + "::" + name
3659
+ attributes = None
3660
+ if s.sy == ':':
3661
+ s.next()
3662
+ attributes = []
3663
+ if s.sy == 'pass':
3664
+ s.next()
3665
+ s.expect_newline("Expected a newline", ignore_semicolon=True)
3666
+ else:
3667
+ s.expect('NEWLINE')
3668
+ s.expect_indent()
3669
+ body_ctx = Ctx(visibility=ctx.visibility)
3670
+ while s.sy != 'DEDENT':
3671
+ if s.sy != 'pass':
3672
+ attributes.append(
3673
+ p_c_func_or_var_declaration(s, s.position(), body_ctx))
3674
+ else:
3675
+ s.next()
3676
+ s.expect_newline("Expected a newline")
3677
+ s.expect_dedent()
3678
+
3679
+ if not attributes and ctx.visibility != "extern":
3680
+ error(pos, "Empty struct or union definition not allowed outside a 'cdef extern from' block")
3681
+ else:
3682
+ s.expect_newline("Syntax error in struct or union definition")
3683
+
3684
+ return Nodes.CStructOrUnionDefNode(pos,
3685
+ name = name, cname = cname, kind = kind, attributes = attributes,
3686
+ typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
3687
+ api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
3688
+
3689
+
3690
+ @cython.cfunc
3691
+ def p_fused_definition(s: PyrexScanner, pos, ctx):
3692
+ """
3693
+ c(type)def fused my_fused_type:
3694
+ ...
3695
+ """
3696
+ # s.systring == 'fused'
3697
+
3698
+ if ctx.level not in ('module', 'module_pxd'):
3699
+ error(pos, "Fused type definition not allowed here")
3700
+
3701
+ s.next()
3702
+ name = p_ident(s)
3703
+
3704
+ s.expect(":")
3705
+ s.expect_newline()
3706
+ s.expect_indent()
3707
+
3708
+ types = []
3709
+ while s.sy != 'DEDENT':
3710
+ if s.sy != 'pass':
3711
+ #types.append(p_c_declarator(s))
3712
+ types.append(p_c_base_type(s)) #, nonempty=1))
3713
+ else:
3714
+ s.next()
3715
+
3716
+ s.expect_newline()
3717
+
3718
+ s.expect_dedent()
3719
+
3720
+ if not types:
3721
+ error(pos, "Need at least one type")
3722
+
3723
+ return Nodes.FusedTypeNode(pos, name=name, types=types)
3724
+
3725
+
3726
+ @cython.cfunc
3727
+ def p_struct_enum(s: PyrexScanner, pos, ctx):
3728
+ if s.systring == 'enum':
3729
+ return p_c_enum_definition(s, pos, ctx)
3730
+ else:
3731
+ return p_c_struct_or_union_definition(s, pos, ctx)
3732
+
3733
+
3734
+ @cython.cfunc
3735
+ def p_visibility(s: PyrexScanner, prev_visibility):
3736
+ visibility = prev_visibility
3737
+ if s.sy == 'IDENT' and s.systring in ('extern', 'public', 'readonly'):
3738
+ visibility = s.systring
3739
+ if prev_visibility != 'private' and visibility != prev_visibility:
3740
+ s.error("Conflicting visibility options '%s' and '%s'"
3741
+ % (prev_visibility, visibility), fatal=False)
3742
+ s.next()
3743
+ return visibility
3744
+
3745
+
3746
+ @cython.cfunc
3747
+ def p_c_modifiers(s: PyrexScanner) -> list:
3748
+ if s.sy == 'IDENT' and s.systring in ('inline',):
3749
+ modifier = s.systring
3750
+ s.next()
3751
+ return [modifier] + p_c_modifiers(s)
3752
+ return []
3753
+
3754
+
3755
+ @cython.cfunc
3756
+ def p_c_func_or_var_declaration(s: PyrexScanner, pos, ctx):
3757
+ cmethod_flag: cython.bint = ctx.level in ('c_class', 'c_class_pxd')
3758
+ modifiers = p_c_modifiers(s)
3759
+ base_type = p_c_base_type(s, nonempty=True, templates = ctx.templates)
3760
+ declarator = p_c_declarator(s, ctx(modifiers=modifiers), cmethod_flag = cmethod_flag,
3761
+ assignable=True, nonempty =True)
3762
+ declarator.overridable = ctx.overridable
3763
+
3764
+ if s.sy == 'IDENT' and s.systring == 'const' and ctx.level == 'cpp_class':
3765
+ s.next()
3766
+ is_const_method = True
3767
+ else:
3768
+ is_const_method = False
3769
+
3770
+ if s.sy == '->':
3771
+ # Special enough to give a better error message and keep going.
3772
+ s.error(
3773
+ "Return type annotation is not allowed in cdef/cpdef signatures. "
3774
+ "Please define it before the function name, as in C signatures.",
3775
+ fatal=False)
3776
+ s.next()
3777
+ p_test(s) # Keep going, but ignore result.
3778
+
3779
+ if s.sy == ':':
3780
+ if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class') and not ctx.templates:
3781
+ s.error("C function definition not allowed here")
3782
+ doc, suite = p_suite_with_docstring(s, Ctx(level='function'))
3783
+ result = Nodes.CFuncDefNode(pos,
3784
+ visibility = ctx.visibility,
3785
+ base_type = base_type,
3786
+ declarator = declarator,
3787
+ body = suite,
3788
+ doc = doc,
3789
+ modifiers = modifiers,
3790
+ api = ctx.api,
3791
+ overridable = ctx.overridable,
3792
+ is_const_method = is_const_method)
3793
+ else:
3794
+ #if api:
3795
+ # s.error("'api' not allowed with variable declaration")
3796
+ if is_const_method:
3797
+ declarator.is_const_method = is_const_method
3798
+ declarators = [declarator]
3799
+ while s.sy == ',':
3800
+ s.next()
3801
+ if s.sy == 'NEWLINE':
3802
+ break
3803
+ declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag,
3804
+ assignable=True, nonempty=True)
3805
+ declarators.append(declarator)
3806
+ doc_line = s.start_line + 1
3807
+ s.expect_newline("Syntax error in C variable declaration", ignore_semicolon=True)
3808
+ if ctx.level in ('c_class', 'c_class_pxd') and s.start_line == doc_line:
3809
+ doc = p_doc_string(s)
3810
+ else:
3811
+ doc = None
3812
+ result = Nodes.CVarDefNode(pos,
3813
+ visibility = ctx.visibility,
3814
+ base_type = base_type,
3815
+ declarators = declarators,
3816
+ in_pxd = ctx.level in ('module_pxd', 'c_class_pxd'),
3817
+ doc = doc,
3818
+ api = ctx.api,
3819
+ modifiers = modifiers,
3820
+ overridable = ctx.overridable)
3821
+ return result
3822
+
3823
+
3824
+ @cython.cfunc
3825
+ def p_ctypedef_statement(s: PyrexScanner, ctx):
3826
+ # s.sy == 'ctypedef'
3827
+ pos = s.position()
3828
+ s.next()
3829
+ visibility = p_visibility(s, ctx.visibility)
3830
+ api = p_api(s)
3831
+ ctx = ctx(typedef_flag=True, visibility = visibility)
3832
+ if api:
3833
+ ctx.api = True
3834
+ if s.sy == 'class':
3835
+ return p_c_class_definition(s, pos, ctx)
3836
+ elif s.sy == 'IDENT' and s.systring in struct_enum_union:
3837
+ return p_struct_enum(s, pos, ctx)
3838
+ elif s.sy == 'IDENT' and s.systring == 'fused':
3839
+ return p_fused_definition(s, pos, ctx)
3840
+ else:
3841
+ base_type = p_c_base_type(s, nonempty=True)
3842
+ declarator = p_c_declarator(s, ctx, is_type=True, nonempty=True)
3843
+ s.expect_newline("Syntax error in ctypedef statement", ignore_semicolon=True)
3844
+ return Nodes.CTypeDefNode(
3845
+ pos, base_type = base_type,
3846
+ declarator = declarator,
3847
+ visibility = visibility, api = api,
3848
+ in_pxd = ctx.level == 'module_pxd')
3849
+
3850
+
3851
+ @cython.cfunc
3852
+ def p_decorators(s: PyrexScanner) -> list:
3853
+ decorators = []
3854
+ while s.sy == '@':
3855
+ pos = s.position()
3856
+ s.next()
3857
+ decorator = p_namedexpr_test(s)
3858
+ decorators.append(Nodes.DecoratorNode(pos, decorator=decorator))
3859
+ s.expect_newline("Expected a newline after decorator")
3860
+ return decorators
3861
+
3862
+
3863
+ @cython.cfunc
3864
+ def _reject_cdef_modifier_in_py(s: PyrexScanner, name):
3865
+ """Step over incorrectly placed cdef modifiers (@see _CDEF_MODIFIERS) to provide a good error message for them.
3866
+ """
3867
+ if s.sy == 'IDENT' and name in _CDEF_MODIFIERS:
3868
+ # Special enough to provide a good error message.
3869
+ s.error("Cannot use cdef modifier '%s' in Python function signature. Use a decorator instead." % name, fatal=False)
3870
+ return p_ident(s) # Keep going, in case there are other errors.
3871
+ return name
3872
+
3873
+
3874
+ @cython.cfunc
3875
+ def p_def_statement(s: PyrexScanner, decorators: list = None, is_async_def: cython.bint = False):
3876
+ # s.sy == 'def'
3877
+ pos = decorators[0].pos if decorators else s.position()
3878
+ # PEP 492 switches the async/await keywords on in "async def" functions
3879
+ if is_async_def:
3880
+ s.enter_async()
3881
+ s.next()
3882
+ name = _reject_cdef_modifier_in_py(s, p_ident(s))
3883
+ s.expect(
3884
+ '(',
3885
+ "Expected '(', found '%s'. Did you use cdef syntax in a Python declaration? "
3886
+ "Use decorators and Python type annotations instead." % (
3887
+ s.systring if s.sy == 'IDENT' else s.sy))
3888
+ args, star_arg, starstar_arg = p_varargslist(s, terminator=')')
3889
+ s.expect(')')
3890
+ _reject_cdef_modifier_in_py(s, s.systring)
3891
+ return_type_annotation = None
3892
+ if s.sy == '->':
3893
+ s.next()
3894
+ return_type_annotation = p_annotation(s)
3895
+ _reject_cdef_modifier_in_py(s, s.systring)
3896
+
3897
+ doc, body = p_suite_with_docstring(s, Ctx(level='function'))
3898
+ if is_async_def:
3899
+ s.exit_async()
3900
+
3901
+ return Nodes.DefNode(
3902
+ pos, name=name, args=args, star_arg=star_arg, starstar_arg=starstar_arg,
3903
+ doc=doc, body=body, decorators=decorators, is_async_def=is_async_def,
3904
+ return_type_annotation=return_type_annotation)
3905
+
3906
+
3907
+ @cython.cfunc
3908
+ def p_varargslist(s: PyrexScanner, terminator: cython.Py_UCS4 = ')', annotated: cython.bint = True) -> tuple:
3909
+ args = p_c_arg_list(s, in_pyfunc=True, nonempty_declarators=True,
3910
+ annotated = annotated)
3911
+ star_arg = None
3912
+ starstar_arg = None
3913
+ if s.sy == '/':
3914
+ if len(args) == 0:
3915
+ s.error("Got zero positional-only arguments despite presence of "
3916
+ "positional-only specifier '/'")
3917
+ s.next()
3918
+ # Mark all args to the left as pos only
3919
+ for arg in args:
3920
+ arg.pos_only = 1
3921
+ if s.sy == ',':
3922
+ s.next()
3923
+ args.extend(p_c_arg_list(
3924
+ s, in_pyfunc=True, nonempty_declarators=True, annotated = annotated))
3925
+ elif s.sy != terminator:
3926
+ s.error("Syntax error in Python function argument list")
3927
+ if s.sy == '*':
3928
+ s.next()
3929
+ if s.sy == 'IDENT':
3930
+ star_arg = p_py_arg_decl(s, annotated=annotated)
3931
+ if s.sy == ',':
3932
+ s.next()
3933
+ args.extend(p_c_arg_list(
3934
+ s, in_pyfunc =True, nonempty_declarators=True, kw_only=True, annotated = annotated))
3935
+ elif s.sy != terminator:
3936
+ s.error("Syntax error in Python function argument list")
3937
+ if s.sy == '**':
3938
+ s.next()
3939
+ starstar_arg = p_py_arg_decl(s, annotated=annotated)
3940
+ if s.sy == ',':
3941
+ s.next()
3942
+ return (args, star_arg, starstar_arg)
3943
+
3944
+
3945
+ @cython.cfunc
3946
+ def p_py_arg_decl(s: PyrexScanner, annotated: cython.bint = True):
3947
+ pos = s.position()
3948
+ name = p_ident(s)
3949
+ annotation = None
3950
+ if annotated and s.sy == ':':
3951
+ s.next()
3952
+ annotation = p_annotation(s)
3953
+ return Nodes.PyArgDeclNode(pos, name = name, annotation = annotation)
3954
+
3955
+
3956
+ @cython.cfunc
3957
+ def p_class_statement(s: PyrexScanner, decorators):
3958
+ # s.sy == 'class'
3959
+ pos = s.position()
3960
+ s.next()
3961
+ class_name = EncodedString(p_ident(s))
3962
+ class_name.encoding = s.source_encoding # FIXME: why is this needed?
3963
+ arg_tuple = None
3964
+ keyword_dict = None
3965
+ if s.sy == '(':
3966
+ positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False)
3967
+ arg_tuple, keyword_dict = p_call_build_packed_args(pos, positional_args, keyword_args)
3968
+ if arg_tuple is None:
3969
+ # XXX: empty arg_tuple
3970
+ arg_tuple = ExprNodes.TupleNode(pos, args=[])
3971
+ doc, body = p_suite_with_docstring(s, Ctx(level='class'))
3972
+ return Nodes.PyClassDefNode(
3973
+ pos, name=class_name,
3974
+ bases=arg_tuple,
3975
+ keyword_args=keyword_dict,
3976
+ doc=doc, body=body, decorators=decorators,
3977
+ force_py3_semantics=s.context.language_level >= 3)
3978
+
3979
+
3980
+ @cython.cfunc
3981
+ def p_c_class_definition(s: PyrexScanner, pos, ctx):
3982
+ # s.sy == 'class'
3983
+ s.next()
3984
+ module_path = []
3985
+ class_name = p_ident(s)
3986
+ while s.sy == '.':
3987
+ s.next()
3988
+ module_path.append(class_name)
3989
+ class_name = p_ident(s)
3990
+ if module_path and ctx.visibility != 'extern':
3991
+ error(pos, "Qualified class name only allowed for 'extern' C class")
3992
+ if module_path and s.sy == 'IDENT' and s.systring == 'as':
3993
+ s.next()
3994
+ as_name = p_ident(s)
3995
+ else:
3996
+ as_name = class_name
3997
+ objstruct_name = None
3998
+ typeobj_name = None
3999
+ bases = None
4000
+ check_size = None
4001
+ if s.sy == '(':
4002
+ positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False)
4003
+ if keyword_args:
4004
+ s.error("C classes cannot take keyword bases.")
4005
+ bases, _ = p_call_build_packed_args(pos, positional_args, keyword_args)
4006
+ if bases is None:
4007
+ bases = ExprNodes.TupleNode(pos, args=[])
4008
+
4009
+ if s.sy == '[':
4010
+ if ctx.visibility not in ('public', 'extern') and not ctx.api:
4011
+ error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
4012
+ objstruct_name, typeobj_name, check_size = p_c_class_options(s)
4013
+ if s.sy == ':':
4014
+ if ctx.level == 'module_pxd':
4015
+ body_level = 'c_class_pxd'
4016
+ else:
4017
+ body_level = 'c_class'
4018
+ doc, body = p_suite_with_docstring(s, Ctx(level=body_level))
4019
+ else:
4020
+ s.expect_newline("Syntax error in C class definition")
4021
+ doc = None
4022
+ body = None
4023
+ if ctx.visibility == 'extern':
4024
+ if not module_path:
4025
+ error(pos, "Module name required for 'extern' C class")
4026
+ if typeobj_name:
4027
+ error(pos, "Type object name specification not allowed for 'extern' C class")
4028
+ elif ctx.visibility == 'public':
4029
+ if not objstruct_name:
4030
+ error(pos, "Object struct name specification required for 'public' C class")
4031
+ if not typeobj_name:
4032
+ error(pos, "Type object name specification required for 'public' C class")
4033
+ elif ctx.visibility == 'private':
4034
+ if ctx.api:
4035
+ if not objstruct_name:
4036
+ error(pos, "Object struct name specification required for 'api' C class")
4037
+ if not typeobj_name:
4038
+ error(pos, "Type object name specification required for 'api' C class")
4039
+ else:
4040
+ error(pos, "Invalid class visibility '%s'" % ctx.visibility)
4041
+ return Nodes.CClassDefNode(pos,
4042
+ visibility = ctx.visibility,
4043
+ typedef_flag = ctx.typedef_flag,
4044
+ api = ctx.api,
4045
+ module_name = EncodedString(".".join(module_path)),
4046
+ class_name = class_name,
4047
+ as_name = as_name,
4048
+ bases = bases,
4049
+ objstruct_name = objstruct_name,
4050
+ typeobj_name = typeobj_name,
4051
+ check_size = check_size,
4052
+ in_pxd = ctx.level == 'module_pxd',
4053
+ doc = doc,
4054
+ body = body)
4055
+
4056
+
4057
+ @cython.cfunc
4058
+ def p_c_class_options(s: PyrexScanner) -> tuple:
4059
+ objstruct_name = None
4060
+ typeobj_name = None
4061
+ check_size = None
4062
+ s.expect('[')
4063
+ while 1:
4064
+ if s.sy != 'IDENT':
4065
+ break
4066
+ if s.systring == 'object':
4067
+ s.next()
4068
+ objstruct_name = p_ident(s)
4069
+ elif s.systring == 'type':
4070
+ s.next()
4071
+ typeobj_name = p_ident(s)
4072
+ elif s.systring == 'check_size':
4073
+ s.next()
4074
+ check_size = p_ident(s)
4075
+ if check_size not in ('ignore', 'warn', 'error'):
4076
+ s.error("Expected one of ignore, warn or error, found %r" % check_size)
4077
+ if s.sy != ',':
4078
+ break
4079
+ s.next()
4080
+ s.expect(']', "Expected 'object', 'type' or 'check_size'")
4081
+ return objstruct_name, typeobj_name, check_size
4082
+
4083
+
4084
+ @cython.cfunc
4085
+ def p_property_decl(s: PyrexScanner):
4086
+ pos = s.position()
4087
+ s.next() # 'property'
4088
+ name = p_ident(s)
4089
+ doc, body = p_suite_with_docstring(
4090
+ s, Ctx(level='property'), with_doc_only=True)
4091
+ return Nodes.PropertyNode(pos, name=name, doc=doc, body=body)
4092
+
4093
+
4094
+ @cython.cfunc
4095
+ def p_ignorable_statement(s: PyrexScanner):
4096
+ """
4097
+ Parses any kind of ignorable statement that is allowed in .pxd files.
4098
+ """
4099
+ if s.sy == 'BEGIN_STRING':
4100
+ pos = s.position()
4101
+ string_node = p_atom(s)
4102
+ s.expect_newline("Syntax error in string", ignore_semicolon=True)
4103
+ return Nodes.ExprStatNode(pos, expr=string_node)
4104
+ return None
4105
+
4106
+
4107
+ @cython.cfunc
4108
+ def p_doc_string(s: PyrexScanner):
4109
+ if s.sy == 'BEGIN_STRING':
4110
+ pos = s.position()
4111
+ kind, bytes_result, unicode_result = p_cat_string_literal(s)
4112
+ s.expect_newline("Syntax error in doc string", ignore_semicolon=True)
4113
+ if kind in ('u', ''):
4114
+ return unicode_result
4115
+ warning(pos, "Python 3 requires docstrings to be unicode strings")
4116
+ return bytes_result
4117
+ else:
4118
+ return None
4119
+
4120
+
4121
+ @cython.cfunc
4122
+ def _extract_docstring(node) -> tuple:
4123
+ """
4124
+ Extract a docstring from a statement or from the first statement
4125
+ in a list. Remove the statement if found. Return a tuple
4126
+ (plain-docstring or None, node).
4127
+ """
4128
+ doc_node = None
4129
+ if node is None:
4130
+ pass
4131
+ elif isinstance(node, Nodes.ExprStatNode):
4132
+ if node.expr.is_string_literal:
4133
+ doc_node = node.expr
4134
+ node = Nodes.StatListNode(node.pos, stats=[])
4135
+ elif isinstance(node, Nodes.StatListNode) and node.stats:
4136
+ stats = node.stats
4137
+ if isinstance(stats[0], Nodes.ExprStatNode):
4138
+ if stats[0].expr.is_string_literal:
4139
+ doc_node = stats[0].expr
4140
+ del stats[0]
4141
+
4142
+ if doc_node is None:
4143
+ doc = None
4144
+ elif isinstance(doc_node, ExprNodes.BytesNode):
4145
+ warning(node.pos,
4146
+ "Python 3 requires docstrings to be unicode strings")
4147
+ doc = doc_node.value
4148
+ else:
4149
+ doc = doc_node.value
4150
+ return doc, node
4151
+
4152
+
4153
+ @cython.ccall
4154
+ def p_code(s: PyrexScanner, level=None, ctx=Ctx):
4155
+ body = p_statement_list(s, ctx(level = level), first_statement=True)
4156
+ if s.sy != 'EOF':
4157
+ s.error("Syntax error in statement [%s,%s]" % (
4158
+ repr(s.sy), repr(s.systring)))
4159
+ return body
4160
+
4161
+
4162
+ _match_compiler_directive_comment = cython.declare(object, re.compile(
4163
+ r"^#\s*cython\s*:\s*((\w|[.])+\s*=.*)$").match)
4164
+
4165
+
4166
+ @cython.cfunc
4167
+ def p_compiler_directive_comments(s: PyrexScanner) -> dict:
4168
+ result = {}
4169
+ while s.sy == 'commentline':
4170
+ pos = s.position()
4171
+ m = _match_compiler_directive_comment(s.systring)
4172
+ if m:
4173
+ directives_string = m.group(1).strip()
4174
+ try:
4175
+ new_directives = Options.parse_directive_list(directives_string, ignore_unknown=True)
4176
+ except ValueError as e:
4177
+ s.error(e.args[0], fatal=False)
4178
+ s.next()
4179
+ continue
4180
+
4181
+ for name in new_directives:
4182
+ if name not in result:
4183
+ pass
4184
+ elif Options.directive_types.get(name) is list:
4185
+ result[name] += new_directives[name]
4186
+ new_directives[name] = result[name]
4187
+ elif new_directives[name] == result[name]:
4188
+ warning(pos, "Duplicate directive found: %s" % (name,))
4189
+ else:
4190
+ s.error("Conflicting settings found for top-level directive %s: %r and %r" % (
4191
+ name, result[name], new_directives[name]), pos=pos)
4192
+
4193
+ if 'language_level' in new_directives:
4194
+ # Make sure we apply the language level already to the first token that follows the comments.
4195
+ s.context.set_language_level(new_directives['language_level'])
4196
+ if 'legacy_implicit_noexcept' in new_directives:
4197
+ s.context.legacy_implicit_noexcept = new_directives['legacy_implicit_noexcept']
4198
+
4199
+
4200
+ result.update(new_directives)
4201
+
4202
+ s.next()
4203
+ return result
4204
+
4205
+
4206
+ @cython.ccall
4207
+ def p_module(s: PyrexScanner, pxd, full_module_name, ctx=Ctx):
4208
+ pos = s.position()
4209
+
4210
+ directive_comments = p_compiler_directive_comments(s)
4211
+ s.parse_comments = False
4212
+
4213
+ if s.context.language_level is None:
4214
+ s.context.set_language_level('3')
4215
+
4216
+ level = 'module_pxd' if pxd else 'module'
4217
+ doc = p_doc_string(s)
4218
+ body = p_statement_list(s, ctx(level=level), first_statement=True)
4219
+ if s.sy != 'EOF':
4220
+ s.error("Syntax error in statement [%s,%s]" % (
4221
+ repr(s.sy), repr(s.systring)))
4222
+ return ModuleNode(pos, doc = doc, body = body,
4223
+ full_module_name = full_module_name,
4224
+ directive_comments = directive_comments)
4225
+
4226
+
4227
+ @cython.cfunc
4228
+ def p_template_definition(s: PyrexScanner) -> tuple:
4229
+ name = p_ident(s)
4230
+ if s.sy == '=':
4231
+ s.expect('=')
4232
+ s.expect('*')
4233
+ required = False
4234
+ else:
4235
+ required = True
4236
+ return name, required
4237
+
4238
+
4239
+ @cython.cfunc
4240
+ def p_cpp_class_definition(s: PyrexScanner, pos, ctx):
4241
+ # s.sy == 'cppclass'
4242
+ s.next()
4243
+ class_name = p_ident(s)
4244
+ cname = p_opt_cname(s)
4245
+ if cname is None and ctx.namespace is not None:
4246
+ cname = ctx.namespace + "::" + class_name
4247
+ if s.sy == '.':
4248
+ error(pos, "Qualified class name not allowed C++ class")
4249
+ if s.sy == '[':
4250
+ s.next()
4251
+ templates = [p_template_definition(s)]
4252
+ while s.sy == ',':
4253
+ s.next()
4254
+ templates.append(p_template_definition(s))
4255
+ s.expect(']')
4256
+ template_names = [name for name, required in templates]
4257
+ else:
4258
+ templates = None
4259
+ template_names = None
4260
+ if s.sy == '(':
4261
+ s.next()
4262
+ base_classes = [p_c_base_type(s, templates = template_names)]
4263
+ while s.sy == ',':
4264
+ s.next()
4265
+ base_classes.append(p_c_base_type(s, templates = template_names))
4266
+ s.expect(')')
4267
+ else:
4268
+ base_classes = []
4269
+ if s.sy == '[':
4270
+ error(s.position(), "Name options not allowed for C++ class")
4271
+ nogil = p_nogil(s)
4272
+ if s.sy == ':':
4273
+ s.next()
4274
+ s.expect('NEWLINE')
4275
+ s.expect_indent()
4276
+ # Allow a cppclass to have docstrings. It will be discarded as comment.
4277
+ # The goal of this is consistency: we can make docstrings inside cppclass methods,
4278
+ # so why not on the cppclass itself ?
4279
+ p_doc_string(s)
4280
+ attributes = []
4281
+ body_ctx = Ctx(visibility = ctx.visibility, level='cpp_class', nogil=nogil or ctx.nogil)
4282
+ body_ctx.templates = template_names
4283
+ while s.sy != 'DEDENT':
4284
+ if s.sy != 'pass':
4285
+ attributes.append(p_cpp_class_attribute(s, body_ctx))
4286
+ else:
4287
+ s.next()
4288
+ s.expect_newline("Expected a newline")
4289
+ s.expect_dedent()
4290
+ else:
4291
+ attributes = None
4292
+ s.expect_newline("Syntax error in C++ class definition")
4293
+ return Nodes.CppClassNode(pos,
4294
+ name = class_name,
4295
+ cname = cname,
4296
+ base_classes = base_classes,
4297
+ visibility = ctx.visibility,
4298
+ in_pxd = ctx.level == 'module_pxd',
4299
+ attributes = attributes,
4300
+ templates = templates)
4301
+
4302
+
4303
+ @cython.cfunc
4304
+ def p_cpp_class_attribute(s: PyrexScanner, ctx):
4305
+ pos = s.position()
4306
+ decorators = None
4307
+ if s.sy == '@':
4308
+ decorators = p_decorators(s)
4309
+ if s.systring == 'cppclass':
4310
+ return p_cpp_class_definition(s, pos, ctx)
4311
+ elif s.systring == 'ctypedef':
4312
+ return p_ctypedef_statement(s, ctx)
4313
+ elif s.sy == 'IDENT' and s.systring in struct_enum_union:
4314
+ if s.systring != 'enum':
4315
+ return p_cpp_class_definition(s, pos, ctx)
4316
+ else:
4317
+ return p_struct_enum(s, pos, ctx)
4318
+ else:
4319
+ node = p_c_func_or_var_declaration(s, pos, ctx)
4320
+ if decorators is not None:
4321
+ tup = Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode
4322
+ if ctx.allow_struct_enum_decorator:
4323
+ tup += Nodes.CStructOrUnionDefNode, Nodes.CEnumDefNode
4324
+ if not isinstance(node, tup):
4325
+ s.error("Decorators can only be followed by functions or classes")
4326
+ node.decorators = decorators
4327
+ return node
4328
+
4329
+
4330
+ @cython.cfunc
4331
+ def p_match_statement(s: PyrexScanner, ctx):
4332
+ assert s.sy == "IDENT" and s.systring == "match"
4333
+ pos = s.position()
4334
+ with tentatively_scan(s) as errors:
4335
+ s.next()
4336
+ subject = p_namedexpr_test(s)
4337
+ subjects = None
4338
+ if s.sy == ",":
4339
+ subjects = [subject]
4340
+ while s.sy == ",":
4341
+ s.next()
4342
+ if s.sy == ":":
4343
+ break
4344
+ subjects.append(p_test(s))
4345
+ if subjects is not None:
4346
+ subject = ExprNodes.TupleNode(pos, args=subjects)
4347
+ s.expect(":")
4348
+ if errors:
4349
+ return None
4350
+
4351
+ # at this stage we are committed to it being a match block so continue
4352
+ # outside "with tentatively_scan"
4353
+ # (I think this deviates from the PEG parser slightly, and it'd
4354
+ # backtrack on the whole thing)
4355
+ s.expect_newline()
4356
+ s.expect_indent()
4357
+ cases = []
4358
+ while s.sy != "DEDENT":
4359
+ cases.append(p_case_block(s, ctx))
4360
+ s.expect_dedent()
4361
+ return MatchCaseNodes.MatchNode(pos, subject=subject, cases=cases)
4362
+
4363
+
4364
+ @cython.cfunc
4365
+ def p_case_block(s: PyrexScanner, ctx):
4366
+ if not (s.sy == "IDENT" and s.systring == "case"):
4367
+ s.expected("case")
4368
+ s.next()
4369
+ pos = s.position()
4370
+ pattern = p_patterns(s)
4371
+ guard = None
4372
+ if s.sy == 'if':
4373
+ s.next()
4374
+ guard = p_test(s)
4375
+ body = p_suite(s, ctx)
4376
+
4377
+ return MatchCaseNodes.MatchCaseNode(pos, pattern=pattern, body=body, guard=guard)
4378
+
4379
+
4380
+ @cython.cfunc
4381
+ def p_patterns(s: PyrexScanner):
4382
+ # note - in slight contrast to the name (which comes from the Python grammar),
4383
+ # returns a single pattern
4384
+ patterns = []
4385
+ seq = False
4386
+ pos = s.position()
4387
+ while True:
4388
+ with tentatively_scan(s) as errors:
4389
+ pattern = p_maybe_star_pattern(s)
4390
+ if errors:
4391
+ if patterns:
4392
+ break # all is good provided we have at least 1 pattern
4393
+ else:
4394
+ e = errors[0]
4395
+ s.error(e.args[1], pos=e.args[0])
4396
+ patterns.append(pattern)
4397
+
4398
+ if s.sy == ",":
4399
+ seq = True
4400
+ s.next()
4401
+ if s.sy in [":", "if"]:
4402
+ break # common reasons to break
4403
+ else:
4404
+ break
4405
+
4406
+ if seq:
4407
+ return MatchCaseNodes.MatchSequencePatternNode(pos, patterns=patterns)
4408
+ else:
4409
+ return patterns[0]
4410
+
4411
+
4412
+ @cython.cfunc
4413
+ def p_maybe_star_pattern(s: PyrexScanner):
4414
+ # For match case. Either star_pattern or pattern
4415
+ if s.sy == "*":
4416
+ # star pattern
4417
+ s.next()
4418
+ target = None
4419
+ if s.systring != "_": # for match-case '_' is treated as a special wildcard
4420
+ target = p_pattern_capture_target(s)
4421
+ else:
4422
+ s.next()
4423
+ pattern = MatchCaseNodes.MatchAndAssignPatternNode(
4424
+ s.position(), target=target, is_star=True
4425
+ )
4426
+ return pattern
4427
+ else:
4428
+ pattern = p_pattern(s)
4429
+ return pattern
4430
+
4431
+
4432
+ @cython.cfunc
4433
+ def p_pattern(s: PyrexScanner):
4434
+ # try "as_pattern" then "or_pattern"
4435
+ # (but practically "as_pattern" starts with "or_pattern" too)
4436
+ patterns = []
4437
+ pos = s.position()
4438
+ while True:
4439
+ patterns.append(p_closed_pattern(s))
4440
+ if s.sy != "|":
4441
+ break
4442
+ s.next()
4443
+
4444
+ if len(patterns) > 1:
4445
+ pattern = MatchCaseNodes.OrPatternNode(
4446
+ pos,
4447
+ alternatives=patterns
4448
+ )
4449
+ else:
4450
+ pattern = patterns[0]
4451
+
4452
+ if s.sy == 'IDENT' and s.systring == 'as':
4453
+ s.next()
4454
+ with tentatively_scan(s) as errors:
4455
+ pattern.as_targets.append(p_pattern_capture_target(s))
4456
+ if errors and s.sy == "_":
4457
+ s.next()
4458
+ # make this a specific error
4459
+ return Nodes.ErrorNode(errors[0].args[0], what=errors[0].args[1])
4460
+ elif errors:
4461
+ with tentatively_scan(s):
4462
+ expr = p_test(s)
4463
+ return Nodes.ErrorNode(expr.pos, what="Invalid pattern target")
4464
+ s.error(errors[0])
4465
+ return pattern
4466
+
4467
+
4468
+ @cython.cfunc
4469
+ def p_closed_pattern(s: PyrexScanner):
4470
+ """
4471
+ The PEG parser specifies it as
4472
+ | literal_pattern
4473
+ | capture_pattern
4474
+ | wildcard_pattern
4475
+ | value_pattern
4476
+ | group_pattern
4477
+ | sequence_pattern
4478
+ | mapping_pattern
4479
+ | class_pattern
4480
+
4481
+ For the sake avoiding too much backtracking, we know:
4482
+ * starts with "{" is a mapping_pattern
4483
+ * starts with "[" is a sequence_pattern
4484
+ * starts with "(" is a group_pattern or sequence_pattern
4485
+ * wildcard pattern is just identifier=='_'
4486
+ The rest are then tried in order with backtracking
4487
+ """
4488
+ if s.sy == 'IDENT' and s.systring == '_':
4489
+ pos = s.position()
4490
+ s.next()
4491
+ return MatchCaseNodes.MatchAndAssignPatternNode(pos)
4492
+ elif s.sy == '{':
4493
+ return p_mapping_pattern(s)
4494
+ elif s.sy == '[':
4495
+ return p_sequence_pattern(s)
4496
+ elif s.sy == '(':
4497
+ with tentatively_scan(s) as errors:
4498
+ result = p_group_pattern(s)
4499
+ if not errors:
4500
+ return result
4501
+ return p_sequence_pattern(s)
4502
+
4503
+ with tentatively_scan(s) as errors:
4504
+ result = p_literal_pattern(s)
4505
+ if not errors:
4506
+ return result
4507
+ with tentatively_scan(s) as errors:
4508
+ result = p_capture_pattern(s)
4509
+ if not errors:
4510
+ return result
4511
+ with tentatively_scan(s) as errors:
4512
+ result = p_value_pattern(s)
4513
+ if not errors:
4514
+ return result
4515
+ return p_class_pattern(s)
4516
+
4517
+
4518
+ @cython.cfunc
4519
+ def p_literal_pattern(s: PyrexScanner):
4520
+ # a lot of duplication in this function with "p_atom"
4521
+ next_must_be_a_number = False
4522
+ sign = ''
4523
+ if s.sy == '-':
4524
+ sign = s.sy
4525
+ sign_pos = s.position()
4526
+ s.next()
4527
+ next_must_be_a_number = True
4528
+ elif s.sy == '+':
4529
+ s.next()
4530
+ next_must_be_a_number = True
4531
+
4532
+ sy = s.sy
4533
+ pos = s.position()
4534
+
4535
+ res = None
4536
+ if sy == 'INT':
4537
+ res = p_int_literal(s)
4538
+ elif sy == 'FLOAT':
4539
+ value = s.systring
4540
+ s.next()
4541
+ res = ExprNodes.FloatNode(pos, value=value)
4542
+
4543
+ if res is not None and sign == "-":
4544
+ res = ExprNodes.UnaryMinusNode(sign_pos, operand=res)
4545
+
4546
+ if res is not None and s.sy in ['+', '-']:
4547
+ sign = s.sy
4548
+ s.next()
4549
+ if s.sy == '+':
4550
+ s.next()
4551
+ if s.sy != 'IMAG':
4552
+ s.error("Expected imaginary number")
4553
+ else:
4554
+ add_pos = s.position()
4555
+ value = s.systring[:-1]
4556
+ s.next()
4557
+ res = ExprNodes.binop_node(
4558
+ add_pos,
4559
+ sign,
4560
+ operand1=res,
4561
+ operand2=ExprNodes.ImagNode(s.position(), value=value)
4562
+ )
4563
+
4564
+ if res is None and sy == 'IMAG':
4565
+ value = s.systring[:-1]
4566
+ s.next()
4567
+ res = ExprNodes.ImagNode(pos, value=sign+value)
4568
+
4569
+ if res is not None:
4570
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=res)
4571
+
4572
+ if next_must_be_a_number:
4573
+ s.error("Expected a number")
4574
+ if sy == 'BEGIN_STRING':
4575
+ res = p_atom_string(s)
4576
+ # Whether f-strings are suitable is validated in PostParse.
4577
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=res)
4578
+ elif sy == 'IDENT':
4579
+ # Note that p_atom_ident_constants includes NULL.
4580
+ # This is a deliberate Cython addition to the pattern matching specification
4581
+ result = p_atom_ident_constants(s)
4582
+ if result:
4583
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=result, is_is_check=True)
4584
+
4585
+ s.error("Failed to match literal")
4586
+
4587
+
4588
+ @cython.cfunc
4589
+ def p_capture_pattern(s: PyrexScanner):
4590
+ return MatchCaseNodes.MatchAndAssignPatternNode(
4591
+ s.position(),
4592
+ target=p_pattern_capture_target(s)
4593
+ )
4594
+
4595
+
4596
+ @cython.cfunc
4597
+ def p_value_pattern(s: PyrexScanner):
4598
+ if s.sy != "IDENT":
4599
+ s.error("Expected identifier")
4600
+ pos = s.position()
4601
+ res = p_name(s, s.systring)
4602
+ s.next()
4603
+ if s.sy != '.':
4604
+ s.error(".")
4605
+ while s.sy == '.':
4606
+ attr_pos = s.position()
4607
+ s.next()
4608
+ attr = p_ident(s)
4609
+ res = ExprNodes.AttributeNode(attr_pos, obj=res, attribute=attr)
4610
+ if s.sy in ['(', '=']:
4611
+ s.error("Unexpected symbol '%s'" % s.sy)
4612
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=res)
4613
+
4614
+
4615
+ @cython.cfunc
4616
+ def p_group_pattern(s: PyrexScanner):
4617
+ s.expect("(")
4618
+ pattern = p_pattern(s)
4619
+ s.expect(")")
4620
+ return pattern
4621
+
4622
+
4623
+ @cython.cfunc
4624
+ def p_sequence_pattern(s: PyrexScanner):
4625
+ pos = s.position()
4626
+ assert s.sy in ('(', '[')
4627
+ closer = ')' if s.sy == '(' else ']'
4628
+ s.next()
4629
+ # maybe_sequence_pattern and open_sequence_pattern
4630
+ patterns = []
4631
+ while s.sy != closer:
4632
+ patterns.append(p_maybe_star_pattern(s))
4633
+ if s.sy != ",":
4634
+ if closer == ')' and len(patterns) == 1:
4635
+ s.error("tuple-like pattern of length 1 must finish with ','")
4636
+ break
4637
+ s.next()
4638
+ s.expect(closer)
4639
+ return MatchCaseNodes.MatchSequencePatternNode(pos, patterns=patterns)
4640
+
4641
+
4642
+ @cython.cfunc
4643
+ def p_mapping_pattern(s: PyrexScanner):
4644
+ pos = s.position()
4645
+ s.expect('{')
4646
+ if s.sy == '}':
4647
+ # trivial empty mapping
4648
+ s.next()
4649
+ return MatchCaseNodes.MatchMappingPatternNode(pos)
4650
+
4651
+ double_star_capture_target = None
4652
+ items_patterns = []
4653
+ double_star_set_twice_pos = None
4654
+ pattern_after_double_star_pos = None
4655
+ star_star_arg_pos = None
4656
+ while s.sy != '}':
4657
+ if double_star_capture_target and not star_star_arg_pos:
4658
+ star_star_arg_pos = s.position()
4659
+ if s.sy == '**':
4660
+ s.next()
4661
+ if double_star_capture_target:
4662
+ double_star_set_twice_pos = s.position()
4663
+ double_star_capture_target = p_pattern_capture_target(s)
4664
+ else:
4665
+ # key=(literal_expr | attr)
4666
+ with tentatively_scan(s) as errors:
4667
+ pattern = p_literal_pattern(s)
4668
+ key = pattern.value
4669
+ if errors:
4670
+ pattern = p_value_pattern(s)
4671
+ key = pattern.value
4672
+ s.expect(':')
4673
+ value = p_pattern(s)
4674
+ items_patterns.append((key, value))
4675
+ if double_star_capture_target:
4676
+ pattern_after_double_star_pos = value.pos
4677
+ if s.sy != ',':
4678
+ break
4679
+ s.next()
4680
+ s.expect('}')
4681
+ if double_star_set_twice_pos is not None:
4682
+ return Nodes.ErrorNode(double_star_set_twice_pos, what = "Double star capture set twice")
4683
+ if pattern_after_double_star_pos is not None:
4684
+ return Nodes.ErrorNode(pattern_after_double_star_pos, what = "pattern follows ** capture")
4685
+
4686
+ if star_star_arg_pos is not None:
4687
+ return Nodes.ErrorNode(
4688
+ star_star_arg_pos,
4689
+ what = "** pattern must be the final part of a mapping pattern."
4690
+ )
4691
+ return MatchCaseNodes.MatchMappingPatternNode(
4692
+ pos,
4693
+ keys = [kv[0] for kv in items_patterns],
4694
+ value_patterns = [kv[1] for kv in items_patterns],
4695
+ double_star_capture_target = double_star_capture_target
4696
+ )
4697
+
4698
+
4699
+ @cython.cfunc
4700
+ def p_class_pattern(s: PyrexScanner):
4701
+ # start by parsing the class as name_or_attr
4702
+ pos = s.position()
4703
+ res = p_name(s, s.systring)
4704
+ s.next()
4705
+ while s.sy == '.':
4706
+ attr_pos = s.position()
4707
+ s.next()
4708
+ attr = p_ident(s)
4709
+ res = ExprNodes.AttributeNode(attr_pos, obj=res, attribute=attr)
4710
+ class_ = res
4711
+
4712
+ s.expect("(")
4713
+ if s.sy == ")":
4714
+ # trivial case with no arguments matched
4715
+ s.next()
4716
+ return MatchCaseNodes.ClassPatternNode(pos, class_=class_)
4717
+
4718
+ # parse the arguments
4719
+ positional_patterns = []
4720
+ keyword_patterns = []
4721
+ keyword_patterns_error = None
4722
+ while s.sy != ')':
4723
+ with tentatively_scan(s) as errors:
4724
+ positional_patterns.append(p_pattern(s))
4725
+ if not errors:
4726
+ if keyword_patterns:
4727
+ keyword_patterns_error = s.position()
4728
+ else:
4729
+ with tentatively_scan(s) as errors:
4730
+ keyword_patterns.append(p_keyword_pattern(s))
4731
+ if s.sy != ",":
4732
+ break
4733
+ s.next()
4734
+ s.expect(")")
4735
+
4736
+ if keyword_patterns_error is not None:
4737
+ return Nodes.ErrorNode(
4738
+ keyword_patterns_error,
4739
+ what="Positional patterns follow keyword patterns"
4740
+ )
4741
+ return MatchCaseNodes.ClassPatternNode(
4742
+ pos, class_ = class_,
4743
+ positional_patterns = positional_patterns,
4744
+ keyword_pattern_names = [kv[0] for kv in keyword_patterns],
4745
+ keyword_pattern_patterns = [kv[1] for kv in keyword_patterns],
4746
+ )
4747
+
4748
+
4749
+ @cython.cfunc
4750
+ def p_keyword_pattern(s: PyrexScanner) -> tuple:
4751
+ if s.sy != "IDENT":
4752
+ s.error("Expected identifier")
4753
+ arg = p_name(s, s.systring)
4754
+ s.next()
4755
+ s.expect("=")
4756
+ value = p_pattern(s)
4757
+ return arg, value
4758
+
4759
+
4760
+ @cython.cfunc
4761
+ def p_pattern_capture_target(s: PyrexScanner):
4762
+ # any name but '_', and with some constraints on what follows
4763
+ if s.sy != 'IDENT':
4764
+ s.error("Expected identifier")
4765
+ if s.systring == '_':
4766
+ s.error("Pattern capture target cannot be '_'")
4767
+ target = p_name(s, s.systring)
4768
+ s.next()
4769
+ if s.sy in ['.', '(', '=']:
4770
+ s.error("Illegal next symbol '%s'" % s.sy)
4771
+ return target
4772
+
4773
+
4774
+
4775
+ #----------------------------------------------
4776
+ #
4777
+ # Debugging
4778
+ #
4779
+ #----------------------------------------------
4780
+
4781
+ @cython.ccall
4782
+ def print_parse_tree(f, node, level: cython.long, key = None):
4783
+ ind: str = " " * level
4784
+ f.write(ind)
4785
+ if key:
4786
+ f.write(f"{key}: ")
4787
+ if not node:
4788
+ f.write("None\n")
4789
+ elif type(node) is tuple:
4790
+ f.write(f"({node[0]} @ {node[1]}\n")
4791
+ for item in node[2:]:
4792
+ print_parse_tree(f, item, level+1)
4793
+ f.write(f"{ind})\n")
4794
+ elif isinstance(node, Nodes.Node):
4795
+ try:
4796
+ tag = node.tag
4797
+ except AttributeError:
4798
+ tag = node.__class__.__name__
4799
+ f.write(f"{tag} @ {node.pos}\n")
4800
+ for name, value in sorted(node.__dict__.items()):
4801
+ if name != 'tag' and name != 'pos':
4802
+ print_parse_tree(f, value, level+1, name)
4803
+ elif type(node) is list:
4804
+ f.write("[\n")
4805
+ for item in node:
4806
+ print_parse_tree(f, item, level+1)
4807
+ f.write(f"{ind}]\n")
4808
+ else:
4809
+ f.write(f"{ind}{node}\n")