Cython 3.3.0a1__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 (335) 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 +1276 -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 +84 -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 +815 -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 +680 -0
  23. Cython/Compiler/Builtin.py +997 -0
  24. Cython/Compiler/CmdLine.py +263 -0
  25. Cython/Compiler/Code.cp315-win_amd64.pyd +0 -0
  26. Cython/Compiler/Code.pxd +152 -0
  27. Cython/Compiler/Code.py +3907 -0
  28. Cython/Compiler/CodeGeneration.py +33 -0
  29. Cython/Compiler/CythonScope.py +194 -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 +15983 -0
  34. Cython/Compiler/FlowControl.cp315-win_amd64.pyd +0 -0
  35. Cython/Compiler/FlowControl.pxd +99 -0
  36. Cython/Compiler/FlowControl.py +1571 -0
  37. Cython/Compiler/FusedNode.cp315-win_amd64.pyd +0 -0
  38. Cython/Compiler/FusedNode.py +976 -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 +2197 -0
  46. Cython/Compiler/MemoryView.py +930 -0
  47. Cython/Compiler/ModuleNode.py +4517 -0
  48. Cython/Compiler/Naming.py +367 -0
  49. Cython/Compiler/Nodes.py +10941 -0
  50. Cython/Compiler/Optimize.py +5455 -0
  51. Cython/Compiler/Options.py +838 -0
  52. Cython/Compiler/ParseTreeTransforms.pxd +79 -0
  53. Cython/Compiler/ParseTreeTransforms.py +4744 -0
  54. Cython/Compiler/Parsing.cp315-win_amd64.pyd +0 -0
  55. Cython/Compiler/Parsing.pxd +9 -0
  56. Cython/Compiler/Parsing.py +4792 -0
  57. Cython/Compiler/Pipeline.py +439 -0
  58. Cython/Compiler/PyrexTypes.py +6111 -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.py +297 -0
  64. Cython/Compiler/Symtab.py +3092 -0
  65. Cython/Compiler/Tests/TestBuffer.py +105 -0
  66. Cython/Compiler/Tests/TestBuiltin.py +117 -0
  67. Cython/Compiler/Tests/TestCmdLine.py +587 -0
  68. Cython/Compiler/Tests/TestCode.py +145 -0
  69. Cython/Compiler/Tests/TestFlowControl.py +65 -0
  70. Cython/Compiler/Tests/TestGrammar.py +202 -0
  71. Cython/Compiler/Tests/TestMemView.py +71 -0
  72. Cython/Compiler/Tests/TestParseTreeTransforms.py +285 -0
  73. Cython/Compiler/Tests/TestScanning.py +132 -0
  74. Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
  75. Cython/Compiler/Tests/TestStringEncoding.py +20 -0
  76. Cython/Compiler/Tests/TestTreeFragment.py +63 -0
  77. Cython/Compiler/Tests/TestTreePath.py +103 -0
  78. Cython/Compiler/Tests/TestTypes.py +118 -0
  79. Cython/Compiler/Tests/TestUtilityLoad.py +112 -0
  80. Cython/Compiler/Tests/TestVisitor.py +61 -0
  81. Cython/Compiler/Tests/Utils.py +36 -0
  82. Cython/Compiler/Tests/__init__.py +1 -0
  83. Cython/Compiler/TreeFragment.py +278 -0
  84. Cython/Compiler/TreePath.py +303 -0
  85. Cython/Compiler/TypeInference.py +611 -0
  86. Cython/Compiler/TypeSlots.py +1329 -0
  87. Cython/Compiler/UFuncs.py +311 -0
  88. Cython/Compiler/UtilNodes.py +413 -0
  89. Cython/Compiler/UtilityCode.py +348 -0
  90. Cython/Compiler/Version.py +8 -0
  91. Cython/Compiler/Visitor.cp315-win_amd64.pyd +0 -0
  92. Cython/Compiler/Visitor.pxd +53 -0
  93. Cython/Compiler/Visitor.py +864 -0
  94. Cython/Compiler/__init__.py +1 -0
  95. Cython/Coverage.py +448 -0
  96. Cython/Debugger/Cygdb.py +177 -0
  97. Cython/Debugger/DebugWriter.py +82 -0
  98. Cython/Debugger/Tests/TestLibCython.py +280 -0
  99. Cython/Debugger/Tests/__init__.py +1 -0
  100. Cython/Debugger/Tests/cfuncs.c +8 -0
  101. Cython/Debugger/Tests/codefile +49 -0
  102. Cython/Debugger/Tests/test_libcython_in_gdb.py +580 -0
  103. Cython/Debugger/Tests/test_libpython_in_gdb.py +90 -0
  104. Cython/Debugger/__init__.py +1 -0
  105. Cython/Debugger/libcython.py +1548 -0
  106. Cython/Debugger/libpython.py +2821 -0
  107. Cython/Debugging.py +20 -0
  108. Cython/Distutils/__init__.py +2 -0
  109. Cython/Distutils/build_ext.py +139 -0
  110. Cython/Distutils/extension.py +96 -0
  111. Cython/Distutils/old_build_ext.py +351 -0
  112. Cython/Includes/cpython/__init__.pxd +173 -0
  113. Cython/Includes/cpython/array.pxd +152 -0
  114. Cython/Includes/cpython/bool.pxd +37 -0
  115. Cython/Includes/cpython/buffer.pxd +112 -0
  116. Cython/Includes/cpython/bytearray.pxd +33 -0
  117. Cython/Includes/cpython/bytes.pxd +200 -0
  118. Cython/Includes/cpython/cellobject.pxd +35 -0
  119. Cython/Includes/cpython/ceval.pxd +8 -0
  120. Cython/Includes/cpython/codecs.pxd +121 -0
  121. Cython/Includes/cpython/complex.pxd +60 -0
  122. Cython/Includes/cpython/contextvars.pxd +145 -0
  123. Cython/Includes/cpython/conversion.pxd +36 -0
  124. Cython/Includes/cpython/datetime.pxd +395 -0
  125. Cython/Includes/cpython/descr.pxd +26 -0
  126. Cython/Includes/cpython/dict.pxd +268 -0
  127. Cython/Includes/cpython/exc.pxd +263 -0
  128. Cython/Includes/cpython/fileobject.pxd +57 -0
  129. Cython/Includes/cpython/float.pxd +56 -0
  130. Cython/Includes/cpython/frozendict.pxd +37 -0
  131. Cython/Includes/cpython/function.pxd +65 -0
  132. Cython/Includes/cpython/genobject.pxd +25 -0
  133. Cython/Includes/cpython/getargs.pxd +12 -0
  134. Cython/Includes/cpython/instance.pxd +25 -0
  135. Cython/Includes/cpython/iterator.pxd +36 -0
  136. Cython/Includes/cpython/iterobject.pxd +24 -0
  137. Cython/Includes/cpython/list.pxd +144 -0
  138. Cython/Includes/cpython/long.pxd +180 -0
  139. Cython/Includes/cpython/longintrepr.pxd +14 -0
  140. Cython/Includes/cpython/mapping.pxd +63 -0
  141. Cython/Includes/cpython/marshal.pxd +66 -0
  142. Cython/Includes/cpython/mem.pxd +120 -0
  143. Cython/Includes/cpython/memoryview.pxd +50 -0
  144. Cython/Includes/cpython/method.pxd +49 -0
  145. Cython/Includes/cpython/module.pxd +208 -0
  146. Cython/Includes/cpython/number.pxd +258 -0
  147. Cython/Includes/cpython/object.pxd +430 -0
  148. Cython/Includes/cpython/pycapsule.pxd +143 -0
  149. Cython/Includes/cpython/pylifecycle.pxd +68 -0
  150. Cython/Includes/cpython/pyport.pxd +8 -0
  151. Cython/Includes/cpython/pystate.pxd +95 -0
  152. Cython/Includes/cpython/pythread.pxd +53 -0
  153. Cython/Includes/cpython/ref.pxd +141 -0
  154. Cython/Includes/cpython/sentinel.pxd +17 -0
  155. Cython/Includes/cpython/sequence.pxd +134 -0
  156. Cython/Includes/cpython/set.pxd +119 -0
  157. Cython/Includes/cpython/slice.pxd +70 -0
  158. Cython/Includes/cpython/time.pxd +129 -0
  159. Cython/Includes/cpython/tuple.pxd +72 -0
  160. Cython/Includes/cpython/type.pxd +146 -0
  161. Cython/Includes/cpython/unicode.pxd +639 -0
  162. Cython/Includes/cpython/version.pxd +32 -0
  163. Cython/Includes/cpython/weakref.pxd +78 -0
  164. Cython/Includes/libc/__init__.pxd +1 -0
  165. Cython/Includes/libc/complex.pxd +35 -0
  166. Cython/Includes/libc/errno.pxd +127 -0
  167. Cython/Includes/libc/float.pxd +43 -0
  168. Cython/Includes/libc/limits.pxd +28 -0
  169. Cython/Includes/libc/locale.pxd +46 -0
  170. Cython/Includes/libc/math.pxd +209 -0
  171. Cython/Includes/libc/setjmp.pxd +10 -0
  172. Cython/Includes/libc/signal.pxd +64 -0
  173. Cython/Includes/libc/stddef.pxd +9 -0
  174. Cython/Includes/libc/stdint.pxd +105 -0
  175. Cython/Includes/libc/stdio.pxd +80 -0
  176. Cython/Includes/libc/stdlib.pxd +72 -0
  177. Cython/Includes/libc/string.pxd +50 -0
  178. Cython/Includes/libc/threads.pxd +234 -0
  179. Cython/Includes/libc/time.pxd +52 -0
  180. Cython/Includes/libcpp/__init__.pxd +4 -0
  181. Cython/Includes/libcpp/algorithm.pxd +320 -0
  182. Cython/Includes/libcpp/any.pxd +16 -0
  183. Cython/Includes/libcpp/atomic.pxd +59 -0
  184. Cython/Includes/libcpp/barrier.pxd +22 -0
  185. Cython/Includes/libcpp/bit.pxd +29 -0
  186. Cython/Includes/libcpp/cast.pxd +12 -0
  187. Cython/Includes/libcpp/cmath.pxd +518 -0
  188. Cython/Includes/libcpp/complex.pxd +106 -0
  189. Cython/Includes/libcpp/condition_variable.pxd +322 -0
  190. Cython/Includes/libcpp/deque.pxd +165 -0
  191. Cython/Includes/libcpp/exception.pxd +216 -0
  192. Cython/Includes/libcpp/execution.pxd +15 -0
  193. Cython/Includes/libcpp/forward_list.pxd +63 -0
  194. Cython/Includes/libcpp/functional.pxd +26 -0
  195. Cython/Includes/libcpp/future.pxd +103 -0
  196. Cython/Includes/libcpp/iterator.pxd +34 -0
  197. Cython/Includes/libcpp/latch.pxd +17 -0
  198. Cython/Includes/libcpp/limits.pxd +61 -0
  199. Cython/Includes/libcpp/list.pxd +117 -0
  200. Cython/Includes/libcpp/map.pxd +252 -0
  201. Cython/Includes/libcpp/memory.pxd +115 -0
  202. Cython/Includes/libcpp/mutex.pxd +387 -0
  203. Cython/Includes/libcpp/numbers.pxd +15 -0
  204. Cython/Includes/libcpp/numeric.pxd +131 -0
  205. Cython/Includes/libcpp/optional.pxd +34 -0
  206. Cython/Includes/libcpp/pair.pxd +1 -0
  207. Cython/Includes/libcpp/queue.pxd +25 -0
  208. Cython/Includes/libcpp/random.pxd +166 -0
  209. Cython/Includes/libcpp/semaphore.pxd +43 -0
  210. Cython/Includes/libcpp/set.pxd +228 -0
  211. Cython/Includes/libcpp/shared_mutex.pxd +96 -0
  212. Cython/Includes/libcpp/span.pxd +87 -0
  213. Cython/Includes/libcpp/stack.pxd +11 -0
  214. Cython/Includes/libcpp/stop_token.pxd +117 -0
  215. Cython/Includes/libcpp/string.pxd +355 -0
  216. Cython/Includes/libcpp/string_view.pxd +183 -0
  217. Cython/Includes/libcpp/typeindex.pxd +15 -0
  218. Cython/Includes/libcpp/typeinfo.pxd +10 -0
  219. Cython/Includes/libcpp/unordered_map.pxd +193 -0
  220. Cython/Includes/libcpp/unordered_set.pxd +152 -0
  221. Cython/Includes/libcpp/utility.pxd +30 -0
  222. Cython/Includes/libcpp/vector.pxd +186 -0
  223. Cython/Includes/numpy/math.pxd +150 -0
  224. Cython/Includes/openmp.pxd +50 -0
  225. Cython/Includes/posix/__init__.pxd +1 -0
  226. Cython/Includes/posix/dlfcn.pxd +14 -0
  227. Cython/Includes/posix/fcntl.pxd +86 -0
  228. Cython/Includes/posix/ioctl.pxd +4 -0
  229. Cython/Includes/posix/mman.pxd +101 -0
  230. Cython/Includes/posix/resource.pxd +57 -0
  231. Cython/Includes/posix/select.pxd +21 -0
  232. Cython/Includes/posix/signal.pxd +73 -0
  233. Cython/Includes/posix/stat.pxd +98 -0
  234. Cython/Includes/posix/stdio.pxd +37 -0
  235. Cython/Includes/posix/stdlib.pxd +29 -0
  236. Cython/Includes/posix/strings.pxd +9 -0
  237. Cython/Includes/posix/time.pxd +71 -0
  238. Cython/Includes/posix/types.pxd +30 -0
  239. Cython/Includes/posix/uio.pxd +26 -0
  240. Cython/Includes/posix/unistd.pxd +271 -0
  241. Cython/Includes/posix/wait.pxd +38 -0
  242. Cython/LZSS.py +170 -0
  243. Cython/Plex/Actions.cp315-win_amd64.pyd +0 -0
  244. Cython/Plex/Actions.pxd +24 -0
  245. Cython/Plex/Actions.py +119 -0
  246. Cython/Plex/DFA.cp315-win_amd64.pyd +0 -0
  247. Cython/Plex/DFA.pxd +14 -0
  248. Cython/Plex/DFA.py +164 -0
  249. Cython/Plex/Errors.py +48 -0
  250. Cython/Plex/Lexicons.py +178 -0
  251. Cython/Plex/Machines.cp315-win_amd64.pyd +0 -0
  252. Cython/Plex/Machines.pxd +36 -0
  253. Cython/Plex/Machines.py +238 -0
  254. Cython/Plex/Regexps.py +535 -0
  255. Cython/Plex/Scanners.cp315-win_amd64.pyd +0 -0
  256. Cython/Plex/Scanners.pxd +45 -0
  257. Cython/Plex/Scanners.py +328 -0
  258. Cython/Plex/Transitions.cp315-win_amd64.pyd +0 -0
  259. Cython/Plex/Transitions.pxd +14 -0
  260. Cython/Plex/Transitions.py +239 -0
  261. Cython/Plex/__init__.py +34 -0
  262. Cython/Runtime/__init__.py +1 -0
  263. Cython/Runtime/refnanny.cp315-win_amd64.pyd +0 -0
  264. Cython/Runtime/refnanny.pyx +237 -0
  265. Cython/Shadow.py +1167 -0
  266. Cython/StringIOTree.cp315-win_amd64.pyd +0 -0
  267. Cython/StringIOTree.py +169 -0
  268. Cython/Tempita/__init__.py +4 -0
  269. Cython/Tempita/_looper.py +154 -0
  270. Cython/Tempita/_tempita.cp315-win_amd64.pyd +0 -0
  271. Cython/Tempita/_tempita.py +1087 -0
  272. Cython/TestUtils.py +464 -0
  273. Cython/Tests/TestCodeWriter.py +128 -0
  274. Cython/Tests/TestCythonUtils.py +202 -0
  275. Cython/Tests/TestJediTyper.py +223 -0
  276. Cython/Tests/TestShadow.py +110 -0
  277. Cython/Tests/TestStringIOTree.py +68 -0
  278. Cython/Tests/TestTestUtils.py +89 -0
  279. Cython/Tests/__init__.py +1 -0
  280. Cython/Tests/xmlrunner.py +390 -0
  281. Cython/Utility/AsyncGen.c +1073 -0
  282. Cython/Utility/Buffer.c +866 -0
  283. Cython/Utility/BufferFormatFromTypeInfo.pxd +2 -0
  284. Cython/Utility/Builtins.c +933 -0
  285. Cython/Utility/CConvert.pyx +149 -0
  286. Cython/Utility/CMath.c +104 -0
  287. Cython/Utility/CommonStructures.c +244 -0
  288. Cython/Utility/Complex.c +378 -0
  289. Cython/Utility/Coroutine.c +2337 -0
  290. Cython/Utility/CpdefEnums.pyx +107 -0
  291. Cython/Utility/CppConvert.pyx +282 -0
  292. Cython/Utility/CppSupport.cpp +151 -0
  293. Cython/Utility/CythonFunction.c +2072 -0
  294. Cython/Utility/Dataclasses.c +101 -0
  295. Cython/Utility/Embed.c +129 -0
  296. Cython/Utility/Exceptions.c +1038 -0
  297. Cython/Utility/ExtensionTypes.c +1158 -0
  298. Cython/Utility/FunctionArguments.c +1045 -0
  299. Cython/Utility/FusedFunction.pyx +44 -0
  300. Cython/Utility/ImportExport.c +930 -0
  301. Cython/Utility/MatchCase.c +979 -0
  302. Cython/Utility/MatchCase_Cy.pyx +12 -0
  303. Cython/Utility/MemoryView.pxd +108 -0
  304. Cython/Utility/MemoryView.pyx +1499 -0
  305. Cython/Utility/MemoryView_C.c +1056 -0
  306. Cython/Utility/ModuleSetupCode.c +3352 -0
  307. Cython/Utility/NumpyImportArray.c +46 -0
  308. Cython/Utility/ObjectHandling.c +3372 -0
  309. Cython/Utility/Optimize.c +2563 -0
  310. Cython/Utility/Overflow.c +378 -0
  311. Cython/Utility/Profile.c +736 -0
  312. Cython/Utility/StringTools.c +1414 -0
  313. Cython/Utility/Synchronization.c +438 -0
  314. Cython/Utility/TString.c +369 -0
  315. Cython/Utility/TestCyUtilityLoader.pyx +8 -0
  316. Cython/Utility/TestCythonScope.pyx +75 -0
  317. Cython/Utility/TestUtilityLoader.c +12 -0
  318. Cython/Utility/TypeConversion.c +1556 -0
  319. Cython/Utility/UFuncs.pyx +50 -0
  320. Cython/Utility/UFuncs_C.c +89 -0
  321. Cython/Utility/__init__.py +28 -0
  322. Cython/Utility/arrayarray.h +172 -0
  323. Cython/Utils.cp315-win_amd64.pyd +0 -0
  324. Cython/Utils.py +677 -0
  325. Cython/__init__.py +12 -0
  326. Cython/py.typed +0 -0
  327. cython-3.3.0a1.dist-info/METADATA +394 -0
  328. cython-3.3.0a1.dist-info/RECORD +335 -0
  329. cython-3.3.0a1.dist-info/WHEEL +5 -0
  330. cython-3.3.0a1.dist-info/entry_points.txt +4 -0
  331. cython-3.3.0a1.dist-info/top_level.txt +3 -0
  332. cython.py +29 -0
  333. pyximport/__init__.py +4 -0
  334. pyximport/pyxbuild.py +160 -0
  335. pyximport/pyximport.py +482 -0
@@ -0,0 +1,4792 @@
1
+ # cython: 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:
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, test=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:
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:
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:
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,
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:
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:
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, 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 = -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
+ if expr.is_starred:
1380
+ s.error("iterable unpacking cannot be used in comprehension")
1381
+ append = ExprNodes.ComprehensionAppendNode(pos, expr=expr)
1382
+ loop = p_comp_for(s, append)
1383
+ s.expect(']')
1384
+ return ExprNodes.ComprehensionNode(
1385
+ pos, loop=loop, append=append, type=Builtin.list_type,
1386
+ # list comprehensions leak their loop variable in Py2
1387
+ has_local_scope=s.context.language_level >= 3)
1388
+
1389
+ # (merged) list literal
1390
+ if s.sy == ',':
1391
+ s.next()
1392
+ exprs = p_namedexpr_test_or_starred_expr_list(s, expr)
1393
+ else:
1394
+ exprs = [expr]
1395
+ s.expect(']')
1396
+ return ExprNodes.ListNode(pos, args=exprs)
1397
+
1398
+
1399
+ @cython.cfunc
1400
+ def p_comp_iter(s: PyrexScanner, body):
1401
+ if s.sy in ('for', 'async'):
1402
+ return p_comp_for(s, body)
1403
+ elif s.sy == 'if':
1404
+ return p_comp_if(s, body)
1405
+ else:
1406
+ # insert the 'append' operation into the loop
1407
+ return body
1408
+
1409
+
1410
+ @cython.cfunc
1411
+ def p_comp_for(s: PyrexScanner, body):
1412
+ pos = s.position()
1413
+ # [async] for ...
1414
+ is_async = False
1415
+ if s.sy == 'async':
1416
+ is_async = True
1417
+ s.next()
1418
+
1419
+ # s.sy == 'for'
1420
+ s.expect('for')
1421
+ kw = p_for_bounds(s, allow_testlist=False, is_async=is_async)
1422
+ kw.update(else_clause=None, body=p_comp_iter(s, body), is_async=is_async)
1423
+ return Nodes.ForStatNode(pos, **kw)
1424
+
1425
+
1426
+ @cython.cfunc
1427
+ def p_comp_if(s: PyrexScanner, body):
1428
+ # s.sy == 'if'
1429
+ pos = s.position()
1430
+ s.next()
1431
+ # Note that Python 3.9+ is actually more restrictive here and Cython now follows
1432
+ # the Python 3.9+ behaviour: https://github.com/python/cpython/issues/86014
1433
+ # On Python <3.9 `[i for i in range(10) if lambda: i if True else 1]` was disallowed
1434
+ # but `[i for i in range(10) if lambda: i]` was allowed.
1435
+ # On Python >=3.9 they're both disallowed.
1436
+ test = p_or_test(s)
1437
+ return Nodes.IfStatNode(pos,
1438
+ if_clauses = [Nodes.IfClauseNode(pos, condition = test,
1439
+ body = p_comp_iter(s, body))],
1440
+ else_clause = None )
1441
+
1442
+
1443
+ # since PEP 448:
1444
+ #dictorsetmaker: ( ((test ':' test | '**' expr)
1445
+ # (comp_for | (',' (test ':' test | '**' expr))* [','])) |
1446
+ # ((test | star_expr)
1447
+ # (comp_for | (',' (test | star_expr))* [','])) )
1448
+
1449
+ @cython.cfunc
1450
+ def p_dict_or_set_maker(s: PyrexScanner):
1451
+ # s.sy == '{'
1452
+ pos = s.position()
1453
+ s.next()
1454
+ if s.sy == '}':
1455
+ s.next()
1456
+ return ExprNodes.DictNode(pos, key_value_pairs=[])
1457
+
1458
+ parts = []
1459
+ target_type: cython.int = 0
1460
+ last_was_simple_item = False
1461
+ while True:
1462
+ if s.sy in ('*', '**'):
1463
+ # merged set/dict literal
1464
+ if target_type == 0:
1465
+ target_type = 1 if s.sy == '*' else 2 # 'stars'
1466
+ elif target_type != len(s.sy):
1467
+ s.error("unexpected %sitem found in %s literal" % (
1468
+ s.sy, 'set' if target_type == 1 else 'dict'))
1469
+ s.next()
1470
+ if s.sy == '*':
1471
+ s.error("expected expression, found '*'")
1472
+ item = p_starred_expr(s)
1473
+ parts.append(item)
1474
+ last_was_simple_item = False
1475
+ else:
1476
+ item = p_test(s)
1477
+ if target_type == 0:
1478
+ target_type = 2 if s.sy == ':' else 1 # dict vs. set
1479
+ if target_type == 2:
1480
+ # dict literal
1481
+ s.expect(':')
1482
+ key = item
1483
+ value = p_test(s)
1484
+ item = ExprNodes.DictItemNode(key.pos, key=key, value=value)
1485
+ if last_was_simple_item:
1486
+ parts[-1].append(item)
1487
+ else:
1488
+ parts.append([item])
1489
+ last_was_simple_item = True
1490
+
1491
+ if s.sy == ',':
1492
+ s.next()
1493
+ if s.sy == '}':
1494
+ break
1495
+ else:
1496
+ break
1497
+
1498
+ if s.sy in ('for', 'async'):
1499
+ # dict/set comprehension
1500
+ if len(parts) == 1 and isinstance(parts[0], list) and len(parts[0]) == 1:
1501
+ item = parts[0][0]
1502
+ if target_type == 2:
1503
+ assert isinstance(item, ExprNodes.DictItemNode), type(item)
1504
+ comprehension_type = Builtin.dict_type
1505
+ append = ExprNodes.DictComprehensionAppendNode(
1506
+ item.pos, key_expr=item.key, value_expr=item.value)
1507
+ else:
1508
+ comprehension_type = Builtin.set_type
1509
+ append = ExprNodes.ComprehensionAppendNode(item.pos, expr=item)
1510
+ loop = p_comp_for(s, append)
1511
+ s.expect('}')
1512
+ return ExprNodes.ComprehensionNode(pos, loop=loop, append=append, type=comprehension_type)
1513
+ else:
1514
+ # syntax error, try to find a good error message
1515
+ if len(parts) == 1 and not isinstance(parts[0], list):
1516
+ s.error("iterable unpacking cannot be used in comprehension")
1517
+ else:
1518
+ # e.g. "{1,2,3 for ..."
1519
+ s.expect('}')
1520
+ return ExprNodes.DictNode(pos, key_value_pairs=[])
1521
+
1522
+ s.expect('}')
1523
+ if target_type == 1:
1524
+ # (merged) set literal
1525
+ items = []
1526
+ set_items = []
1527
+ for part in parts:
1528
+ if isinstance(part, list):
1529
+ set_items.extend(part)
1530
+ else:
1531
+ if set_items:
1532
+ items.append(ExprNodes.SetNode(set_items[0].pos, args=set_items))
1533
+ set_items = []
1534
+ items.append(part)
1535
+ if set_items:
1536
+ items.append(ExprNodes.SetNode(set_items[0].pos, args=set_items))
1537
+ if len(items) == 1 and items[0].is_set_literal:
1538
+ return items[0]
1539
+ return ExprNodes.MergedSequenceNode(pos, args=items, type=Builtin.set_type)
1540
+ else:
1541
+ # (merged) dict literal
1542
+ items = []
1543
+ dict_items = []
1544
+ for part in parts:
1545
+ if isinstance(part, list):
1546
+ dict_items.extend(part)
1547
+ else:
1548
+ if dict_items:
1549
+ items.append(ExprNodes.DictNode(dict_items[0].pos, key_value_pairs=dict_items))
1550
+ dict_items = []
1551
+ items.append(part)
1552
+ if dict_items:
1553
+ items.append(ExprNodes.DictNode(dict_items[0].pos, key_value_pairs=dict_items))
1554
+ if len(items) == 1 and items[0].is_dict_literal:
1555
+ return items[0]
1556
+ return ExprNodes.MergedDictNode(pos, keyword_args=items, reject_duplicates=False)
1557
+
1558
+
1559
+ # NOTE: no longer in Py3 :)
1560
+ @cython.cfunc
1561
+ def p_backquote_expr(s: PyrexScanner):
1562
+ # s.sy == '`'
1563
+ pos = s.position()
1564
+ s.next()
1565
+ args = [p_test(s)]
1566
+ while s.sy == ',':
1567
+ s.next()
1568
+ args.append(p_test(s))
1569
+ s.expect('`')
1570
+ if len(args) == 1:
1571
+ arg = args[0]
1572
+ else:
1573
+ arg = ExprNodes.TupleNode(pos, args = args)
1574
+ return ExprNodes.BackquoteNode(pos, arg = arg)
1575
+
1576
+
1577
+ @cython.cfunc
1578
+ def p_simple_expr_list(s: PyrexScanner, expr=None) -> list:
1579
+ exprs: list = [expr] if expr is not None else []
1580
+ while s.sy not in expr_terminators:
1581
+ exprs.append( p_test(s) )
1582
+ if s.sy != ',':
1583
+ break
1584
+ s.next()
1585
+ return exprs
1586
+
1587
+
1588
+ @cython.cfunc
1589
+ def p_test_or_starred_expr_list(s: PyrexScanner, expr=None) -> list:
1590
+ exprs: list = [expr] if expr is not None else []
1591
+ while s.sy not in expr_terminators:
1592
+ exprs.append(p_test_or_starred_expr(s))
1593
+ if s.sy != ',':
1594
+ break
1595
+ s.next()
1596
+ return exprs
1597
+
1598
+
1599
+ @cython.cfunc
1600
+ def p_namedexpr_test_or_starred_expr_list(s: PyrexScanner, expr=None) -> list:
1601
+ exprs: list = [expr] if expr is not None else []
1602
+ while s.sy not in expr_terminators:
1603
+ exprs.append(p_namedexpr_test_or_starred_expr(s))
1604
+ if s.sy != ',':
1605
+ break
1606
+ s.next()
1607
+ return exprs
1608
+
1609
+
1610
+ #testlist: test (',' test)* [',']
1611
+
1612
+ @cython.cfunc
1613
+ def p_testlist(s: PyrexScanner):
1614
+ pos = s.position()
1615
+ expr = p_test(s)
1616
+ if s.sy == ',':
1617
+ s.next()
1618
+ exprs = p_simple_expr_list(s, expr)
1619
+ return ExprNodes.TupleNode(pos, args = exprs)
1620
+ else:
1621
+ return expr
1622
+
1623
+
1624
+ # testlist_star_expr: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
1625
+
1626
+ @cython.cfunc
1627
+ def p_testlist_star_expr(s: PyrexScanner):
1628
+ pos = s.position()
1629
+ expr = p_test_or_starred_expr(s)
1630
+ if s.sy == ',':
1631
+ s.next()
1632
+ exprs = p_test_or_starred_expr_list(s, expr)
1633
+ return ExprNodes.TupleNode(pos, args = exprs)
1634
+ else:
1635
+ return expr
1636
+
1637
+
1638
+ # testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
1639
+
1640
+ @cython.cfunc
1641
+ def p_testlist_comp(s: PyrexScanner):
1642
+ pos = s.position()
1643
+ expr = p_namedexpr_test_or_starred_expr(s)
1644
+ if s.sy == ',':
1645
+ s.next()
1646
+ exprs = p_namedexpr_test_or_starred_expr_list(s, expr)
1647
+ return ExprNodes.TupleNode(pos, args = exprs)
1648
+ elif s.sy in ('for', 'async'):
1649
+ return p_genexp(s, expr)
1650
+ else:
1651
+ return expr
1652
+
1653
+
1654
+ @cython.cfunc
1655
+ def p_genexp(s: PyrexScanner, expr):
1656
+ # s.sy == 'async' | 'for'
1657
+ loop = p_comp_for(s, Nodes.ExprStatNode(
1658
+ expr.pos, expr = ExprNodes.YieldExprNode(expr.pos, arg=expr)))
1659
+ return ExprNodes.GeneratorExpressionNode(expr.pos, loop=loop)
1660
+
1661
+
1662
+ expr_terminators = cython.declare(frozenset, frozenset((
1663
+ ')', ']', '}', ':', '=', 'NEWLINE', 'EOF')))
1664
+
1665
+
1666
+ #-------------------------------------------------------
1667
+ #
1668
+ # Statements
1669
+ #
1670
+ #-------------------------------------------------------
1671
+
1672
+ @cython.cfunc
1673
+ def p_global_statement(s: PyrexScanner):
1674
+ # assume s.sy == 'global'
1675
+ pos = s.position()
1676
+ s.next()
1677
+ names = p_ident_list(s)
1678
+ return Nodes.GlobalNode(pos, names = names)
1679
+
1680
+
1681
+ @cython.cfunc
1682
+ def p_nonlocal_statement(s: PyrexScanner):
1683
+ pos = s.position()
1684
+ s.next()
1685
+ names = p_ident_list(s)
1686
+ return Nodes.NonlocalNode(pos, names = names)
1687
+
1688
+
1689
+ @cython.cfunc
1690
+ def p_expression_or_assignment(s: PyrexScanner):
1691
+ expr = p_testlist_star_expr(s)
1692
+ has_annotation = False
1693
+ if s.sy == ':' and (expr.is_name or expr.is_subscript or expr.is_attribute):
1694
+ has_annotation = True
1695
+ s.next()
1696
+ expr.annotation = p_annotation(s)
1697
+
1698
+ if s.sy == '=' and expr.is_starred:
1699
+ # This is a common enough error to make when learning Cython to let
1700
+ # it fail as early as possible and give a very clear error message.
1701
+ s.error("a starred assignment target must be in a list or tuple"
1702
+ " - maybe you meant to use an index assignment: var[0] = ...",
1703
+ pos=expr.pos)
1704
+
1705
+ expr_list = [expr]
1706
+ while s.sy == '=':
1707
+ s.next()
1708
+ if s.sy == 'yield':
1709
+ expr = p_yield_expression(s)
1710
+ else:
1711
+ expr = p_testlist_star_expr(s)
1712
+ expr_list.append(expr)
1713
+ if len(expr_list) == 1:
1714
+ if re.match(r"([-+*/%^&|]|<<|>>|\*\*|//|@)=", s.sy):
1715
+ lhs = expr_list[0]
1716
+ if isinstance(lhs, ExprNodes.SliceIndexNode):
1717
+ # implementation requires IndexNode
1718
+ lhs = ExprNodes.IndexNode(
1719
+ lhs.pos,
1720
+ base=lhs.base,
1721
+ index=make_slice_node(lhs.pos, lhs.start, lhs.stop))
1722
+ elif not isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode, ExprNodes.NameNode)):
1723
+ error(lhs.pos, "Illegal operand for inplace operation.")
1724
+ operator = s.sy[:-1]
1725
+ s.next()
1726
+ if s.sy == 'yield':
1727
+ rhs = p_yield_expression(s)
1728
+ else:
1729
+ rhs = p_testlist(s)
1730
+ return Nodes.InPlaceAssignmentNode(lhs.pos, operator=operator, lhs=lhs, rhs=rhs)
1731
+ expr = expr_list[0]
1732
+ return Nodes.ExprStatNode(expr.pos, expr=expr)
1733
+
1734
+ rhs = expr_list[-1]
1735
+ if len(expr_list) == 2:
1736
+ return Nodes.SingleAssignmentNode(rhs.pos, lhs=expr_list[0], rhs=rhs, first=has_annotation)
1737
+ else:
1738
+ return Nodes.CascadedAssignmentNode(rhs.pos, lhs_list=expr_list[:-1], rhs=rhs)
1739
+
1740
+
1741
+ @cython.cfunc
1742
+ def p_print_statement(s: PyrexScanner):
1743
+ # s.sy == 'print'
1744
+ pos = s.position()
1745
+ ends_with_comma: cython.bint = False
1746
+ s.next()
1747
+ if s.sy == '>>':
1748
+ s.next()
1749
+ stream = p_test(s)
1750
+ if s.sy == ',':
1751
+ s.next()
1752
+ ends_with_comma = s.sy in ('NEWLINE', 'EOF')
1753
+ else:
1754
+ stream = None
1755
+ args = []
1756
+ if s.sy not in ('NEWLINE', 'EOF'):
1757
+ args.append(p_test(s))
1758
+ while s.sy == ',':
1759
+ s.next()
1760
+ if s.sy in ('NEWLINE', 'EOF'):
1761
+ ends_with_comma = True
1762
+ break
1763
+ args.append(p_test(s))
1764
+ arg_tuple = ExprNodes.TupleNode(pos, args=args)
1765
+ return Nodes.PrintStatNode(pos,
1766
+ arg_tuple=arg_tuple, stream=stream,
1767
+ append_newline=not ends_with_comma)
1768
+
1769
+
1770
+ @cython.cfunc
1771
+ def p_exec_statement(s: PyrexScanner):
1772
+ # s.sy == 'exec'
1773
+ pos = s.position()
1774
+ s.next()
1775
+ code = p_bit_expr(s)
1776
+ if isinstance(code, ExprNodes.TupleNode):
1777
+ # Py3 compatibility syntax
1778
+ tuple_variant = True
1779
+ args = code.args
1780
+ if len(args) not in (2, 3):
1781
+ s.error("expected tuple of length 2 or 3, got length %d" % len(args),
1782
+ pos=pos, fatal=False)
1783
+ args = [code]
1784
+ else:
1785
+ tuple_variant = False
1786
+ args = [code]
1787
+ if s.sy == 'in':
1788
+ if tuple_variant:
1789
+ s.error("tuple variant of exec does not support additional 'in' arguments",
1790
+ fatal=False)
1791
+ s.next()
1792
+ args.append(p_test(s))
1793
+ if s.sy == ',':
1794
+ s.next()
1795
+ args.append(p_test(s))
1796
+ return Nodes.ExecStatNode(pos, args=args)
1797
+
1798
+
1799
+ @cython.cfunc
1800
+ def p_del_statement(s: PyrexScanner):
1801
+ # s.sy == 'del'
1802
+ pos = s.position()
1803
+ s.next()
1804
+ # FIXME: 'exprlist' in Python
1805
+ args = p_simple_expr_list(s)
1806
+ return Nodes.DelStatNode(pos, args = args)
1807
+
1808
+
1809
+ @cython.cfunc
1810
+ def p_pass_statement(s: PyrexScanner, with_newline: cython.bint = False):
1811
+ pos = s.position()
1812
+ s.expect('pass')
1813
+ if with_newline:
1814
+ s.expect_newline("Expected a newline", ignore_semicolon=True)
1815
+ return Nodes.PassStatNode(pos)
1816
+
1817
+
1818
+ @cython.cfunc
1819
+ def p_break_statement(s: PyrexScanner):
1820
+ # s.sy == 'break'
1821
+ pos = s.position()
1822
+ s.next()
1823
+ return Nodes.BreakStatNode(pos)
1824
+
1825
+
1826
+ @cython.cfunc
1827
+ def p_continue_statement(s: PyrexScanner):
1828
+ # s.sy == 'continue'
1829
+ pos = s.position()
1830
+ s.next()
1831
+ return Nodes.ContinueStatNode(pos)
1832
+
1833
+
1834
+ @cython.cfunc
1835
+ def p_return_statement(s: PyrexScanner):
1836
+ # s.sy == 'return'
1837
+ pos = s.position()
1838
+ s.next()
1839
+ if s.sy not in statement_terminators:
1840
+ value = p_testlist(s)
1841
+ else:
1842
+ value = None
1843
+ return Nodes.ReturnStatNode(pos, value = value)
1844
+
1845
+
1846
+ @cython.cfunc
1847
+ def p_raise_statement(s: PyrexScanner):
1848
+ # s.sy == 'raise'
1849
+ pos = s.position()
1850
+ s.next()
1851
+ exc_type = None
1852
+ exc_value = None
1853
+ exc_tb = None
1854
+ cause = None
1855
+ if s.sy not in statement_terminators:
1856
+ exc_type = p_test(s)
1857
+ if s.sy == ',':
1858
+ s.next()
1859
+ exc_value = p_test(s)
1860
+ if s.sy == ',':
1861
+ s.next()
1862
+ exc_tb = p_test(s)
1863
+ elif s.sy == 'from':
1864
+ s.next()
1865
+ cause = p_test(s)
1866
+ if exc_type or exc_value or exc_tb:
1867
+ return Nodes.RaiseStatNode(pos,
1868
+ exc_type = exc_type,
1869
+ exc_value = exc_value,
1870
+ exc_tb = exc_tb,
1871
+ cause = cause)
1872
+ else:
1873
+ return Nodes.ReraiseStatNode(pos)
1874
+
1875
+
1876
+ @cython.cfunc
1877
+ def p_import_statement(s: PyrexScanner):
1878
+ # s.sy in ('import', 'cimport')
1879
+ pos = s.position()
1880
+ kind = s.sy
1881
+ s.next()
1882
+ items = [p_dotted_name(s, as_allowed=True)]
1883
+ while s.sy == ',':
1884
+ s.next()
1885
+ items.append(p_dotted_name(s, as_allowed=True))
1886
+ stats = []
1887
+ is_absolute = Future.absolute_import in s.context.future_directives
1888
+ for pos, target_name, dotted_name, as_name in items:
1889
+ if kind == 'cimport':
1890
+ stat = Nodes.CImportStatNode(
1891
+ pos,
1892
+ module_name=dotted_name,
1893
+ as_name=as_name,
1894
+ is_absolute=is_absolute)
1895
+ else:
1896
+ stat = Nodes.SingleAssignmentNode(
1897
+ pos,
1898
+ lhs=ExprNodes.NameNode(pos, name=as_name or target_name),
1899
+ rhs=ExprNodes.ImportNode(
1900
+ pos,
1901
+ module_name=ExprNodes.IdentifierStringNode(pos, value=dotted_name),
1902
+ is_import_as_name=bool(as_name),
1903
+ level=0 if is_absolute else None,
1904
+ imported_names=None))
1905
+ stats.append(stat)
1906
+ return Nodes.StatListNode(pos, stats=stats)
1907
+
1908
+
1909
+ @cython.cfunc
1910
+ def p_from_import_statement(s: PyrexScanner, first_statement: cython.bint = 0):
1911
+ # s.sy == 'from'
1912
+ pos = s.position()
1913
+ s.next()
1914
+ if s.sy in ('.', '...'):
1915
+ # count relative import level
1916
+ level = 0
1917
+ while s.sy in ('.', '...'):
1918
+ level += len(s.sy)
1919
+ s.next()
1920
+ else:
1921
+ level = None
1922
+ if level is not None and s.sy in ('import', 'cimport'):
1923
+ # we are dealing with "from .. import foo, bar"
1924
+ dotted_name_pos, dotted_name = s.position(), s.context.intern_ustring('')
1925
+ else:
1926
+ if level is None and Future.absolute_import in s.context.future_directives:
1927
+ level = 0
1928
+ (dotted_name_pos, _, dotted_name, _) = p_dotted_name(s, as_allowed=False)
1929
+ if s.sy not in ('import', 'cimport'):
1930
+ s.error("Expected 'import' or 'cimport'")
1931
+ kind = s.sy
1932
+ s.next()
1933
+
1934
+ is_cimport = kind == 'cimport'
1935
+ is_parenthesized = False
1936
+ if s.sy == '*':
1937
+ imported_names = [(s.position(), s.context.intern_ustring("*"), None)]
1938
+ s.next()
1939
+ else:
1940
+ if s.sy == '(':
1941
+ is_parenthesized = True
1942
+ s.next()
1943
+ imported_names = [p_imported_name(s)]
1944
+ while s.sy == ',':
1945
+ s.next()
1946
+ if is_parenthesized and s.sy == ')':
1947
+ break
1948
+ imported_names.append(p_imported_name(s))
1949
+ if is_parenthesized:
1950
+ s.expect(')')
1951
+ if dotted_name == '__future__':
1952
+ if not first_statement:
1953
+ s.error("from __future__ imports must occur at the beginning of the file")
1954
+ elif level:
1955
+ s.error("invalid syntax")
1956
+ else:
1957
+ for (name_pos, name, as_name) in imported_names:
1958
+ if name == "braces":
1959
+ s.error("not a chance", name_pos)
1960
+ break
1961
+ try:
1962
+ directive = getattr(Future, name)
1963
+ except AttributeError:
1964
+ s.error("future feature %s is not defined" % name, name_pos)
1965
+ break
1966
+ s.context.future_directives.add(directive)
1967
+ return Nodes.PassStatNode(pos)
1968
+ elif is_cimport:
1969
+ return Nodes.FromCImportStatNode(
1970
+ pos, module_name=dotted_name,
1971
+ relative_level=level,
1972
+ imported_names=imported_names)
1973
+ else:
1974
+ imported_name_strings = []
1975
+ items = []
1976
+ for (name_pos, name, as_name) in imported_names:
1977
+ imported_name_strings.append(
1978
+ ExprNodes.IdentifierStringNode(name_pos, value=name))
1979
+ items.append(
1980
+ (name, ExprNodes.NameNode(name_pos, name=as_name or name)))
1981
+ return Nodes.FromImportStatNode(pos,
1982
+ module = ExprNodes.ImportNode(dotted_name_pos,
1983
+ module_name = ExprNodes.IdentifierStringNode(pos, value = dotted_name),
1984
+ is_import_as_name = False,
1985
+ level = level,
1986
+ imported_names = imported_name_strings),
1987
+ items = items)
1988
+
1989
+
1990
+ @cython.cfunc
1991
+ def p_imported_name(s: PyrexScanner) -> tuple:
1992
+ pos = s.position()
1993
+ name = p_ident(s)
1994
+ as_name = p_as_name(s)
1995
+ return (pos, name, as_name)
1996
+
1997
+
1998
+ @cython.cfunc
1999
+ def p_dotted_name(s: PyrexScanner, as_allowed: cython.bint) -> tuple:
2000
+ pos = s.position()
2001
+ target_name = p_ident(s)
2002
+ as_name = None
2003
+ names = [target_name]
2004
+ while s.sy == '.':
2005
+ s.next()
2006
+ names.append(p_ident(s))
2007
+ if as_allowed:
2008
+ as_name = p_as_name(s)
2009
+ return (pos, target_name, s.context.intern_ustring('.'.join(names)), as_name)
2010
+
2011
+
2012
+ @cython.cfunc
2013
+ def p_as_name(s: PyrexScanner):
2014
+ if s.sy == 'IDENT' and s.systring == 'as':
2015
+ s.next()
2016
+ return p_ident(s)
2017
+ else:
2018
+ return None
2019
+
2020
+
2021
+ @cython.cfunc
2022
+ def p_assert_statement(s: PyrexScanner):
2023
+ # s.sy == 'assert'
2024
+ pos = s.position()
2025
+ s.next()
2026
+ cond = p_test(s)
2027
+ if s.sy == ',':
2028
+ s.next()
2029
+ value = p_test(s)
2030
+ else:
2031
+ value = None
2032
+ return Nodes.AssertStatNode(pos, condition=cond, value=value)
2033
+
2034
+
2035
+ @cython.cfunc
2036
+ def p_if_statement(s: PyrexScanner):
2037
+ # s.sy == 'if'
2038
+ pos = s.position()
2039
+ s.next()
2040
+ if_clauses = [p_if_clause(s)]
2041
+ while s.sy == 'elif':
2042
+ s.next()
2043
+ if_clauses.append(p_if_clause(s))
2044
+ else_clause = p_else_clause(s)
2045
+ return Nodes.IfStatNode(pos,
2046
+ if_clauses = if_clauses, else_clause = else_clause)
2047
+
2048
+
2049
+ @cython.cfunc
2050
+ def p_if_clause(s: PyrexScanner):
2051
+ pos = s.position()
2052
+ test = p_namedexpr_test(s)
2053
+ body = p_suite(s)
2054
+ return Nodes.IfClauseNode(pos,
2055
+ condition = test, body = body)
2056
+
2057
+
2058
+ @cython.cfunc
2059
+ def p_else_clause(s: PyrexScanner):
2060
+ if s.sy == 'else':
2061
+ s.next()
2062
+ return p_suite(s)
2063
+ else:
2064
+ return None
2065
+
2066
+
2067
+ @cython.cfunc
2068
+ def p_while_statement(s: PyrexScanner):
2069
+ # s.sy == 'while'
2070
+ pos = s.position()
2071
+ s.next()
2072
+ test = p_namedexpr_test(s)
2073
+ body = p_suite(s)
2074
+ else_clause = p_else_clause(s)
2075
+ return Nodes.WhileStatNode(pos,
2076
+ condition = test, body = body,
2077
+ else_clause = else_clause)
2078
+
2079
+
2080
+ @cython.cfunc
2081
+ def p_for_statement(s: PyrexScanner, is_async: cython.bint = False):
2082
+ # s.sy == 'for'
2083
+ pos = s.position()
2084
+ s.next()
2085
+ kw = p_for_bounds(s, allow_testlist=True, is_async=is_async)
2086
+ body = p_suite(s)
2087
+ else_clause = p_else_clause(s)
2088
+ kw.update(body=body, else_clause=else_clause, is_async=is_async)
2089
+ return Nodes.ForStatNode(pos, **kw)
2090
+
2091
+
2092
+ @cython.cfunc
2093
+ def p_for_bounds(s: PyrexScanner, allow_testlist: cython.bint = True, is_async: cython.bint = False) -> dict:
2094
+ target = p_for_target(s)
2095
+ if s.sy == 'in':
2096
+ s.next()
2097
+ iterator = p_for_iterator(s, allow_testlist, is_async=is_async)
2098
+ return dict(target=target, iterator=iterator)
2099
+ elif not s.in_python_file and not is_async:
2100
+ if s.sy == 'from':
2101
+ s.next()
2102
+ bound1 = p_bit_expr(s)
2103
+ else:
2104
+ # Support shorter "for a <= x < b" syntax
2105
+ bound1, target = target, None
2106
+ rel1 = p_for_from_relation(s)
2107
+ name2_pos = s.position()
2108
+ name2 = p_ident(s)
2109
+ rel2_pos = s.position()
2110
+ rel2 = p_for_from_relation(s)
2111
+ bound2 = p_bit_expr(s)
2112
+ step = p_for_from_step(s)
2113
+ if target is None:
2114
+ target = ExprNodes.NameNode(name2_pos, name = name2)
2115
+ else:
2116
+ if not target.is_name:
2117
+ error(target.pos,
2118
+ "Target of for-from statement must be a variable name")
2119
+ elif name2 != target.name:
2120
+ error(name2_pos,
2121
+ "Variable name in for-from range does not match target")
2122
+ if rel1[0] != rel2[0]:
2123
+ error(rel2_pos,
2124
+ "Relation directions in for-from do not match")
2125
+ return dict(target = target,
2126
+ bound1 = bound1,
2127
+ relation1 = rel1,
2128
+ relation2 = rel2,
2129
+ bound2 = bound2,
2130
+ step = step,
2131
+ )
2132
+ else:
2133
+ s.expect('in')
2134
+ return {}
2135
+
2136
+
2137
+ @cython.cfunc
2138
+ def p_for_from_relation(s: PyrexScanner):
2139
+ if s.sy in inequality_relations:
2140
+ op = s.sy
2141
+ s.next()
2142
+ return op
2143
+ else:
2144
+ s.error("Expected one of '<', '<=', '>' '>='")
2145
+
2146
+
2147
+ @cython.cfunc
2148
+ def p_for_from_step(s: PyrexScanner):
2149
+ if s.sy == 'IDENT' and s.systring == 'by':
2150
+ s.next()
2151
+ step = p_bit_expr(s)
2152
+ return step
2153
+ else:
2154
+ return None
2155
+
2156
+
2157
+ inequality_relations = cython.declare(frozenset, frozenset((
2158
+ '<', '<=', '>', '>=')))
2159
+
2160
+
2161
+ @cython.cfunc
2162
+ def p_target(s: PyrexScanner, terminator: str):
2163
+ pos = s.position()
2164
+ expr = p_starred_expr(s)
2165
+ if s.sy == ',':
2166
+ s.next()
2167
+ exprs = [expr]
2168
+ while s.sy != terminator:
2169
+ exprs.append(p_starred_expr(s))
2170
+ if s.sy != ',':
2171
+ break
2172
+ s.next()
2173
+ return ExprNodes.TupleNode(pos, args = exprs)
2174
+ else:
2175
+ return expr
2176
+
2177
+
2178
+ @cython.cfunc
2179
+ def p_for_target(s: PyrexScanner):
2180
+ return p_target(s, 'in')
2181
+
2182
+
2183
+ @cython.cfunc
2184
+ def p_for_iterator(s: PyrexScanner, allow_testlist: cython.bint = True, is_async: cython.bint = False):
2185
+ pos = s.position()
2186
+ if allow_testlist:
2187
+ expr = p_testlist(s)
2188
+ else:
2189
+ expr = p_or_test(s)
2190
+ return (ExprNodes.AsyncIteratorNode if is_async else ExprNodes.IteratorNode)(pos, sequence=expr)
2191
+
2192
+
2193
+ @cython.cfunc
2194
+ def p_try_statement(s: PyrexScanner):
2195
+ # s.sy == 'try'
2196
+ pos = s.position()
2197
+ s.next()
2198
+ body = p_suite(s)
2199
+ except_clauses = []
2200
+ else_clause = None
2201
+ if s.sy in ('except', 'else'):
2202
+ while s.sy == 'except':
2203
+ except_clauses.append(p_except_clause(s))
2204
+ if s.sy == 'else':
2205
+ s.next()
2206
+ else_clause = p_suite(s)
2207
+ body = Nodes.TryExceptStatNode(pos,
2208
+ body = body, except_clauses = except_clauses,
2209
+ else_clause = else_clause)
2210
+ if s.sy != 'finally':
2211
+ return body
2212
+ # try-except-finally is equivalent to nested try-except/try-finally
2213
+ if s.sy == 'finally':
2214
+ s.next()
2215
+ finally_clause = p_suite(s)
2216
+ return Nodes.TryFinallyStatNode(pos,
2217
+ body = body, finally_clause = finally_clause)
2218
+ else:
2219
+ s.error("Expected 'except' or 'finally'")
2220
+
2221
+
2222
+ @cython.cfunc
2223
+ def p_except_clause(s: PyrexScanner):
2224
+ # s.sy == 'except'
2225
+ pos = s.position()
2226
+ s.next()
2227
+ exc_type = None
2228
+ exc_value = None
2229
+ is_except_as = False
2230
+ if s.sy != ':':
2231
+ exc_type = p_test(s)
2232
+ # normalise into list of single exception tests
2233
+ if isinstance(exc_type, ExprNodes.TupleNode):
2234
+ exc_type = exc_type.args
2235
+ else:
2236
+ exc_type = [exc_type]
2237
+ if s.sy == ',' or (s.sy == 'IDENT' and s.systring == 'as'
2238
+ and s.context.language_level == 2):
2239
+ s.next()
2240
+ exc_value = p_test(s)
2241
+ elif s.sy == 'IDENT' and s.systring == 'as':
2242
+ # Py3 syntax requires a name here
2243
+ s.next()
2244
+ pos2 = s.position()
2245
+ name = p_ident(s)
2246
+ exc_value = ExprNodes.NameNode(pos2, name = name)
2247
+ is_except_as = True
2248
+ body = p_suite(s)
2249
+ return Nodes.ExceptClauseNode(pos,
2250
+ pattern = exc_type, target = exc_value,
2251
+ body = body, is_except_as=is_except_as)
2252
+
2253
+
2254
+ @cython.cfunc
2255
+ def p_include_statement(s: PyrexScanner, ctx):
2256
+ pos = s.position()
2257
+ s.next() # 'include'
2258
+ unicode_include_file_name = p_string_literal(s, 'u')[2]
2259
+ s.expect_newline("Syntax error in include statement")
2260
+ if s.compile_time_eval:
2261
+ include_file_name = unicode_include_file_name
2262
+ include_file_path = s.context.find_include_file(include_file_name, pos)
2263
+ if include_file_path:
2264
+ s.included_files.append(include_file_name)
2265
+ source_desc = FileSourceDescriptor(include_file_path)
2266
+ with source_desc.get_file_object() as f:
2267
+ s2 = PyrexScanner(f, source_desc, s, source_encoding=f.encoding, parse_comments=s.parse_comments)
2268
+ tree = p_statement_list(s2, ctx)
2269
+ return tree
2270
+ else:
2271
+ return None
2272
+ else:
2273
+ return Nodes.PassStatNode(pos)
2274
+
2275
+
2276
+ @cython.cfunc
2277
+ def p_with_statement(s: PyrexScanner):
2278
+ s.next() # 'with'
2279
+ if s.systring == 'template' and not s.in_python_file:
2280
+ node = p_with_template(s)
2281
+ else:
2282
+ node = p_with_items(s)
2283
+ return node
2284
+
2285
+
2286
+ @cython.cfunc
2287
+ def p_with_items(s: PyrexScanner, is_async: cython.bint = False):
2288
+ """
2289
+ Copied from CPython:
2290
+ | 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' b=block {
2291
+ _PyAST_With(a, b, NULL, EXTRA) }
2292
+ | 'with' a[asdl_withitem_seq*]=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
2293
+ _PyAST_With(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2294
+ Therefore the first thing to try is the bracket-enclosed
2295
+ version and if that fails try the regular version
2296
+ """
2297
+ brackets_succeeded = False
2298
+ items = () # unused, but static analysis fails to track that below
2299
+ if s.sy == '(':
2300
+ with tentatively_scan(s) as errors:
2301
+ s.next()
2302
+ items = p_with_items_list(s, is_async)
2303
+ s.expect(")")
2304
+ if s.sy != ":":
2305
+ # Fail - the message doesn't matter because we'll try the
2306
+ # non-bracket version so it'll never be shown
2307
+ s.error("")
2308
+ brackets_succeeded = not errors
2309
+ if not brackets_succeeded:
2310
+ # try the non-bracket version
2311
+ items = p_with_items_list(s, is_async)
2312
+ body = p_suite(s)
2313
+ for cls, pos, kwds in reversed(items):
2314
+ # construct the actual nodes now that we know what the body is
2315
+ body = cls(pos, body=body, **kwds)
2316
+ return body
2317
+
2318
+
2319
+ @cython.cfunc
2320
+ def p_with_items_list(s: PyrexScanner, is_async: cython.bint) -> list[tuple]:
2321
+ items = []
2322
+ while True:
2323
+ items.append(p_with_item(s, is_async))
2324
+ if s.sy != ",":
2325
+ break
2326
+ s.next()
2327
+ if s.sy == ")":
2328
+ # trailing commas allowed
2329
+ break
2330
+ return items
2331
+
2332
+
2333
+ @cython.cfunc
2334
+ def p_with_item(s: PyrexScanner, is_async: cython.bint) -> tuple:
2335
+ # In contrast to most parsing functions, this returns a tuple of
2336
+ # class, pos, kwd_dict
2337
+ # This is because GILStatNode does a reasonable amount of initialization in its
2338
+ # constructor, and requires "body" to be set, which we don't currently have
2339
+ pos = s.position()
2340
+ if not s.in_python_file and s.sy == 'IDENT' and s.systring in ('nogil', 'gil'):
2341
+ if is_async:
2342
+ s.error("with gil/nogil cannot be async")
2343
+ state = s.systring
2344
+ s.next()
2345
+
2346
+ # support conditional gil/nogil
2347
+ condition = None
2348
+ if s.sy == '(':
2349
+ s.next()
2350
+ condition = p_test(s)
2351
+ s.expect(')')
2352
+
2353
+ return Nodes.GILStatNode, pos, {"state": state, "condition": condition}
2354
+ else:
2355
+ manager = p_test(s)
2356
+ target = None
2357
+ if s.sy == 'IDENT' and s.systring == 'as':
2358
+ s.next()
2359
+ target = p_starred_expr(s)
2360
+ return Nodes.WithStatNode, pos, {"manager": manager, "target": target, "is_async": is_async}
2361
+
2362
+
2363
+ @cython.cfunc
2364
+ def p_with_template(s: PyrexScanner):
2365
+ pos = s.position()
2366
+ templates = []
2367
+ s.next()
2368
+ s.expect('[')
2369
+ templates.append(s.systring)
2370
+ s.next()
2371
+ while s.systring == ',':
2372
+ s.next()
2373
+ templates.append(s.systring)
2374
+ s.next()
2375
+ s.expect(']')
2376
+ if s.sy == ':':
2377
+ s.next()
2378
+ s.expect_newline("Syntax error in template function declaration")
2379
+ s.expect_indent()
2380
+ body_ctx = Ctx()
2381
+ body_ctx.templates = templates
2382
+ func_or_var = p_c_func_or_var_declaration(s, pos, body_ctx)
2383
+ s.expect_dedent()
2384
+ return func_or_var
2385
+ else:
2386
+ error(pos, "Syntax error in template function declaration")
2387
+
2388
+
2389
+ @cython.cfunc
2390
+ def p_simple_statement(s: PyrexScanner, first_statement: cython.bint = 0):
2391
+ #print "p_simple_statement:", s.sy, s.systring ###
2392
+ if s.sy == 'global':
2393
+ node = p_global_statement(s)
2394
+ elif s.sy == 'nonlocal':
2395
+ node = p_nonlocal_statement(s)
2396
+ elif s.sy == 'print':
2397
+ node = p_print_statement(s)
2398
+ elif s.sy == 'exec':
2399
+ node = p_exec_statement(s)
2400
+ elif s.sy == 'del':
2401
+ node = p_del_statement(s)
2402
+ elif s.sy == 'break':
2403
+ node = p_break_statement(s)
2404
+ elif s.sy == 'continue':
2405
+ node = p_continue_statement(s)
2406
+ elif s.sy == 'return':
2407
+ node = p_return_statement(s)
2408
+ elif s.sy == 'raise':
2409
+ node = p_raise_statement(s)
2410
+ elif s.sy in ('import', 'cimport'):
2411
+ node = p_import_statement(s)
2412
+ elif s.sy == 'from':
2413
+ node = p_from_import_statement(s, first_statement = first_statement)
2414
+ elif s.sy == 'yield':
2415
+ node = p_yield_statement(s)
2416
+ elif s.sy == 'assert':
2417
+ node = p_assert_statement(s)
2418
+ elif s.sy == 'pass':
2419
+ node = p_pass_statement(s)
2420
+ else:
2421
+ node = p_expression_or_assignment(s)
2422
+ return node
2423
+
2424
+
2425
+ @cython.cfunc
2426
+ def p_simple_statement_list(s: PyrexScanner, ctx, first_statement: cython.bint = 0):
2427
+ # Parse a series of simple statements on one line
2428
+ # separated by semicolons.
2429
+ stat = p_simple_statement(s, first_statement = first_statement)
2430
+ pos = stat.pos
2431
+ stats = []
2432
+ if not isinstance(stat, Nodes.PassStatNode):
2433
+ stats.append(stat)
2434
+ while s.sy == ';':
2435
+ #print "p_simple_statement_list: maybe more to follow" ###
2436
+ s.next()
2437
+ if s.sy in ('NEWLINE', 'EOF'):
2438
+ break
2439
+ stat = p_simple_statement(s, first_statement = first_statement)
2440
+ if isinstance(stat, Nodes.PassStatNode):
2441
+ continue
2442
+ stats.append(stat)
2443
+ first_statement = False
2444
+
2445
+ if not stats:
2446
+ stat = Nodes.PassStatNode(pos)
2447
+ elif len(stats) == 1:
2448
+ stat = stats[0]
2449
+ else:
2450
+ stat = Nodes.StatListNode(pos, stats = stats)
2451
+
2452
+ if s.sy not in ('NEWLINE', 'EOF'):
2453
+ # provide a better error message for users who accidentally write Cython code in .py files
2454
+ if isinstance(stat, Nodes.ExprStatNode):
2455
+ if stat.expr.is_name and stat.expr.name == 'cdef':
2456
+ s.error("The 'cdef' keyword is only allowed in Cython files (pyx/pxi/pxd)", pos)
2457
+ s.expect_newline("Syntax error in simple statement list")
2458
+
2459
+ return stat
2460
+
2461
+
2462
+ @cython.cfunc
2463
+ def p_compile_time_expr(s: PyrexScanner):
2464
+ old = s.compile_time_expr
2465
+ s.compile_time_expr = 1
2466
+ expr = p_testlist(s)
2467
+ s.compile_time_expr = old
2468
+ return expr
2469
+
2470
+
2471
+ @cython.cfunc
2472
+ def p_DEF_statement(s: PyrexScanner):
2473
+ pos = s.position()
2474
+ denv = s.compile_time_env
2475
+ s.next() # 'DEF'
2476
+ name = p_ident(s)
2477
+ s.expect('=')
2478
+ expr = p_compile_time_expr(s)
2479
+ if s.compile_time_eval:
2480
+ value = expr.compile_time_value(denv)
2481
+ #print "p_DEF_statement: %s = %r" % (name, value) ###
2482
+ denv.declare(name, value)
2483
+ s.expect_newline("Expected a newline", ignore_semicolon=True)
2484
+ return Nodes.PassStatNode(pos)
2485
+
2486
+
2487
+ @cython.cfunc
2488
+ def p_IF_statement(s: PyrexScanner, ctx):
2489
+ pos = s.position()
2490
+ saved_eval = s.compile_time_eval
2491
+ current_eval = saved_eval
2492
+ denv = s.compile_time_env
2493
+ result = None
2494
+ while 1:
2495
+ s.next() # 'IF' or 'ELIF'
2496
+ expr = p_compile_time_expr(s)
2497
+ s.compile_time_eval = current_eval and bool(expr.compile_time_value(denv))
2498
+ body = p_suite(s, ctx)
2499
+ if s.compile_time_eval:
2500
+ result = body
2501
+ current_eval = 0
2502
+ if s.sy != 'ELIF':
2503
+ break
2504
+ if s.sy == 'ELSE':
2505
+ s.next()
2506
+ s.compile_time_eval = current_eval
2507
+ body = p_suite(s, ctx)
2508
+ if current_eval:
2509
+ result = body
2510
+ if not result:
2511
+ result = Nodes.PassStatNode(pos)
2512
+ s.compile_time_eval = saved_eval
2513
+ return result
2514
+
2515
+
2516
+ @cython.cfunc
2517
+ def p_statement(s: PyrexScanner, ctx, first_statement: cython.bint = False):
2518
+ cdef_flag: cython.bint = ctx.cdef_flag
2519
+ pos = s.position()
2520
+ decorators = None
2521
+ if s.sy == 'ctypedef':
2522
+ if ctx.level not in ('module', 'module_pxd'):
2523
+ s.error("ctypedef statement not allowed here")
2524
+ #if ctx.api:
2525
+ # error(pos, "'api' not allowed with 'ctypedef'")
2526
+ return p_ctypedef_statement(s, ctx)
2527
+ elif s.sy == 'DEF':
2528
+ # We used to dep-warn about this but removed the warning again since
2529
+ # we don't have a good answer yet for all use cases.
2530
+ if s.context.compiler_directives.get("warn.deprecated.DEF", False):
2531
+ warning(pos,
2532
+ "The 'DEF' statement will be removed in a future Cython version. "
2533
+ "Consider using global variables, constants, and in-place literals instead. "
2534
+ "See https://github.com/cython/cython/issues/4310", level=1)
2535
+ return p_DEF_statement(s)
2536
+ elif s.sy == 'IF':
2537
+ if s.context.compiler_directives.get("warn.deprecated.IF", True):
2538
+ warning(pos,
2539
+ "The 'IF' statement is deprecated and will be removed in a future Cython version. "
2540
+ "Consider using runtime conditions or C macros instead. "
2541
+ "See https://github.com/cython/cython/issues/4310", level=1)
2542
+ return p_IF_statement(s, ctx)
2543
+ elif s.sy == '@':
2544
+ if ctx.level not in ('module', 'class', 'c_class', 'function', 'property', 'module_pxd', 'c_class_pxd', 'other'):
2545
+ s.error('decorator not allowed here')
2546
+ s.level = ctx.level
2547
+ decorators = p_decorators(s)
2548
+ if not ctx.allow_struct_enum_decorator and s.sy not in ('def', 'cdef', 'cpdef', 'class', 'async'):
2549
+ if s.sy == 'IDENT' and s.systring == 'async':
2550
+ pass # handled below
2551
+ else:
2552
+ s.error("Decorators can only be followed by functions or classes")
2553
+ elif s.sy == 'pass' and cdef_flag:
2554
+ # empty cdef block
2555
+ return p_pass_statement(s, with_newline=True)
2556
+
2557
+ overridable = False
2558
+ if s.sy == 'cdef':
2559
+ cdef_flag = True
2560
+ s.next()
2561
+ elif s.sy == 'cpdef':
2562
+ cdef_flag = True
2563
+ overridable = True
2564
+ s.next()
2565
+ if cdef_flag:
2566
+ if ctx.level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'):
2567
+ s.error('cdef statement not allowed here')
2568
+ s.level = ctx.level
2569
+ node = p_cdef_statement(s, pos, ctx(overridable=overridable))
2570
+ if decorators is not None:
2571
+ tup = (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode)
2572
+ if ctx.allow_struct_enum_decorator:
2573
+ tup += (Nodes.CStructOrUnionDefNode, Nodes.CEnumDefNode)
2574
+ if not isinstance(node, tup):
2575
+ s.error("Decorators can only be followed by functions or classes")
2576
+ node.decorators = decorators
2577
+ return node
2578
+ else:
2579
+ if ctx.api:
2580
+ s.error("'api' not allowed with this statement", fatal=False)
2581
+ elif s.sy == 'def':
2582
+ # def statements aren't allowed in pxd files, except
2583
+ # as part of a cdef class
2584
+ if ('pxd' in ctx.level) and (ctx.level != 'c_class_pxd'):
2585
+ s.error('def statement not allowed here')
2586
+ s.level = ctx.level
2587
+ return p_def_statement(s, decorators)
2588
+ elif s.sy == 'class':
2589
+ if ctx.level not in ('module', 'function', 'class', 'other'):
2590
+ s.error("class definition not allowed here")
2591
+ return p_class_statement(s, decorators)
2592
+ elif s.sy == 'include':
2593
+ if ctx.level not in ('module', 'module_pxd'):
2594
+ s.error("include statement not allowed here")
2595
+ return p_include_statement(s, ctx)
2596
+ elif ctx.level == 'c_class' and s.sy == 'IDENT' and s.systring == 'property':
2597
+ return p_property_decl(s)
2598
+ elif s.sy == 'pass' and ctx.level != 'property':
2599
+ return p_pass_statement(s, with_newline=True)
2600
+ else:
2601
+ if ctx.level in ('c_class_pxd', 'property'):
2602
+ node = p_ignorable_statement(s)
2603
+ if node is not None:
2604
+ return node
2605
+ s.error("Executable statement not allowed here")
2606
+ if s.sy == 'if':
2607
+ return p_if_statement(s)
2608
+ elif s.sy == 'while':
2609
+ return p_while_statement(s)
2610
+ elif s.sy == 'for':
2611
+ return p_for_statement(s)
2612
+ elif s.sy == 'try':
2613
+ return p_try_statement(s)
2614
+ elif s.sy == 'with':
2615
+ return p_with_statement(s)
2616
+ elif s.sy == 'async':
2617
+ s.next()
2618
+ return p_async_statement(s, ctx, decorators)
2619
+ else:
2620
+ if s.sy == 'IDENT' and s.systring == 'async':
2621
+ ident_name = s.systring
2622
+ ident_pos = s.position()
2623
+ # PEP 492 enables the async/await keywords when it spots "async def ..."
2624
+ s.next()
2625
+ if s.sy == 'def':
2626
+ return p_async_statement(s, ctx, decorators)
2627
+ elif decorators:
2628
+ s.error("Decorators can only be followed by functions or classes")
2629
+ s.put_back('IDENT', ident_name, ident_pos) # re-insert original token
2630
+ if s.sy == 'IDENT' and s.systring == 'match':
2631
+ # p_match_statement returns None on a "soft" initial failure
2632
+ match_statement = p_match_statement(s, ctx)
2633
+ if match_statement is not None:
2634
+ return match_statement
2635
+ return p_simple_statement_list(s, ctx, first_statement=first_statement)
2636
+
2637
+
2638
+ @cython.cfunc
2639
+ def p_statement_list(s: PyrexScanner, ctx, first_statement: cython.bint = 0):
2640
+ # Parse a series of statements separated by newlines.
2641
+ pos = s.position()
2642
+ stats = []
2643
+ while s.sy not in ('DEDENT', 'EOF'):
2644
+ stat = p_statement(s, ctx, first_statement = first_statement)
2645
+ if isinstance(stat, Nodes.PassStatNode):
2646
+ continue
2647
+ stats.append(stat)
2648
+ first_statement = False
2649
+ if not stats:
2650
+ return Nodes.PassStatNode(pos)
2651
+ elif len(stats) == 1:
2652
+ return stats[0]
2653
+ else:
2654
+ return Nodes.StatListNode(pos, stats = stats)
2655
+
2656
+
2657
+ @cython.cfunc
2658
+ def p_suite(s: PyrexScanner, ctx=Ctx()):
2659
+ return p_suite_with_docstring(s, ctx, with_doc_only=False)[1]
2660
+
2661
+
2662
+ @cython.cfunc
2663
+ def p_suite_with_docstring(s: PyrexScanner, ctx, with_doc_only: cython.bint = False) -> tuple:
2664
+ s.expect(':')
2665
+ doc = None
2666
+ if s.sy == 'NEWLINE':
2667
+ s.next()
2668
+ s.expect_indent()
2669
+ if with_doc_only:
2670
+ doc = p_doc_string(s)
2671
+ body = p_statement_list(s, ctx)
2672
+ s.expect_dedent()
2673
+ else:
2674
+ if ctx.api:
2675
+ s.error("'api' not allowed with this statement", fatal=False)
2676
+ if ctx.level in ('module', 'class', 'function', 'other'):
2677
+ body = p_simple_statement_list(s, ctx)
2678
+ else:
2679
+ body = p_pass_statement(s)
2680
+ s.expect_newline("Syntax error in declarations", ignore_semicolon=True)
2681
+ if not with_doc_only:
2682
+ doc, body = _extract_docstring(body)
2683
+ return doc, body
2684
+
2685
+
2686
+ @cython.cfunc
2687
+ def p_positional_and_keyword_args(s: PyrexScanner, end_sy_set, templates = None) -> tuple:
2688
+ """
2689
+ Parses positional and keyword arguments. end_sy_set
2690
+ should contain any s.sy that terminate the argument list.
2691
+ Argument expansion (* and **) are not allowed.
2692
+
2693
+ Returns: (positional_args, keyword_args)
2694
+ """
2695
+ positional_args = []
2696
+ keyword_args = []
2697
+ pos_idx = 0
2698
+
2699
+ while s.sy not in end_sy_set:
2700
+ if s.sy == '*' or s.sy == '**':
2701
+ s.error('Argument expansion not allowed here.', fatal=False)
2702
+
2703
+ parsed_type = False
2704
+ if s.sy == 'IDENT' and s.peek()[0] == '=':
2705
+ ident = s.systring
2706
+ s.next() # s.sy is '='
2707
+ s.next()
2708
+ if looking_at_expr(s):
2709
+ arg = p_test(s)
2710
+ else:
2711
+ base_type = p_c_base_type(s, templates = templates)
2712
+ declarator = p_c_declarator(s, empty=True)
2713
+ arg = Nodes.CComplexBaseTypeNode(base_type.pos,
2714
+ base_type = base_type, declarator = declarator)
2715
+ parsed_type = True
2716
+ keyword_node = ExprNodes.IdentifierStringNode(arg.pos, value=ident)
2717
+ keyword_args.append((keyword_node, arg))
2718
+ was_keyword = True
2719
+
2720
+ else:
2721
+ if looking_at_expr(s):
2722
+ arg = p_test(s)
2723
+ else:
2724
+ base_type = p_c_base_type(s, templates = templates)
2725
+ declarator = p_c_declarator(s, empty=True)
2726
+ arg = Nodes.CComplexBaseTypeNode(base_type.pos,
2727
+ base_type = base_type, declarator = declarator)
2728
+ parsed_type = True
2729
+ positional_args.append(arg)
2730
+ pos_idx += 1
2731
+ if len(keyword_args) > 0:
2732
+ s.error("Non-keyword arg following keyword arg",
2733
+ pos=arg.pos)
2734
+
2735
+ if s.sy != ',':
2736
+ if s.sy not in end_sy_set:
2737
+ if parsed_type:
2738
+ s.error("Unmatched %s" % " or ".join(end_sy_set))
2739
+ break
2740
+ s.next()
2741
+ return positional_args, keyword_args
2742
+
2743
+
2744
+ @cython.ccall
2745
+ def p_c_base_type(s: PyrexScanner, nonempty: cython.bint = False, templates=None):
2746
+ if s.sy == '(':
2747
+ return p_c_complex_base_type(s, templates = templates)
2748
+ else:
2749
+ return p_c_simple_base_type(s, nonempty=nonempty, templates=templates)
2750
+
2751
+
2752
+ @cython.cfunc
2753
+ def p_calling_convention(s: PyrexScanner):
2754
+ if s.sy == 'IDENT' and s.systring in calling_convention_words:
2755
+ result = s.systring
2756
+ s.next()
2757
+ return result
2758
+ else:
2759
+ return EncodedString("")
2760
+
2761
+
2762
+ calling_convention_words = cython.declare(frozenset, frozenset((
2763
+ "__stdcall", "__cdecl", "__fastcall")))
2764
+
2765
+
2766
+ @cython.cfunc
2767
+ def p_c_complex_base_type(s: PyrexScanner, templates = None):
2768
+ # s.sy == '('
2769
+ pos = s.position()
2770
+ s.next()
2771
+ base_type = p_c_base_type(s, templates=templates)
2772
+ declarator = p_c_declarator(s, empty=True)
2773
+ type_node = Nodes.CComplexBaseTypeNode(
2774
+ pos, base_type=base_type, declarator=declarator)
2775
+ if s.sy == ',':
2776
+ components = [type_node]
2777
+ while s.sy == ',':
2778
+ s.next()
2779
+ if s.sy == ')':
2780
+ break
2781
+ base_type = p_c_base_type(s, templates=templates)
2782
+ declarator = p_c_declarator(s, empty=True)
2783
+ components.append(Nodes.CComplexBaseTypeNode(
2784
+ pos, base_type=base_type, declarator=declarator))
2785
+ type_node = Nodes.CTupleBaseTypeNode(pos, components = components)
2786
+
2787
+ s.expect(')')
2788
+ if s.sy == '[':
2789
+ if is_memoryviewslice_access(s):
2790
+ type_node = p_memoryviewslice_access(s, type_node)
2791
+ else:
2792
+ type_node = p_buffer_or_template(s, type_node, templates)
2793
+ return type_node
2794
+
2795
+
2796
+ @cython.cfunc
2797
+ def p_c_simple_base_type(s: PyrexScanner, nonempty: cython.bint, templates=None):
2798
+ is_basic = False
2799
+ signed = 1
2800
+ longness = 0
2801
+ complex = False
2802
+ module_path = []
2803
+ pos = s.position()
2804
+
2805
+ # Handle const/volatile
2806
+ is_const = is_volatile = False
2807
+ while s.sy == 'IDENT':
2808
+ if s.systring == 'const':
2809
+ if is_const: error(pos, "Duplicate 'const'")
2810
+ is_const = True
2811
+ elif s.systring == 'volatile':
2812
+ if is_volatile: error(pos, "Duplicate 'volatile'")
2813
+ is_volatile = True
2814
+ else:
2815
+ break
2816
+ s.next()
2817
+ if is_const or is_volatile:
2818
+ base_type = p_c_base_type(s, nonempty=nonempty, templates=templates)
2819
+ if isinstance(base_type, Nodes.MemoryViewSliceTypeNode):
2820
+ # reverse order to avoid having to write "(const int)[:]"
2821
+ base_type.base_type_node = Nodes.CQualifierTypeNode(pos,
2822
+ base_type=base_type.base_type_node, is_const=is_const, is_volatile=is_volatile)
2823
+ return base_type
2824
+ return Nodes.CQualifierTypeNode(pos,
2825
+ base_type=base_type, is_const=is_const, is_volatile=is_volatile)
2826
+
2827
+ if s.sy != 'IDENT':
2828
+ error(pos, "Expected an identifier, found '%s'" % s.sy)
2829
+ if looking_at_base_type(s):
2830
+ #print "p_c_simple_base_type: looking_at_base_type at", s.position()
2831
+ is_basic = True
2832
+ if s.sy == 'IDENT' and s.systring in special_basic_c_types:
2833
+ signed, longness = special_basic_c_types[s.systring]
2834
+ name = s.systring
2835
+ s.next()
2836
+ else:
2837
+ signed, longness = p_sign_and_longness(s)
2838
+ if s.sy == 'IDENT' and s.systring in basic_c_type_names:
2839
+ name = s.systring
2840
+ s.next()
2841
+ else:
2842
+ name = 'int' # long [int], short [int], long [int] complex, etc.
2843
+ if s.sy == 'IDENT' and s.systring == 'complex':
2844
+ complex = True
2845
+ s.next()
2846
+ elif looking_at_dotted_name(s):
2847
+ #print "p_c_simple_base_type: looking_at_type_name at", s.position()
2848
+ name = s.systring
2849
+ s.next()
2850
+ while s.sy == '.':
2851
+ module_path.append(name)
2852
+ s.next()
2853
+ name = p_ident(s)
2854
+ else:
2855
+ name = s.systring
2856
+ name_pos = s.position()
2857
+ s.next()
2858
+ if nonempty and s.sy != 'IDENT':
2859
+ # Make sure this is not a declaration of a variable or function.
2860
+ if s.sy == '(':
2861
+ old_pos = s.position()
2862
+ s.next()
2863
+ if (s.sy == '*' or s.sy == '**' or s.sy == '&'
2864
+ or (s.sy == 'IDENT' and s.systring in calling_convention_words)):
2865
+ s.put_back('(', '(', old_pos)
2866
+ else:
2867
+ s.put_back('(', '(', old_pos)
2868
+ s.put_back('IDENT', name, name_pos)
2869
+ name = None
2870
+ elif s.sy not in ('*', '**', '[', '&'):
2871
+ s.put_back('IDENT', name, name_pos)
2872
+ name = None
2873
+
2874
+ type_node = Nodes.CSimpleBaseTypeNode(pos,
2875
+ name = name, module_path = module_path,
2876
+ is_basic_c_type = is_basic, signed = signed,
2877
+ complex = complex, longness = longness,
2878
+ templates = templates)
2879
+
2880
+ # declarations here.
2881
+ if s.sy == '[':
2882
+ if is_memoryviewslice_access(s):
2883
+ type_node = p_memoryviewslice_access(s, type_node)
2884
+ else:
2885
+ type_node = p_buffer_or_template(s, type_node, templates)
2886
+
2887
+ if s.sy == '.':
2888
+ s.next()
2889
+ name = p_ident(s)
2890
+ type_node = Nodes.CNestedBaseTypeNode(pos, base_type = type_node, name = name)
2891
+
2892
+ return type_node
2893
+
2894
+
2895
+ @cython.cfunc
2896
+ def p_buffer_or_template(s: PyrexScanner, base_type_node, templates):
2897
+ # s.sy == '['
2898
+ pos = s.position()
2899
+ s.next()
2900
+ # Note that buffer_positional_options_count=1, so the only positional argument is dtype.
2901
+ # For templated types, all parameters are types.
2902
+ positional_args, keyword_args = (
2903
+ p_positional_and_keyword_args(s, (']',), templates)
2904
+ )
2905
+ s.expect(']')
2906
+
2907
+ if s.sy == '[':
2908
+ base_type_node = p_buffer_or_template(s, base_type_node, templates)
2909
+
2910
+ keyword_dict = ExprNodes.DictNode(pos,
2911
+ key_value_pairs = [
2912
+ ExprNodes.DictItemNode(pos=key.pos, key=key, value=value)
2913
+ for key, value in keyword_args
2914
+ ])
2915
+ result = Nodes.TemplatedTypeNode(pos,
2916
+ positional_args = positional_args,
2917
+ keyword_args = keyword_dict,
2918
+ base_type_node = base_type_node)
2919
+ return result
2920
+
2921
+
2922
+ @cython.cfunc
2923
+ def is_memoryviewslice_access(s: PyrexScanner) -> cython.bint:
2924
+ # s.sy == '['
2925
+ # a memoryview slice declaration is distinguishable from a buffer access
2926
+ # declaration by the first entry in the bracketed list. The buffer will
2927
+ # not have an unnested colon in the first entry; the memoryview slice will.
2928
+ saved = [(s.sy, s.systring, s.position())]
2929
+ s.next()
2930
+ retval = False
2931
+ if s.systring == ':':
2932
+ retval = True
2933
+ elif s.sy == 'INT':
2934
+ saved.append((s.sy, s.systring, s.position()))
2935
+ s.next()
2936
+ if s.sy == ':':
2937
+ retval = True
2938
+
2939
+ for sv in saved[::-1]:
2940
+ s.put_back(*sv)
2941
+
2942
+ return retval
2943
+
2944
+
2945
+ @cython.cfunc
2946
+ def p_memoryviewslice_access(s: PyrexScanner, base_type_node):
2947
+ # s.sy == '['
2948
+ pos = s.position()
2949
+ s.next()
2950
+ subscripts, _ = p_subscript_list(s)
2951
+ # make sure each entry in subscripts is a slice
2952
+ for subscript in subscripts:
2953
+ if len(subscript) < 2:
2954
+ s.error("An axis specification in memoryview declaration does not have a ':'.")
2955
+ s.expect(']')
2956
+ indexes = make_slice_nodes(pos, subscripts)
2957
+ result = Nodes.MemoryViewSliceTypeNode(pos,
2958
+ base_type_node = base_type_node,
2959
+ axes = indexes)
2960
+ return result
2961
+
2962
+
2963
+ @cython.cfunc
2964
+ def looking_at_name(s: PyrexScanner) -> cython.bint:
2965
+ return s.sy == 'IDENT' and s.systring not in calling_convention_words
2966
+
2967
+
2968
+ @cython.cfunc
2969
+ def looking_at_expr(s: PyrexScanner) -> cython.bint:
2970
+ if s.systring in base_type_start_words:
2971
+ return False
2972
+ elif s.sy == 'IDENT':
2973
+ is_type = False
2974
+ name = s.systring
2975
+ name_pos = s.position()
2976
+ dotted_path = []
2977
+ s.next()
2978
+
2979
+ while s.sy == '.':
2980
+ s.next()
2981
+ dotted_path.append((s.systring, s.position()))
2982
+ s.expect('IDENT')
2983
+
2984
+ saved = s.sy, s.systring, s.position()
2985
+ if s.sy == 'IDENT':
2986
+ is_type = True
2987
+ elif s.sy == '*' or s.sy == '**':
2988
+ s.next()
2989
+ is_type = s.sy in (')', ']')
2990
+ s.put_back(*saved)
2991
+ elif s.sy == '(':
2992
+ s.next()
2993
+ is_type = s.sy == '*'
2994
+ s.put_back(*saved)
2995
+ elif s.sy == '[':
2996
+ s.next()
2997
+ is_type = s.sy == ']' or not looking_at_expr(s) # could be a nested template type
2998
+ s.put_back(*saved)
2999
+
3000
+ dotted_path.reverse()
3001
+ for p in dotted_path:
3002
+ s.put_back('IDENT', *p)
3003
+ s.put_back('.', '.', p[1]) # gets the position slightly wrong
3004
+
3005
+ s.put_back('IDENT', name, name_pos)
3006
+ return not is_type and saved[0]
3007
+ else:
3008
+ return True
3009
+
3010
+
3011
+ @cython.cfunc
3012
+ def looking_at_base_type(s: PyrexScanner) -> cython.bint:
3013
+ #print "looking_at_base_type?", s.sy, s.systring, s.position()
3014
+ return s.sy == 'IDENT' and s.systring in base_type_start_words
3015
+
3016
+
3017
+ @cython.cfunc
3018
+ def looking_at_dotted_name(s: PyrexScanner) -> cython.bint:
3019
+ if s.sy == 'IDENT':
3020
+ name = s.systring
3021
+ name_pos = s.position()
3022
+ s.next()
3023
+ result: cython.bint = s.sy == '.'
3024
+ s.put_back('IDENT', name, name_pos)
3025
+ return result
3026
+ else:
3027
+ return False
3028
+
3029
+
3030
+ basic_c_type_names = cython.declare(frozenset, frozenset((
3031
+ "void", "char", "int", "float", "double", "bint")))
3032
+
3033
+ special_basic_c_types = cython.declare(dict, {
3034
+ # name : (signed, longness)
3035
+ "Py_UNICODE" : (0, 0),
3036
+ "Py_UCS4" : (0, 0),
3037
+ "Py_hash_t" : (2, 0),
3038
+ "Py_ssize_t" : (2, 0),
3039
+ "ssize_t" : (2, 0),
3040
+ "size_t" : (0, 0),
3041
+ "ptrdiff_t" : (2, 0),
3042
+ "Py_tss_t" : (1, 0),
3043
+ })
3044
+
3045
+ sign_and_longness_words = cython.declare(frozenset, frozenset((
3046
+ "short", "long", "signed", "unsigned")))
3047
+
3048
+ base_type_start_words = cython.declare(
3049
+ frozenset,
3050
+ basic_c_type_names
3051
+ | sign_and_longness_words
3052
+ | frozenset(special_basic_c_types))
3053
+
3054
+ struct_enum_union = cython.declare(frozenset, frozenset((
3055
+ "struct", "union", "enum", "packed")))
3056
+
3057
+
3058
+ @cython.cfunc
3059
+ def p_sign_and_longness(s: PyrexScanner) -> tuple:
3060
+ signed = 1
3061
+ longness = 0
3062
+ while s.sy == 'IDENT' and s.systring in sign_and_longness_words:
3063
+ if s.systring == 'unsigned':
3064
+ signed = 0
3065
+ elif s.systring == 'signed':
3066
+ signed = 2
3067
+ elif s.systring == 'short':
3068
+ longness = -1
3069
+ elif s.systring == 'long':
3070
+ longness += 1
3071
+ s.next()
3072
+ return signed, longness
3073
+
3074
+
3075
+ @cython.cfunc
3076
+ def p_opt_cname(s: PyrexScanner):
3077
+ literal = p_opt_string_literal(s, 'u')
3078
+ if literal is not None:
3079
+ cname = EncodedString(literal)
3080
+ cname.encoding = s.source_encoding
3081
+ else:
3082
+ cname = None
3083
+ return cname
3084
+
3085
+
3086
+ @cython.ccall
3087
+ def p_c_declarator(s: PyrexScanner, ctx = Ctx(),
3088
+ empty: cython.bint = False, is_type: cython.bint = False, cmethod_flag: cython.bint = False,
3089
+ assignable: cython.bint = False, nonempty: cython.bint = False,
3090
+ calling_convention_allowed: cython.bint = False):
3091
+ # If empty is true, the declarator must be empty. If nonempty is true,
3092
+ # the declarator must be nonempty. Otherwise we don't care.
3093
+ # If cmethod_flag is true, then if this declarator declares
3094
+ # a function, it's a C method of an extension type.
3095
+ pos = s.position()
3096
+ if s.sy == '(':
3097
+ s.next()
3098
+ if s.sy == ')' or looking_at_name(s):
3099
+ base = Nodes.CNameDeclaratorNode(pos, name=s.context.intern_ustring(""), cname=None)
3100
+ result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag)
3101
+ else:
3102
+ result = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
3103
+ cmethod_flag = cmethod_flag,
3104
+ nonempty = nonempty,
3105
+ calling_convention_allowed = True)
3106
+ s.expect(')')
3107
+ else:
3108
+ result = p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
3109
+ assignable, nonempty)
3110
+ if not calling_convention_allowed and result.calling_convention and s.sy != '(':
3111
+ error(s.position(), "%s on something that is not a function"
3112
+ % result.calling_convention)
3113
+ while s.sy in ('[', '('):
3114
+ pos = s.position()
3115
+ if s.sy == '[':
3116
+ result = p_c_array_declarator(s, result)
3117
+ else: # sy == '('
3118
+ s.next()
3119
+ result = p_c_func_declarator(s, pos, ctx, result, cmethod_flag)
3120
+ cmethod_flag = 0
3121
+ return result
3122
+
3123
+
3124
+ @cython.cfunc
3125
+ def p_c_array_declarator(s: PyrexScanner, base):
3126
+ pos = s.position()
3127
+ s.next() # '['
3128
+ if s.sy != ']':
3129
+ dim = p_testlist(s)
3130
+ else:
3131
+ dim = None
3132
+ s.expect(']')
3133
+ return Nodes.CArrayDeclaratorNode(pos, base = base, dimension = dim)
3134
+
3135
+
3136
+ @cython.cfunc
3137
+ def p_c_func_declarator(s: PyrexScanner, pos, ctx, base, cmethod_flag: cython.bint):
3138
+ # Opening paren has already been skipped
3139
+ args = p_c_arg_list(s, ctx, cmethod_flag = cmethod_flag,
3140
+ nonempty_declarators = 0)
3141
+ ellipsis = p_optional_ellipsis(s)
3142
+ s.expect(')')
3143
+ nogil = p_nogil(s)
3144
+ exc_val, exc_check, exc_clause = p_exception_value_clause(s, ctx.visibility == 'extern')
3145
+ if nogil and exc_clause:
3146
+ warning(
3147
+ s.position(),
3148
+ "The keyword 'nogil' should appear at the end of the "
3149
+ "function signature line. Placing it before 'except' "
3150
+ "or 'noexcept' will be disallowed in a future version "
3151
+ "of Cython.",
3152
+ level=2
3153
+ )
3154
+ nogil = nogil or p_nogil(s)
3155
+ with_gil = p_with_gil(s)
3156
+ return Nodes.CFuncDeclaratorNode(pos,
3157
+ base = base, args = args, has_varargs = ellipsis,
3158
+ exception_value = exc_val, exception_check = exc_check,
3159
+ nogil = nogil or ctx.nogil or with_gil, with_gil = with_gil, has_explicit_exc_clause=exc_clause)
3160
+
3161
+
3162
+ supported_overloaded_operators = cython.declare(frozenset, frozenset((
3163
+ '+', '-', '*', '/', '%',
3164
+ '++', '--', '~', '|', '&', '^', '<<', '>>', ',',
3165
+ '==', '!=', '>=', '>', '<=', '<',
3166
+ '[]', '()', '!', '=',
3167
+ 'bool',
3168
+ )))
3169
+
3170
+
3171
+ @cython.cfunc
3172
+ def p_c_simple_declarator(s: PyrexScanner, ctx,
3173
+ empty: cython.bint, is_type: cython.bint, cmethod_flag: cython.bint,
3174
+ assignable: cython.bint, nonempty: cython.bint):
3175
+ pos = s.position()
3176
+ calling_convention = p_calling_convention(s)
3177
+ if s.sy in ('*', '**'):
3178
+ # scanner returns '**' as a single token
3179
+ is_ptrptr = s.sy == '**'
3180
+ s.next()
3181
+
3182
+ const_pos = s.position()
3183
+ is_restrict = is_const = False
3184
+ while s.sy == 'IDENT':
3185
+ if s.systring == 'const':
3186
+ if is_const: error(pos, "Duplicate 'const'")
3187
+ is_const = True
3188
+ elif s.systring == 'restrict':
3189
+ if is_restrict: error(pos, "Duplicate 'restrict'")
3190
+ is_restrict = True
3191
+ else:
3192
+ break
3193
+ s.next()
3194
+
3195
+ base = p_c_declarator(s, ctx, empty=empty, is_type=is_type,
3196
+ cmethod_flag=cmethod_flag,
3197
+ assignable=assignable, nonempty=nonempty)
3198
+ if is_const or is_restrict:
3199
+ base = Nodes.CQualifierDeclaratorNode(const_pos, base=base, is_const=is_const, is_restrict=is_restrict)
3200
+ if is_ptrptr:
3201
+ base = Nodes.CPtrDeclaratorNode(pos, base=base)
3202
+ result = Nodes.CPtrDeclaratorNode(pos, base=base)
3203
+ elif s.sy == '&' or (s.sy == '&&' and s.context.cpp):
3204
+ node_class = Nodes.CppRvalueReferenceDeclaratorNode if s.sy == '&&' else Nodes.CReferenceDeclaratorNode
3205
+ s.next()
3206
+ base = p_c_declarator(s, ctx, empty=empty, is_type=is_type,
3207
+ cmethod_flag=cmethod_flag,
3208
+ assignable=assignable, nonempty=nonempty)
3209
+ result = node_class(pos, base=base)
3210
+ else:
3211
+ rhs = None
3212
+ if s.sy == 'IDENT':
3213
+ name = s.systring
3214
+ if empty:
3215
+ error(s.position(), "Declarator should be empty")
3216
+ s.next()
3217
+ cname = p_opt_cname(s)
3218
+ if name != 'operator' and s.sy == '=' and assignable:
3219
+ s.next()
3220
+ rhs = p_test(s)
3221
+ else:
3222
+ if nonempty:
3223
+ error(s.position(), "Empty declarator")
3224
+ name = ""
3225
+ cname = None
3226
+ if cname is None and ctx.namespace is not None and nonempty:
3227
+ cname = ctx.namespace + "::" + name
3228
+ if name == 'operator' and ctx.visibility == 'extern' and nonempty:
3229
+ op = s.sy
3230
+ if [1 for c in op if c in '+-*/<=>!%&|([^~,']:
3231
+ s.next()
3232
+ # Handle diphthong operators.
3233
+ if op == '(':
3234
+ s.expect(')')
3235
+ op = '()'
3236
+ elif op == '[':
3237
+ s.expect(']')
3238
+ op = '[]'
3239
+ elif op in ('-', '+', '|', '&') and s.sy == op:
3240
+ op *= 2 # ++, --, ...
3241
+ s.next()
3242
+ elif s.sy == '=':
3243
+ op += s.sy # +=, -=, ...
3244
+ s.next()
3245
+ if op not in supported_overloaded_operators:
3246
+ s.error("Overloading operator '%s' not yet supported." % op,
3247
+ fatal=False)
3248
+ name += op
3249
+ elif op == 'IDENT':
3250
+ op = s.systring
3251
+ if op not in supported_overloaded_operators:
3252
+ s.error("Overloading operator '%s' not yet supported." % op,
3253
+ fatal=False)
3254
+ name = name + ' ' + op
3255
+ s.next()
3256
+ result = Nodes.CNameDeclaratorNode(pos,
3257
+ name = name, cname = cname, default = rhs)
3258
+ result.calling_convention = calling_convention
3259
+ return result
3260
+
3261
+
3262
+ @cython.cfunc
3263
+ def p_nogil(s: PyrexScanner) -> cython.bint:
3264
+ if s.sy == 'IDENT' and s.systring == 'nogil':
3265
+ s.next()
3266
+ return True
3267
+ else:
3268
+ return False
3269
+
3270
+
3271
+ @cython.cfunc
3272
+ def p_with_gil(s: PyrexScanner) -> cython.bint:
3273
+ if s.sy == 'with':
3274
+ s.next()
3275
+ s.expect_keyword('gil')
3276
+ return True
3277
+ else:
3278
+ return False
3279
+
3280
+
3281
+ @cython.cfunc
3282
+ def p_exception_value_clause(s: PyrexScanner, is_extern: cython.bint) -> tuple:
3283
+ """
3284
+ Parse exception value clause.
3285
+
3286
+ Maps clauses to exc_check / exc_value / exc_clause as follows:
3287
+ ______________________________________________________________________
3288
+ | | | | |
3289
+ | Clause | exc_check | exc_value | exc_clause |
3290
+ | ___________________________ | ___________ | ___________ | __________ |
3291
+ | | | | |
3292
+ | <nothing> (default func.) | True | None | False |
3293
+ | <nothing> (cdef extern) | False | None | False |
3294
+ | noexcept | False | None | True |
3295
+ | except <val> | False | <val> | True |
3296
+ | except? <val> | True | <val> | True |
3297
+ | except * | True | None | True |
3298
+ | except + | '+' | None | True |
3299
+ | except +* | '+' | '*' | True |
3300
+ | except +<PyErr> | '+' | <PyErr> | True |
3301
+ | ___________________________ | ___________ | ___________ | __________ |
3302
+
3303
+ Note that the only reason we need `exc_clause` is to raise a
3304
+ warning when `'except'` or `'noexcept'` is placed after the
3305
+ `'nogil'` keyword.
3306
+ """
3307
+ exc_clause: cython.bint = False
3308
+ exc_val = None
3309
+ exc_check = False if is_extern else True
3310
+
3311
+ if s.sy == 'IDENT' and s.systring == 'noexcept':
3312
+ exc_clause = True
3313
+ s.next()
3314
+ exc_check = False
3315
+ elif s.sy == 'except':
3316
+ exc_clause = True
3317
+ s.next()
3318
+ if s.sy == '*':
3319
+ exc_check = True
3320
+ s.next()
3321
+ elif s.sy == '+':
3322
+ exc_check = '+'
3323
+ plus_char_pos = s.position()[2]
3324
+ s.next()
3325
+ if s.sy == 'IDENT':
3326
+ name = s.systring
3327
+ if name == 'nogil':
3328
+ if s.position()[2] == plus_char_pos + 1:
3329
+ error(s.position(),
3330
+ "'except +nogil' defines an exception handling function. Use 'except + nogil' for the 'nogil' modifier.")
3331
+ # 'except + nogil' is parsed outside
3332
+ else:
3333
+ exc_val = p_name(s, name)
3334
+ s.next()
3335
+ elif s.sy == '*':
3336
+ exc_val = ExprNodes.CharNode(s.position(), value='*')
3337
+ s.next()
3338
+ else:
3339
+ if s.sy == '?':
3340
+ exc_check = True
3341
+ s.next()
3342
+ else:
3343
+ exc_check = False
3344
+ # exc_val can be non-None even if exc_check is False, c.f. "except -1"
3345
+ exc_val = p_test(s)
3346
+
3347
+ return exc_val, exc_check, exc_clause
3348
+
3349
+
3350
+ c_arg_list_terminators = cython.declare(frozenset, frozenset((
3351
+ '*', '**', '...', ')', ':', '/')))
3352
+
3353
+
3354
+ @cython.ccall
3355
+ def p_c_arg_list(s: PyrexScanner, ctx = Ctx(),
3356
+ in_pyfunc: cython.bint = False, cmethod_flag: cython.bint = False,
3357
+ nonempty_declarators: cython.bint = False, kw_only: cython.bint = False,
3358
+ annotated: cython.bint = True) -> list:
3359
+ # Comma-separated list of C argument declarations, possibly empty.
3360
+ # May have a trailing comma.
3361
+ args = []
3362
+ is_self_arg = cmethod_flag
3363
+ while s.sy not in c_arg_list_terminators:
3364
+ args.append(p_c_arg_decl(s, ctx, in_pyfunc, is_self_arg,
3365
+ nonempty = nonempty_declarators, kw_only = kw_only,
3366
+ annotated = annotated))
3367
+ if s.sy != ',':
3368
+ break
3369
+ s.next()
3370
+ is_self_arg = 0
3371
+ return args
3372
+
3373
+
3374
+ @cython.cfunc
3375
+ def p_optional_ellipsis(s: PyrexScanner) -> cython.bint:
3376
+ if s.sy == '...':
3377
+ expect_ellipsis(s)
3378
+ return True
3379
+ else:
3380
+ return False
3381
+
3382
+
3383
+ @cython.cfunc
3384
+ def p_c_arg_decl(s: PyrexScanner, ctx, in_pyfunc: cython.bint, cmethod_flag: cython.bint = False,
3385
+ nonempty: cython.bint = False,
3386
+ kw_only: cython.bint = False, annotated: cython.bint = True):
3387
+ pos = s.position()
3388
+ not_none = or_none = False
3389
+ default = None
3390
+ annotation = None
3391
+ if s.in_python_file:
3392
+ # empty type declaration
3393
+ base_type = Nodes.CSimpleBaseTypeNode(pos,
3394
+ name = None, module_path = [],
3395
+ is_basic_c_type = False, signed = 0,
3396
+ complex = False, longness = 0,
3397
+ is_self_arg = cmethod_flag, templates = None)
3398
+ else:
3399
+ base_type = p_c_base_type(s, nonempty=nonempty)
3400
+ declarator = p_c_declarator(s, ctx, nonempty = nonempty)
3401
+ if s.sy in ('not', 'or') and not s.in_python_file:
3402
+ kind = s.sy
3403
+ s.next()
3404
+ if s.sy == 'IDENT' and s.systring == 'None':
3405
+ s.next()
3406
+ else:
3407
+ s.error("Expected 'None'")
3408
+ if not in_pyfunc:
3409
+ error(pos, "'%s None' only allowed in Python functions" % kind)
3410
+ or_none = kind == 'or'
3411
+ not_none = kind == 'not'
3412
+ if annotated and s.sy == ':':
3413
+ s.next()
3414
+ annotation = p_annotation(s)
3415
+ if s.sy == '=':
3416
+ s.next()
3417
+ if 'pxd' in ctx.level:
3418
+ if s.sy in ['*', '?']:
3419
+ # TODO(github/1736): Make this an error for inline declarations.
3420
+ default = ExprNodes.NoneNode(pos)
3421
+ s.next()
3422
+ elif 'inline' in ctx.modifiers:
3423
+ default = p_test(s)
3424
+ else:
3425
+ error(pos, "default values cannot be specified in pxd files, use ? or *")
3426
+ else:
3427
+ default = p_test(s)
3428
+ return Nodes.CArgDeclNode(pos,
3429
+ base_type = base_type,
3430
+ declarator = declarator,
3431
+ not_none = not_none,
3432
+ or_none = or_none,
3433
+ default = default,
3434
+ annotation = annotation,
3435
+ kw_only = kw_only)
3436
+
3437
+
3438
+ @cython.cfunc
3439
+ def p_annotation(s: PyrexScanner):
3440
+ """An annotation just has the "test" syntax, but also stores the string it came from
3441
+
3442
+ Note that the string is *allowed* to be changed/processed (although isn't here)
3443
+ so may not exactly match the string generated by Python, and if it doesn't
3444
+ then it is not a bug.
3445
+ """
3446
+ pos = s.position()
3447
+ expr = p_test(s)
3448
+ return ExprNodes.AnnotationNode(pos, expr=expr)
3449
+
3450
+
3451
+ @cython.cfunc
3452
+ def p_api(s: PyrexScanner) -> cython.bint:
3453
+ if s.sy == 'IDENT' and s.systring == 'api':
3454
+ s.next()
3455
+ return True
3456
+ else:
3457
+ return False
3458
+
3459
+
3460
+ @cython.cfunc
3461
+ def p_cdef_statement(s: PyrexScanner, pos, ctx):
3462
+ ctx.visibility = p_visibility(s, ctx.visibility)
3463
+ ctx.api = ctx.api or p_api(s)
3464
+ if ctx.api:
3465
+ if ctx.visibility not in ('private', 'public'):
3466
+ error(pos, "Cannot combine 'api' with '%s'" % ctx.visibility)
3467
+ if (ctx.visibility == 'extern') and s.sy == 'from':
3468
+ return p_cdef_extern_block(s, pos, ctx)
3469
+ elif s.sy == 'import':
3470
+ s.next()
3471
+ return p_cdef_extern_block(s, pos, ctx)
3472
+ elif p_nogil(s):
3473
+ ctx.nogil = True
3474
+ if ctx.overridable:
3475
+ error(pos, "cdef blocks cannot be declared cpdef")
3476
+ return p_cdef_block(s, ctx)
3477
+ elif s.sy == ':':
3478
+ if ctx.overridable:
3479
+ error(pos, "cdef blocks cannot be declared cpdef")
3480
+ return p_cdef_block(s, ctx)
3481
+ elif s.sy == 'class':
3482
+ if ctx.level not in ('module', 'module_pxd'):
3483
+ error(pos, "Extension type definition not allowed here")
3484
+ if ctx.overridable:
3485
+ error(pos, "Extension types cannot be declared cpdef")
3486
+ return p_c_class_definition(s, pos, ctx)
3487
+ elif s.sy == 'IDENT' and s.systring == 'cppclass':
3488
+ return p_cpp_class_definition(s, pos, ctx)
3489
+ elif s.sy == 'IDENT' and s.systring in struct_enum_union:
3490
+ if ctx.level not in ('module', 'module_pxd'):
3491
+ error(pos, "C struct/union/enum definition not allowed here")
3492
+ if ctx.overridable:
3493
+ if s.systring != 'enum':
3494
+ error(pos, "C struct/union cannot be declared cpdef")
3495
+ return p_struct_enum(s, pos, ctx)
3496
+ elif s.sy == 'IDENT' and s.systring == 'fused':
3497
+ return p_fused_definition(s, pos, ctx)
3498
+ else:
3499
+ return p_c_func_or_var_declaration(s, pos, ctx)
3500
+
3501
+
3502
+ @cython.cfunc
3503
+ def p_cdef_block(s: PyrexScanner, ctx):
3504
+ return p_suite(s, ctx(cdef_flag = True))
3505
+
3506
+
3507
+ @cython.cfunc
3508
+ def p_cdef_extern_block(s: PyrexScanner, pos, ctx):
3509
+ if ctx.overridable:
3510
+ error(pos, "cdef extern blocks cannot be declared cpdef")
3511
+ include_file = None
3512
+ s.expect('from')
3513
+ if s.sy == '*':
3514
+ s.next()
3515
+ else:
3516
+ include_file = p_string_literal(s, 'u')[2]
3517
+ ctx = ctx(cdef_flag = True, visibility = 'extern')
3518
+ if s.systring == "namespace":
3519
+ s.next()
3520
+ ctx.namespace = p_string_literal(s, 'u')[2]
3521
+ if p_nogil(s):
3522
+ ctx.nogil = True
3523
+
3524
+ # Use "docstring" as verbatim string to include
3525
+ verbatim_include, body = p_suite_with_docstring(s, ctx, True)
3526
+
3527
+ return Nodes.CDefExternNode(pos,
3528
+ include_file = include_file,
3529
+ verbatim_include = verbatim_include,
3530
+ body = body,
3531
+ namespace = ctx.namespace)
3532
+
3533
+
3534
+ @cython.cfunc
3535
+ def p_c_enum_definition(s: PyrexScanner, pos, ctx):
3536
+ # s.sy == ident 'enum'
3537
+ s.next()
3538
+
3539
+ scoped = False
3540
+ if s.context.cpp and (s.sy == 'class' or (s.sy == 'IDENT' and s.systring == 'struct')):
3541
+ scoped = True
3542
+ s.next()
3543
+
3544
+ if s.sy == 'IDENT':
3545
+ name = s.systring
3546
+ s.next()
3547
+ cname = p_opt_cname(s)
3548
+ if cname is None and ctx.namespace is not None:
3549
+ cname = ctx.namespace + "::" + name
3550
+ else:
3551
+ name = cname = None
3552
+ if scoped:
3553
+ s.error("Unnamed scoped enum not allowed")
3554
+
3555
+ if scoped and s.sy == '(':
3556
+ s.next()
3557
+ underlying_type = p_c_base_type(s)
3558
+ s.expect(')')
3559
+ else:
3560
+ underlying_type = Nodes.CSimpleBaseTypeNode(
3561
+ pos,
3562
+ name="int",
3563
+ module_path = [],
3564
+ is_basic_c_type = True,
3565
+ signed = 1,
3566
+ complex = False,
3567
+ longness = 0
3568
+ )
3569
+
3570
+ s.expect(':')
3571
+ items = []
3572
+
3573
+ doc = None
3574
+ if s.sy != 'NEWLINE':
3575
+ p_c_enum_line(s, ctx, items)
3576
+ else:
3577
+ s.next() # 'NEWLINE'
3578
+ s.expect_indent()
3579
+ doc = p_doc_string(s)
3580
+
3581
+ while s.sy not in ('DEDENT', 'EOF'):
3582
+ p_c_enum_line(s, ctx, items)
3583
+
3584
+ s.expect_dedent()
3585
+
3586
+ if not items and ctx.visibility != "extern":
3587
+ error(pos, "Empty enum definition not allowed outside a 'cdef extern from' block")
3588
+
3589
+ return Nodes.CEnumDefNode(
3590
+ pos, name=name, cname=cname,
3591
+ scoped=scoped, items=items,
3592
+ underlying_type=underlying_type,
3593
+ typedef_flag=ctx.typedef_flag, visibility=ctx.visibility,
3594
+ create_wrapper=ctx.overridable,
3595
+ api=ctx.api, in_pxd=ctx.level == 'module_pxd', doc=doc)
3596
+
3597
+
3598
+ @cython.cfunc
3599
+ def p_c_enum_line(s: PyrexScanner, ctx, items: list):
3600
+ if s.sy != 'pass':
3601
+ p_c_enum_item(s, ctx, items)
3602
+ while s.sy == ',':
3603
+ s.next()
3604
+ if s.sy in ('NEWLINE', 'EOF'):
3605
+ break
3606
+ p_c_enum_item(s, ctx, items)
3607
+ else:
3608
+ s.next()
3609
+ s.expect_newline("Syntax error in enum item list")
3610
+
3611
+
3612
+ @cython.cfunc
3613
+ def p_c_enum_item(s: PyrexScanner, ctx, items: list):
3614
+ pos = s.position()
3615
+ name = p_ident(s)
3616
+ cname = p_opt_cname(s)
3617
+ if cname is None and ctx.namespace is not None:
3618
+ cname = ctx.namespace + "::" + name
3619
+ value = None
3620
+ if s.sy == '=':
3621
+ s.next()
3622
+ value = p_test(s)
3623
+ items.append(Nodes.CEnumDefItemNode(pos,
3624
+ name = name, cname = cname, value = value))
3625
+
3626
+
3627
+ @cython.cfunc
3628
+ def p_c_struct_or_union_definition(s: PyrexScanner, pos, ctx):
3629
+ packed = False
3630
+ if s.systring == 'packed':
3631
+ packed = True
3632
+ s.next()
3633
+ if s.sy != 'IDENT' or s.systring != 'struct':
3634
+ s.expected('struct')
3635
+ # s.sy == ident 'struct' or 'union'
3636
+ kind = s.systring
3637
+ s.next()
3638
+ name = p_ident(s)
3639
+ cname = p_opt_cname(s)
3640
+ if cname is None and ctx.namespace is not None:
3641
+ cname = ctx.namespace + "::" + name
3642
+ attributes = None
3643
+ if s.sy == ':':
3644
+ s.next()
3645
+ attributes = []
3646
+ if s.sy == 'pass':
3647
+ s.next()
3648
+ s.expect_newline("Expected a newline", ignore_semicolon=True)
3649
+ else:
3650
+ s.expect('NEWLINE')
3651
+ s.expect_indent()
3652
+ body_ctx = Ctx(visibility=ctx.visibility)
3653
+ while s.sy != 'DEDENT':
3654
+ if s.sy != 'pass':
3655
+ attributes.append(
3656
+ p_c_func_or_var_declaration(s, s.position(), body_ctx))
3657
+ else:
3658
+ s.next()
3659
+ s.expect_newline("Expected a newline")
3660
+ s.expect_dedent()
3661
+
3662
+ if not attributes and ctx.visibility != "extern":
3663
+ error(pos, "Empty struct or union definition not allowed outside a 'cdef extern from' block")
3664
+ else:
3665
+ s.expect_newline("Syntax error in struct or union definition")
3666
+
3667
+ return Nodes.CStructOrUnionDefNode(pos,
3668
+ name = name, cname = cname, kind = kind, attributes = attributes,
3669
+ typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
3670
+ api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
3671
+
3672
+
3673
+ @cython.cfunc
3674
+ def p_fused_definition(s: PyrexScanner, pos, ctx):
3675
+ """
3676
+ c(type)def fused my_fused_type:
3677
+ ...
3678
+ """
3679
+ # s.systring == 'fused'
3680
+
3681
+ if ctx.level not in ('module', 'module_pxd'):
3682
+ error(pos, "Fused type definition not allowed here")
3683
+
3684
+ s.next()
3685
+ name = p_ident(s)
3686
+
3687
+ s.expect(":")
3688
+ s.expect_newline()
3689
+ s.expect_indent()
3690
+
3691
+ types = []
3692
+ while s.sy != 'DEDENT':
3693
+ if s.sy != 'pass':
3694
+ #types.append(p_c_declarator(s))
3695
+ types.append(p_c_base_type(s)) #, nonempty=1))
3696
+ else:
3697
+ s.next()
3698
+
3699
+ s.expect_newline()
3700
+
3701
+ s.expect_dedent()
3702
+
3703
+ if not types:
3704
+ error(pos, "Need at least one type")
3705
+
3706
+ return Nodes.FusedTypeNode(pos, name=name, types=types)
3707
+
3708
+
3709
+ @cython.cfunc
3710
+ def p_struct_enum(s: PyrexScanner, pos, ctx):
3711
+ if s.systring == 'enum':
3712
+ return p_c_enum_definition(s, pos, ctx)
3713
+ else:
3714
+ return p_c_struct_or_union_definition(s, pos, ctx)
3715
+
3716
+
3717
+ @cython.cfunc
3718
+ def p_visibility(s: PyrexScanner, prev_visibility):
3719
+ visibility = prev_visibility
3720
+ if s.sy == 'IDENT' and s.systring in ('extern', 'public', 'readonly'):
3721
+ visibility = s.systring
3722
+ if prev_visibility != 'private' and visibility != prev_visibility:
3723
+ s.error("Conflicting visibility options '%s' and '%s'"
3724
+ % (prev_visibility, visibility), fatal=False)
3725
+ s.next()
3726
+ return visibility
3727
+
3728
+
3729
+ @cython.cfunc
3730
+ def p_c_modifiers(s: PyrexScanner) -> list:
3731
+ if s.sy == 'IDENT' and s.systring in ('inline',):
3732
+ modifier = s.systring
3733
+ s.next()
3734
+ return [modifier] + p_c_modifiers(s)
3735
+ return []
3736
+
3737
+
3738
+ @cython.cfunc
3739
+ def p_c_func_or_var_declaration(s: PyrexScanner, pos, ctx):
3740
+ cmethod_flag: cython.bint = ctx.level in ('c_class', 'c_class_pxd')
3741
+ modifiers = p_c_modifiers(s)
3742
+ base_type = p_c_base_type(s, nonempty=True, templates = ctx.templates)
3743
+ declarator = p_c_declarator(s, ctx(modifiers=modifiers), cmethod_flag = cmethod_flag,
3744
+ assignable=True, nonempty =True)
3745
+ declarator.overridable = ctx.overridable
3746
+
3747
+ if s.sy == 'IDENT' and s.systring == 'const' and ctx.level == 'cpp_class':
3748
+ s.next()
3749
+ is_const_method = True
3750
+ else:
3751
+ is_const_method = False
3752
+
3753
+ if s.sy == '->':
3754
+ # Special enough to give a better error message and keep going.
3755
+ s.error(
3756
+ "Return type annotation is not allowed in cdef/cpdef signatures. "
3757
+ "Please define it before the function name, as in C signatures.",
3758
+ fatal=False)
3759
+ s.next()
3760
+ p_test(s) # Keep going, but ignore result.
3761
+
3762
+ if s.sy == ':':
3763
+ if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class') and not ctx.templates:
3764
+ s.error("C function definition not allowed here")
3765
+ doc, suite = p_suite_with_docstring(s, Ctx(level='function'))
3766
+ result = Nodes.CFuncDefNode(pos,
3767
+ visibility = ctx.visibility,
3768
+ base_type = base_type,
3769
+ declarator = declarator,
3770
+ body = suite,
3771
+ doc = doc,
3772
+ modifiers = modifiers,
3773
+ api = ctx.api,
3774
+ overridable = ctx.overridable,
3775
+ is_const_method = is_const_method)
3776
+ else:
3777
+ #if api:
3778
+ # s.error("'api' not allowed with variable declaration")
3779
+ if is_const_method:
3780
+ declarator.is_const_method = is_const_method
3781
+ declarators = [declarator]
3782
+ while s.sy == ',':
3783
+ s.next()
3784
+ if s.sy == 'NEWLINE':
3785
+ break
3786
+ declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag,
3787
+ assignable=True, nonempty=True)
3788
+ declarators.append(declarator)
3789
+ doc_line = s.start_line + 1
3790
+ s.expect_newline("Syntax error in C variable declaration", ignore_semicolon=True)
3791
+ if ctx.level in ('c_class', 'c_class_pxd') and s.start_line == doc_line:
3792
+ doc = p_doc_string(s)
3793
+ else:
3794
+ doc = None
3795
+ result = Nodes.CVarDefNode(pos,
3796
+ visibility = ctx.visibility,
3797
+ base_type = base_type,
3798
+ declarators = declarators,
3799
+ in_pxd = ctx.level in ('module_pxd', 'c_class_pxd'),
3800
+ doc = doc,
3801
+ api = ctx.api,
3802
+ modifiers = modifiers,
3803
+ overridable = ctx.overridable)
3804
+ return result
3805
+
3806
+
3807
+ @cython.cfunc
3808
+ def p_ctypedef_statement(s: PyrexScanner, ctx):
3809
+ # s.sy == 'ctypedef'
3810
+ pos = s.position()
3811
+ s.next()
3812
+ visibility = p_visibility(s, ctx.visibility)
3813
+ api = p_api(s)
3814
+ ctx = ctx(typedef_flag=True, visibility = visibility)
3815
+ if api:
3816
+ ctx.api = True
3817
+ if s.sy == 'class':
3818
+ return p_c_class_definition(s, pos, ctx)
3819
+ elif s.sy == 'IDENT' and s.systring in struct_enum_union:
3820
+ return p_struct_enum(s, pos, ctx)
3821
+ elif s.sy == 'IDENT' and s.systring == 'fused':
3822
+ return p_fused_definition(s, pos, ctx)
3823
+ else:
3824
+ base_type = p_c_base_type(s, nonempty=True)
3825
+ declarator = p_c_declarator(s, ctx, is_type=True, nonempty=True)
3826
+ s.expect_newline("Syntax error in ctypedef statement", ignore_semicolon=True)
3827
+ return Nodes.CTypeDefNode(
3828
+ pos, base_type = base_type,
3829
+ declarator = declarator,
3830
+ visibility = visibility, api = api,
3831
+ in_pxd = ctx.level == 'module_pxd')
3832
+
3833
+
3834
+ @cython.cfunc
3835
+ def p_decorators(s: PyrexScanner) -> list:
3836
+ decorators = []
3837
+ while s.sy == '@':
3838
+ pos = s.position()
3839
+ s.next()
3840
+ decorator = p_namedexpr_test(s)
3841
+ decorators.append(Nodes.DecoratorNode(pos, decorator=decorator))
3842
+ s.expect_newline("Expected a newline after decorator")
3843
+ return decorators
3844
+
3845
+
3846
+ @cython.cfunc
3847
+ def _reject_cdef_modifier_in_py(s: PyrexScanner, name):
3848
+ """Step over incorrectly placed cdef modifiers (@see _CDEF_MODIFIERS) to provide a good error message for them.
3849
+ """
3850
+ if s.sy == 'IDENT' and name in _CDEF_MODIFIERS:
3851
+ # Special enough to provide a good error message.
3852
+ s.error("Cannot use cdef modifier '%s' in Python function signature. Use a decorator instead." % name, fatal=False)
3853
+ return p_ident(s) # Keep going, in case there are other errors.
3854
+ return name
3855
+
3856
+
3857
+ @cython.cfunc
3858
+ def p_def_statement(s: PyrexScanner, decorators: list = None, is_async_def: cython.bint = False):
3859
+ # s.sy == 'def'
3860
+ pos = decorators[0].pos if decorators else s.position()
3861
+ # PEP 492 switches the async/await keywords on in "async def" functions
3862
+ if is_async_def:
3863
+ s.enter_async()
3864
+ s.next()
3865
+ name = _reject_cdef_modifier_in_py(s, p_ident(s))
3866
+ s.expect(
3867
+ '(',
3868
+ "Expected '(', found '%s'. Did you use cdef syntax in a Python declaration? "
3869
+ "Use decorators and Python type annotations instead." % (
3870
+ s.systring if s.sy == 'IDENT' else s.sy))
3871
+ args, star_arg, starstar_arg = p_varargslist(s, terminator=')')
3872
+ s.expect(')')
3873
+ _reject_cdef_modifier_in_py(s, s.systring)
3874
+ return_type_annotation = None
3875
+ if s.sy == '->':
3876
+ s.next()
3877
+ return_type_annotation = p_annotation(s)
3878
+ _reject_cdef_modifier_in_py(s, s.systring)
3879
+
3880
+ doc, body = p_suite_with_docstring(s, Ctx(level='function'))
3881
+ if is_async_def:
3882
+ s.exit_async()
3883
+
3884
+ return Nodes.DefNode(
3885
+ pos, name=name, args=args, star_arg=star_arg, starstar_arg=starstar_arg,
3886
+ doc=doc, body=body, decorators=decorators, is_async_def=is_async_def,
3887
+ return_type_annotation=return_type_annotation)
3888
+
3889
+
3890
+ @cython.cfunc
3891
+ def p_varargslist(s: PyrexScanner, terminator: cython.Py_UCS4 = ')', annotated: cython.bint = True) -> tuple:
3892
+ args = p_c_arg_list(s, in_pyfunc=True, nonempty_declarators=True,
3893
+ annotated = annotated)
3894
+ star_arg = None
3895
+ starstar_arg = None
3896
+ if s.sy == '/':
3897
+ if len(args) == 0:
3898
+ s.error("Got zero positional-only arguments despite presence of "
3899
+ "positional-only specifier '/'")
3900
+ s.next()
3901
+ # Mark all args to the left as pos only
3902
+ for arg in args:
3903
+ arg.pos_only = 1
3904
+ if s.sy == ',':
3905
+ s.next()
3906
+ args.extend(p_c_arg_list(
3907
+ s, in_pyfunc=True, nonempty_declarators=True, annotated = annotated))
3908
+ elif s.sy != terminator:
3909
+ s.error("Syntax error in Python function argument list")
3910
+ if s.sy == '*':
3911
+ s.next()
3912
+ if s.sy == 'IDENT':
3913
+ star_arg = p_py_arg_decl(s, annotated=annotated)
3914
+ if s.sy == ',':
3915
+ s.next()
3916
+ args.extend(p_c_arg_list(
3917
+ s, in_pyfunc =True, nonempty_declarators=True, kw_only=True, annotated = annotated))
3918
+ elif s.sy != terminator:
3919
+ s.error("Syntax error in Python function argument list")
3920
+ if s.sy == '**':
3921
+ s.next()
3922
+ starstar_arg = p_py_arg_decl(s, annotated=annotated)
3923
+ if s.sy == ',':
3924
+ s.next()
3925
+ return (args, star_arg, starstar_arg)
3926
+
3927
+
3928
+ @cython.cfunc
3929
+ def p_py_arg_decl(s: PyrexScanner, annotated: cython.bint = True):
3930
+ pos = s.position()
3931
+ name = p_ident(s)
3932
+ annotation = None
3933
+ if annotated and s.sy == ':':
3934
+ s.next()
3935
+ annotation = p_annotation(s)
3936
+ return Nodes.PyArgDeclNode(pos, name = name, annotation = annotation)
3937
+
3938
+
3939
+ @cython.cfunc
3940
+ def p_class_statement(s: PyrexScanner, decorators):
3941
+ # s.sy == 'class'
3942
+ pos = s.position()
3943
+ s.next()
3944
+ class_name = EncodedString(p_ident(s))
3945
+ class_name.encoding = s.source_encoding # FIXME: why is this needed?
3946
+ arg_tuple = None
3947
+ keyword_dict = None
3948
+ if s.sy == '(':
3949
+ positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False)
3950
+ arg_tuple, keyword_dict = p_call_build_packed_args(pos, positional_args, keyword_args)
3951
+ if arg_tuple is None:
3952
+ # XXX: empty arg_tuple
3953
+ arg_tuple = ExprNodes.TupleNode(pos, args=[])
3954
+ doc, body = p_suite_with_docstring(s, Ctx(level='class'))
3955
+ return Nodes.PyClassDefNode(
3956
+ pos, name=class_name,
3957
+ bases=arg_tuple,
3958
+ keyword_args=keyword_dict,
3959
+ doc=doc, body=body, decorators=decorators,
3960
+ force_py3_semantics=s.context.language_level >= 3)
3961
+
3962
+
3963
+ @cython.cfunc
3964
+ def p_c_class_definition(s: PyrexScanner, pos, ctx):
3965
+ # s.sy == 'class'
3966
+ s.next()
3967
+ module_path = []
3968
+ class_name = p_ident(s)
3969
+ while s.sy == '.':
3970
+ s.next()
3971
+ module_path.append(class_name)
3972
+ class_name = p_ident(s)
3973
+ if module_path and ctx.visibility != 'extern':
3974
+ error(pos, "Qualified class name only allowed for 'extern' C class")
3975
+ if module_path and s.sy == 'IDENT' and s.systring == 'as':
3976
+ s.next()
3977
+ as_name = p_ident(s)
3978
+ else:
3979
+ as_name = class_name
3980
+ objstruct_name = None
3981
+ typeobj_name = None
3982
+ bases = None
3983
+ check_size = None
3984
+ if s.sy == '(':
3985
+ positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False)
3986
+ if keyword_args:
3987
+ s.error("C classes cannot take keyword bases.")
3988
+ bases, _ = p_call_build_packed_args(pos, positional_args, keyword_args)
3989
+ if bases is None:
3990
+ bases = ExprNodes.TupleNode(pos, args=[])
3991
+
3992
+ if s.sy == '[':
3993
+ if ctx.visibility not in ('public', 'extern') and not ctx.api:
3994
+ error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
3995
+ objstruct_name, typeobj_name, check_size = p_c_class_options(s)
3996
+ if s.sy == ':':
3997
+ if ctx.level == 'module_pxd':
3998
+ body_level = 'c_class_pxd'
3999
+ else:
4000
+ body_level = 'c_class'
4001
+ doc, body = p_suite_with_docstring(s, Ctx(level=body_level))
4002
+ else:
4003
+ s.expect_newline("Syntax error in C class definition")
4004
+ doc = None
4005
+ body = None
4006
+ if ctx.visibility == 'extern':
4007
+ if not module_path:
4008
+ error(pos, "Module name required for 'extern' C class")
4009
+ if typeobj_name:
4010
+ error(pos, "Type object name specification not allowed for 'extern' C class")
4011
+ elif ctx.visibility == 'public':
4012
+ if not objstruct_name:
4013
+ error(pos, "Object struct name specification required for 'public' C class")
4014
+ if not typeobj_name:
4015
+ error(pos, "Type object name specification required for 'public' C class")
4016
+ elif ctx.visibility == 'private':
4017
+ if ctx.api:
4018
+ if not objstruct_name:
4019
+ error(pos, "Object struct name specification required for 'api' C class")
4020
+ if not typeobj_name:
4021
+ error(pos, "Type object name specification required for 'api' C class")
4022
+ else:
4023
+ error(pos, "Invalid class visibility '%s'" % ctx.visibility)
4024
+ return Nodes.CClassDefNode(pos,
4025
+ visibility = ctx.visibility,
4026
+ typedef_flag = ctx.typedef_flag,
4027
+ api = ctx.api,
4028
+ module_name = EncodedString(".".join(module_path)),
4029
+ class_name = class_name,
4030
+ as_name = as_name,
4031
+ bases = bases,
4032
+ objstruct_name = objstruct_name,
4033
+ typeobj_name = typeobj_name,
4034
+ check_size = check_size,
4035
+ in_pxd = ctx.level == 'module_pxd',
4036
+ doc = doc,
4037
+ body = body)
4038
+
4039
+
4040
+ @cython.cfunc
4041
+ def p_c_class_options(s: PyrexScanner) -> tuple:
4042
+ objstruct_name = None
4043
+ typeobj_name = None
4044
+ check_size = None
4045
+ s.expect('[')
4046
+ while 1:
4047
+ if s.sy != 'IDENT':
4048
+ break
4049
+ if s.systring == 'object':
4050
+ s.next()
4051
+ objstruct_name = p_ident(s)
4052
+ elif s.systring == 'type':
4053
+ s.next()
4054
+ typeobj_name = p_ident(s)
4055
+ elif s.systring == 'check_size':
4056
+ s.next()
4057
+ check_size = p_ident(s)
4058
+ if check_size not in ('ignore', 'warn', 'error'):
4059
+ s.error("Expected one of ignore, warn or error, found %r" % check_size)
4060
+ if s.sy != ',':
4061
+ break
4062
+ s.next()
4063
+ s.expect(']', "Expected 'object', 'type' or 'check_size'")
4064
+ return objstruct_name, typeobj_name, check_size
4065
+
4066
+
4067
+ @cython.cfunc
4068
+ def p_property_decl(s: PyrexScanner):
4069
+ pos = s.position()
4070
+ s.next() # 'property'
4071
+ name = p_ident(s)
4072
+ doc, body = p_suite_with_docstring(
4073
+ s, Ctx(level='property'), with_doc_only=True)
4074
+ return Nodes.PropertyNode(pos, name=name, doc=doc, body=body)
4075
+
4076
+
4077
+ @cython.cfunc
4078
+ def p_ignorable_statement(s: PyrexScanner):
4079
+ """
4080
+ Parses any kind of ignorable statement that is allowed in .pxd files.
4081
+ """
4082
+ if s.sy == 'BEGIN_STRING':
4083
+ pos = s.position()
4084
+ string_node = p_atom(s)
4085
+ s.expect_newline("Syntax error in string", ignore_semicolon=True)
4086
+ return Nodes.ExprStatNode(pos, expr=string_node)
4087
+ return None
4088
+
4089
+
4090
+ @cython.cfunc
4091
+ def p_doc_string(s: PyrexScanner):
4092
+ if s.sy == 'BEGIN_STRING':
4093
+ pos = s.position()
4094
+ kind, bytes_result, unicode_result = p_cat_string_literal(s)
4095
+ s.expect_newline("Syntax error in doc string", ignore_semicolon=True)
4096
+ if kind in ('u', ''):
4097
+ return unicode_result
4098
+ warning(pos, "Python 3 requires docstrings to be unicode strings")
4099
+ return bytes_result
4100
+ else:
4101
+ return None
4102
+
4103
+
4104
+ @cython.cfunc
4105
+ def _extract_docstring(node) -> tuple:
4106
+ """
4107
+ Extract a docstring from a statement or from the first statement
4108
+ in a list. Remove the statement if found. Return a tuple
4109
+ (plain-docstring or None, node).
4110
+ """
4111
+ doc_node = None
4112
+ if node is None:
4113
+ pass
4114
+ elif isinstance(node, Nodes.ExprStatNode):
4115
+ if node.expr.is_string_literal:
4116
+ doc_node = node.expr
4117
+ node = Nodes.StatListNode(node.pos, stats=[])
4118
+ elif isinstance(node, Nodes.StatListNode) and node.stats:
4119
+ stats = node.stats
4120
+ if isinstance(stats[0], Nodes.ExprStatNode):
4121
+ if stats[0].expr.is_string_literal:
4122
+ doc_node = stats[0].expr
4123
+ del stats[0]
4124
+
4125
+ if doc_node is None:
4126
+ doc = None
4127
+ elif isinstance(doc_node, ExprNodes.BytesNode):
4128
+ warning(node.pos,
4129
+ "Python 3 requires docstrings to be unicode strings")
4130
+ doc = doc_node.value
4131
+ else:
4132
+ doc = doc_node.value
4133
+ return doc, node
4134
+
4135
+
4136
+ @cython.ccall
4137
+ def p_code(s: PyrexScanner, level=None, ctx=Ctx):
4138
+ body = p_statement_list(s, ctx(level = level), first_statement=True)
4139
+ if s.sy != 'EOF':
4140
+ s.error("Syntax error in statement [%s,%s]" % (
4141
+ repr(s.sy), repr(s.systring)))
4142
+ return body
4143
+
4144
+
4145
+ _match_compiler_directive_comment = cython.declare(object, re.compile(
4146
+ r"^#\s*cython\s*:\s*((\w|[.])+\s*=.*)$").match)
4147
+
4148
+
4149
+ @cython.cfunc
4150
+ def p_compiler_directive_comments(s: PyrexScanner) -> dict:
4151
+ result = {}
4152
+ while s.sy == 'commentline':
4153
+ pos = s.position()
4154
+ m = _match_compiler_directive_comment(s.systring)
4155
+ if m:
4156
+ directives_string = m.group(1).strip()
4157
+ try:
4158
+ new_directives = Options.parse_directive_list(directives_string, ignore_unknown=True)
4159
+ except ValueError as e:
4160
+ s.error(e.args[0], fatal=False)
4161
+ s.next()
4162
+ continue
4163
+
4164
+ for name in new_directives:
4165
+ if name not in result:
4166
+ pass
4167
+ elif Options.directive_types.get(name) is list:
4168
+ result[name] += new_directives[name]
4169
+ new_directives[name] = result[name]
4170
+ elif new_directives[name] == result[name]:
4171
+ warning(pos, "Duplicate directive found: %s" % (name,))
4172
+ else:
4173
+ s.error("Conflicting settings found for top-level directive %s: %r and %r" % (
4174
+ name, result[name], new_directives[name]), pos=pos)
4175
+
4176
+ if 'language_level' in new_directives:
4177
+ # Make sure we apply the language level already to the first token that follows the comments.
4178
+ s.context.set_language_level(new_directives['language_level'])
4179
+ if 'legacy_implicit_noexcept' in new_directives:
4180
+ s.context.legacy_implicit_noexcept = new_directives['legacy_implicit_noexcept']
4181
+
4182
+
4183
+ result.update(new_directives)
4184
+
4185
+ s.next()
4186
+ return result
4187
+
4188
+
4189
+ @cython.ccall
4190
+ def p_module(s: PyrexScanner, pxd, full_module_name, ctx=Ctx):
4191
+ pos = s.position()
4192
+
4193
+ directive_comments = p_compiler_directive_comments(s)
4194
+ s.parse_comments = False
4195
+
4196
+ if s.context.language_level is None:
4197
+ s.context.set_language_level('3')
4198
+
4199
+ level = 'module_pxd' if pxd else 'module'
4200
+ doc = p_doc_string(s)
4201
+ body = p_statement_list(s, ctx(level=level), first_statement=True)
4202
+ if s.sy != 'EOF':
4203
+ s.error("Syntax error in statement [%s,%s]" % (
4204
+ repr(s.sy), repr(s.systring)))
4205
+ return ModuleNode(pos, doc = doc, body = body,
4206
+ full_module_name = full_module_name,
4207
+ directive_comments = directive_comments)
4208
+
4209
+
4210
+ @cython.cfunc
4211
+ def p_template_definition(s: PyrexScanner) -> tuple:
4212
+ name = p_ident(s)
4213
+ if s.sy == '=':
4214
+ s.expect('=')
4215
+ s.expect('*')
4216
+ required = False
4217
+ else:
4218
+ required = True
4219
+ return name, required
4220
+
4221
+
4222
+ @cython.cfunc
4223
+ def p_cpp_class_definition(s: PyrexScanner, pos, ctx):
4224
+ # s.sy == 'cppclass'
4225
+ s.next()
4226
+ class_name = p_ident(s)
4227
+ cname = p_opt_cname(s)
4228
+ if cname is None and ctx.namespace is not None:
4229
+ cname = ctx.namespace + "::" + class_name
4230
+ if s.sy == '.':
4231
+ error(pos, "Qualified class name not allowed C++ class")
4232
+ if s.sy == '[':
4233
+ s.next()
4234
+ templates = [p_template_definition(s)]
4235
+ while s.sy == ',':
4236
+ s.next()
4237
+ templates.append(p_template_definition(s))
4238
+ s.expect(']')
4239
+ template_names = [name for name, required in templates]
4240
+ else:
4241
+ templates = None
4242
+ template_names = None
4243
+ if s.sy == '(':
4244
+ s.next()
4245
+ base_classes = [p_c_base_type(s, templates = template_names)]
4246
+ while s.sy == ',':
4247
+ s.next()
4248
+ base_classes.append(p_c_base_type(s, templates = template_names))
4249
+ s.expect(')')
4250
+ else:
4251
+ base_classes = []
4252
+ if s.sy == '[':
4253
+ error(s.position(), "Name options not allowed for C++ class")
4254
+ nogil = p_nogil(s)
4255
+ if s.sy == ':':
4256
+ s.next()
4257
+ s.expect('NEWLINE')
4258
+ s.expect_indent()
4259
+ # Allow a cppclass to have docstrings. It will be discarded as comment.
4260
+ # The goal of this is consistency: we can make docstrings inside cppclass methods,
4261
+ # so why not on the cppclass itself ?
4262
+ p_doc_string(s)
4263
+ attributes = []
4264
+ body_ctx = Ctx(visibility = ctx.visibility, level='cpp_class', nogil=nogil or ctx.nogil)
4265
+ body_ctx.templates = template_names
4266
+ while s.sy != 'DEDENT':
4267
+ if s.sy != 'pass':
4268
+ attributes.append(p_cpp_class_attribute(s, body_ctx))
4269
+ else:
4270
+ s.next()
4271
+ s.expect_newline("Expected a newline")
4272
+ s.expect_dedent()
4273
+ else:
4274
+ attributes = None
4275
+ s.expect_newline("Syntax error in C++ class definition")
4276
+ return Nodes.CppClassNode(pos,
4277
+ name = class_name,
4278
+ cname = cname,
4279
+ base_classes = base_classes,
4280
+ visibility = ctx.visibility,
4281
+ in_pxd = ctx.level == 'module_pxd',
4282
+ attributes = attributes,
4283
+ templates = templates)
4284
+
4285
+
4286
+ @cython.cfunc
4287
+ def p_cpp_class_attribute(s: PyrexScanner, ctx):
4288
+ pos = s.position()
4289
+ decorators = None
4290
+ if s.sy == '@':
4291
+ decorators = p_decorators(s)
4292
+ if s.systring == 'cppclass':
4293
+ return p_cpp_class_definition(s, pos, ctx)
4294
+ elif s.systring == 'ctypedef':
4295
+ return p_ctypedef_statement(s, ctx)
4296
+ elif s.sy == 'IDENT' and s.systring in struct_enum_union:
4297
+ if s.systring != 'enum':
4298
+ return p_cpp_class_definition(s, pos, ctx)
4299
+ else:
4300
+ return p_struct_enum(s, pos, ctx)
4301
+ else:
4302
+ node = p_c_func_or_var_declaration(s, pos, ctx)
4303
+ if decorators is not None:
4304
+ tup = Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode
4305
+ if ctx.allow_struct_enum_decorator:
4306
+ tup += Nodes.CStructOrUnionDefNode, Nodes.CEnumDefNode
4307
+ if not isinstance(node, tup):
4308
+ s.error("Decorators can only be followed by functions or classes")
4309
+ node.decorators = decorators
4310
+ return node
4311
+
4312
+
4313
+ @cython.cfunc
4314
+ def p_match_statement(s: PyrexScanner, ctx):
4315
+ assert s.sy == "IDENT" and s.systring == "match"
4316
+ pos = s.position()
4317
+ with tentatively_scan(s) as errors:
4318
+ s.next()
4319
+ subject = p_namedexpr_test(s)
4320
+ subjects = None
4321
+ if s.sy == ",":
4322
+ subjects = [subject]
4323
+ while s.sy == ",":
4324
+ s.next()
4325
+ if s.sy == ":":
4326
+ break
4327
+ subjects.append(p_test(s))
4328
+ if subjects is not None:
4329
+ subject = ExprNodes.TupleNode(pos, args=subjects)
4330
+ s.expect(":")
4331
+ if errors:
4332
+ return None
4333
+
4334
+ # at this stage we are committed to it being a match block so continue
4335
+ # outside "with tentatively_scan"
4336
+ # (I think this deviates from the PEG parser slightly, and it'd
4337
+ # backtrack on the whole thing)
4338
+ s.expect_newline()
4339
+ s.expect_indent()
4340
+ cases = []
4341
+ while s.sy != "DEDENT":
4342
+ cases.append(p_case_block(s, ctx))
4343
+ s.expect_dedent()
4344
+ return MatchCaseNodes.MatchNode(pos, subject=subject, cases=cases)
4345
+
4346
+
4347
+ @cython.cfunc
4348
+ def p_case_block(s: PyrexScanner, ctx):
4349
+ if not (s.sy == "IDENT" and s.systring == "case"):
4350
+ s.expected("case")
4351
+ s.next()
4352
+ pos = s.position()
4353
+ pattern = p_patterns(s)
4354
+ guard = None
4355
+ if s.sy == 'if':
4356
+ s.next()
4357
+ guard = p_test(s)
4358
+ body = p_suite(s, ctx)
4359
+
4360
+ return MatchCaseNodes.MatchCaseNode(pos, pattern=pattern, body=body, guard=guard)
4361
+
4362
+
4363
+ @cython.cfunc
4364
+ def p_patterns(s: PyrexScanner):
4365
+ # note - in slight contrast to the name (which comes from the Python grammar),
4366
+ # returns a single pattern
4367
+ patterns = []
4368
+ seq = False
4369
+ pos = s.position()
4370
+ while True:
4371
+ with tentatively_scan(s) as errors:
4372
+ pattern = p_maybe_star_pattern(s)
4373
+ if errors:
4374
+ if patterns:
4375
+ break # all is good provided we have at least 1 pattern
4376
+ else:
4377
+ e = errors[0]
4378
+ s.error(e.args[1], pos=e.args[0])
4379
+ patterns.append(pattern)
4380
+
4381
+ if s.sy == ",":
4382
+ seq = True
4383
+ s.next()
4384
+ if s.sy in [":", "if"]:
4385
+ break # common reasons to break
4386
+ else:
4387
+ break
4388
+
4389
+ if seq:
4390
+ return MatchCaseNodes.MatchSequencePatternNode(pos, patterns=patterns)
4391
+ else:
4392
+ return patterns[0]
4393
+
4394
+
4395
+ @cython.cfunc
4396
+ def p_maybe_star_pattern(s: PyrexScanner):
4397
+ # For match case. Either star_pattern or pattern
4398
+ if s.sy == "*":
4399
+ # star pattern
4400
+ s.next()
4401
+ target = None
4402
+ if s.systring != "_": # for match-case '_' is treated as a special wildcard
4403
+ target = p_pattern_capture_target(s)
4404
+ else:
4405
+ s.next()
4406
+ pattern = MatchCaseNodes.MatchAndAssignPatternNode(
4407
+ s.position(), target=target, is_star=True
4408
+ )
4409
+ return pattern
4410
+ else:
4411
+ pattern = p_pattern(s)
4412
+ return pattern
4413
+
4414
+
4415
+ @cython.cfunc
4416
+ def p_pattern(s: PyrexScanner):
4417
+ # try "as_pattern" then "or_pattern"
4418
+ # (but practically "as_pattern" starts with "or_pattern" too)
4419
+ patterns = []
4420
+ pos = s.position()
4421
+ while True:
4422
+ patterns.append(p_closed_pattern(s))
4423
+ if s.sy != "|":
4424
+ break
4425
+ s.next()
4426
+
4427
+ if len(patterns) > 1:
4428
+ pattern = MatchCaseNodes.OrPatternNode(
4429
+ pos,
4430
+ alternatives=patterns
4431
+ )
4432
+ else:
4433
+ pattern = patterns[0]
4434
+
4435
+ if s.sy == 'IDENT' and s.systring == 'as':
4436
+ s.next()
4437
+ with tentatively_scan(s) as errors:
4438
+ pattern.as_targets.append(p_pattern_capture_target(s))
4439
+ if errors and s.sy == "_":
4440
+ s.next()
4441
+ # make this a specific error
4442
+ return Nodes.ErrorNode(errors[0].args[0], what=errors[0].args[1])
4443
+ elif errors:
4444
+ with tentatively_scan(s):
4445
+ expr = p_test(s)
4446
+ return Nodes.ErrorNode(expr.pos, what="Invalid pattern target")
4447
+ s.error(errors[0])
4448
+ return pattern
4449
+
4450
+
4451
+ @cython.cfunc
4452
+ def p_closed_pattern(s: PyrexScanner):
4453
+ """
4454
+ The PEG parser specifies it as
4455
+ | literal_pattern
4456
+ | capture_pattern
4457
+ | wildcard_pattern
4458
+ | value_pattern
4459
+ | group_pattern
4460
+ | sequence_pattern
4461
+ | mapping_pattern
4462
+ | class_pattern
4463
+
4464
+ For the sake avoiding too much backtracking, we know:
4465
+ * starts with "{" is a mapping_pattern
4466
+ * starts with "[" is a sequence_pattern
4467
+ * starts with "(" is a group_pattern or sequence_pattern
4468
+ * wildcard pattern is just identifier=='_'
4469
+ The rest are then tried in order with backtracking
4470
+ """
4471
+ if s.sy == 'IDENT' and s.systring == '_':
4472
+ pos = s.position()
4473
+ s.next()
4474
+ return MatchCaseNodes.MatchAndAssignPatternNode(pos)
4475
+ elif s.sy == '{':
4476
+ return p_mapping_pattern(s)
4477
+ elif s.sy == '[':
4478
+ return p_sequence_pattern(s)
4479
+ elif s.sy == '(':
4480
+ with tentatively_scan(s) as errors:
4481
+ result = p_group_pattern(s)
4482
+ if not errors:
4483
+ return result
4484
+ return p_sequence_pattern(s)
4485
+
4486
+ with tentatively_scan(s) as errors:
4487
+ result = p_literal_pattern(s)
4488
+ if not errors:
4489
+ return result
4490
+ with tentatively_scan(s) as errors:
4491
+ result = p_capture_pattern(s)
4492
+ if not errors:
4493
+ return result
4494
+ with tentatively_scan(s) as errors:
4495
+ result = p_value_pattern(s)
4496
+ if not errors:
4497
+ return result
4498
+ return p_class_pattern(s)
4499
+
4500
+
4501
+ @cython.cfunc
4502
+ def p_literal_pattern(s: PyrexScanner):
4503
+ # a lot of duplication in this function with "p_atom"
4504
+ next_must_be_a_number = False
4505
+ sign = ''
4506
+ if s.sy == '-':
4507
+ sign = s.sy
4508
+ sign_pos = s.position()
4509
+ s.next()
4510
+ next_must_be_a_number = True
4511
+ elif s.sy == '+':
4512
+ s.next()
4513
+ next_must_be_a_number = True
4514
+
4515
+ sy = s.sy
4516
+ pos = s.position()
4517
+
4518
+ res = None
4519
+ if sy == 'INT':
4520
+ res = p_int_literal(s)
4521
+ elif sy == 'FLOAT':
4522
+ value = s.systring
4523
+ s.next()
4524
+ res = ExprNodes.FloatNode(pos, value=value)
4525
+
4526
+ if res is not None and sign == "-":
4527
+ res = ExprNodes.UnaryMinusNode(sign_pos, operand=res)
4528
+
4529
+ if res is not None and s.sy in ['+', '-']:
4530
+ sign = s.sy
4531
+ s.next()
4532
+ if s.sy == '+':
4533
+ s.next()
4534
+ if s.sy != 'IMAG':
4535
+ s.error("Expected imaginary number")
4536
+ else:
4537
+ add_pos = s.position()
4538
+ value = s.systring[:-1]
4539
+ s.next()
4540
+ res = ExprNodes.binop_node(
4541
+ add_pos,
4542
+ sign,
4543
+ operand1=res,
4544
+ operand2=ExprNodes.ImagNode(s.position(), value=value)
4545
+ )
4546
+
4547
+ if res is None and sy == 'IMAG':
4548
+ value = s.systring[:-1]
4549
+ s.next()
4550
+ res = ExprNodes.ImagNode(pos, value=sign+value)
4551
+
4552
+ if res is not None:
4553
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=res)
4554
+
4555
+ if next_must_be_a_number:
4556
+ s.error("Expected a number")
4557
+ if sy == 'BEGIN_STRING':
4558
+ res = p_atom_string(s)
4559
+ # Whether f-strings are suitable is validated in PostParse.
4560
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=res)
4561
+ elif sy == 'IDENT':
4562
+ # Note that p_atom_ident_constants includes NULL.
4563
+ # This is a deliberate Cython addition to the pattern matching specification
4564
+ result = p_atom_ident_constants(s)
4565
+ if result:
4566
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=result, is_is_check=True)
4567
+
4568
+ s.error("Failed to match literal")
4569
+
4570
+
4571
+ @cython.cfunc
4572
+ def p_capture_pattern(s: PyrexScanner):
4573
+ return MatchCaseNodes.MatchAndAssignPatternNode(
4574
+ s.position(),
4575
+ target=p_pattern_capture_target(s)
4576
+ )
4577
+
4578
+
4579
+ @cython.cfunc
4580
+ def p_value_pattern(s: PyrexScanner):
4581
+ if s.sy != "IDENT":
4582
+ s.error("Expected identifier")
4583
+ pos = s.position()
4584
+ res = p_name(s, s.systring)
4585
+ s.next()
4586
+ if s.sy != '.':
4587
+ s.error(".")
4588
+ while s.sy == '.':
4589
+ attr_pos = s.position()
4590
+ s.next()
4591
+ attr = p_ident(s)
4592
+ res = ExprNodes.AttributeNode(attr_pos, obj=res, attribute=attr)
4593
+ if s.sy in ['(', '=']:
4594
+ s.error("Unexpected symbol '%s'" % s.sy)
4595
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=res)
4596
+
4597
+
4598
+ @cython.cfunc
4599
+ def p_group_pattern(s: PyrexScanner):
4600
+ s.expect("(")
4601
+ pattern = p_pattern(s)
4602
+ s.expect(")")
4603
+ return pattern
4604
+
4605
+
4606
+ @cython.cfunc
4607
+ def p_sequence_pattern(s: PyrexScanner):
4608
+ pos = s.position()
4609
+ assert s.sy in ('(', '[')
4610
+ closer = ')' if s.sy == '(' else ']'
4611
+ s.next()
4612
+ # maybe_sequence_pattern and open_sequence_pattern
4613
+ patterns = []
4614
+ while s.sy != closer:
4615
+ patterns.append(p_maybe_star_pattern(s))
4616
+ if s.sy != ",":
4617
+ if closer == ')' and len(patterns) == 1:
4618
+ s.error("tuple-like pattern of length 1 must finish with ','")
4619
+ break
4620
+ s.next()
4621
+ s.expect(closer)
4622
+ return MatchCaseNodes.MatchSequencePatternNode(pos, patterns=patterns)
4623
+
4624
+
4625
+ @cython.cfunc
4626
+ def p_mapping_pattern(s: PyrexScanner):
4627
+ pos = s.position()
4628
+ s.expect('{')
4629
+ if s.sy == '}':
4630
+ # trivial empty mapping
4631
+ s.next()
4632
+ return MatchCaseNodes.MatchMappingPatternNode(pos)
4633
+
4634
+ double_star_capture_target = None
4635
+ items_patterns = []
4636
+ double_star_set_twice_pos = None
4637
+ pattern_after_double_star_pos = None
4638
+ star_star_arg_pos = None
4639
+ while s.sy != '}':
4640
+ if double_star_capture_target and not star_star_arg_pos:
4641
+ star_star_arg_pos = s.position()
4642
+ if s.sy == '**':
4643
+ s.next()
4644
+ if double_star_capture_target:
4645
+ double_star_set_twice_pos = s.position()
4646
+ double_star_capture_target = p_pattern_capture_target(s)
4647
+ else:
4648
+ # key=(literal_expr | attr)
4649
+ with tentatively_scan(s) as errors:
4650
+ pattern = p_literal_pattern(s)
4651
+ key = pattern.value
4652
+ if errors:
4653
+ pattern = p_value_pattern(s)
4654
+ key = pattern.value
4655
+ s.expect(':')
4656
+ value = p_pattern(s)
4657
+ items_patterns.append((key, value))
4658
+ if double_star_capture_target:
4659
+ pattern_after_double_star_pos = value.pos
4660
+ if s.sy != ',':
4661
+ break
4662
+ s.next()
4663
+ s.expect('}')
4664
+ if double_star_set_twice_pos is not None:
4665
+ return Nodes.ErrorNode(double_star_set_twice_pos, what = "Double star capture set twice")
4666
+ if pattern_after_double_star_pos is not None:
4667
+ return Nodes.ErrorNode(pattern_after_double_star_pos, what = "pattern follows ** capture")
4668
+
4669
+ if star_star_arg_pos is not None:
4670
+ return Nodes.ErrorNode(
4671
+ star_star_arg_pos,
4672
+ what = "** pattern must be the final part of a mapping pattern."
4673
+ )
4674
+ return MatchCaseNodes.MatchMappingPatternNode(
4675
+ pos,
4676
+ keys = [kv[0] for kv in items_patterns],
4677
+ value_patterns = [kv[1] for kv in items_patterns],
4678
+ double_star_capture_target = double_star_capture_target
4679
+ )
4680
+
4681
+
4682
+ @cython.cfunc
4683
+ def p_class_pattern(s: PyrexScanner):
4684
+ # start by parsing the class as name_or_attr
4685
+ pos = s.position()
4686
+ res = p_name(s, s.systring)
4687
+ s.next()
4688
+ while s.sy == '.':
4689
+ attr_pos = s.position()
4690
+ s.next()
4691
+ attr = p_ident(s)
4692
+ res = ExprNodes.AttributeNode(attr_pos, obj=res, attribute=attr)
4693
+ class_ = res
4694
+
4695
+ s.expect("(")
4696
+ if s.sy == ")":
4697
+ # trivial case with no arguments matched
4698
+ s.next()
4699
+ return MatchCaseNodes.ClassPatternNode(pos, class_=class_)
4700
+
4701
+ # parse the arguments
4702
+ positional_patterns = []
4703
+ keyword_patterns = []
4704
+ keyword_patterns_error = None
4705
+ while s.sy != ')':
4706
+ with tentatively_scan(s) as errors:
4707
+ positional_patterns.append(p_pattern(s))
4708
+ if not errors:
4709
+ if keyword_patterns:
4710
+ keyword_patterns_error = s.position()
4711
+ else:
4712
+ with tentatively_scan(s) as errors:
4713
+ keyword_patterns.append(p_keyword_pattern(s))
4714
+ if s.sy != ",":
4715
+ break
4716
+ s.next()
4717
+ s.expect(")")
4718
+
4719
+ if keyword_patterns_error is not None:
4720
+ return Nodes.ErrorNode(
4721
+ keyword_patterns_error,
4722
+ what="Positional patterns follow keyword patterns"
4723
+ )
4724
+ return MatchCaseNodes.ClassPatternNode(
4725
+ pos, class_ = class_,
4726
+ positional_patterns = positional_patterns,
4727
+ keyword_pattern_names = [kv[0] for kv in keyword_patterns],
4728
+ keyword_pattern_patterns = [kv[1] for kv in keyword_patterns],
4729
+ )
4730
+
4731
+
4732
+ @cython.cfunc
4733
+ def p_keyword_pattern(s: PyrexScanner) -> tuple:
4734
+ if s.sy != "IDENT":
4735
+ s.error("Expected identifier")
4736
+ arg = p_name(s, s.systring)
4737
+ s.next()
4738
+ s.expect("=")
4739
+ value = p_pattern(s)
4740
+ return arg, value
4741
+
4742
+
4743
+ @cython.cfunc
4744
+ def p_pattern_capture_target(s: PyrexScanner):
4745
+ # any name but '_', and with some constraints on what follows
4746
+ if s.sy != 'IDENT':
4747
+ s.error("Expected identifier")
4748
+ if s.systring == '_':
4749
+ s.error("Pattern capture target cannot be '_'")
4750
+ target = p_name(s, s.systring)
4751
+ s.next()
4752
+ if s.sy in ['.', '(', '=']:
4753
+ s.error("Illegal next symbol '%s'" % s.sy)
4754
+ return target
4755
+
4756
+
4757
+
4758
+ #----------------------------------------------
4759
+ #
4760
+ # Debugging
4761
+ #
4762
+ #----------------------------------------------
4763
+
4764
+ @cython.ccall
4765
+ def print_parse_tree(f, node, level: cython.long, key = None):
4766
+ ind: str = " " * level
4767
+ f.write(ind)
4768
+ if key:
4769
+ f.write(f"{key}: ")
4770
+ if not node:
4771
+ f.write("None\n")
4772
+ elif type(node) is tuple:
4773
+ f.write(f"({node[0]} @ {node[1]}\n")
4774
+ for item in node[2:]:
4775
+ print_parse_tree(f, item, level+1)
4776
+ f.write(f"{ind})\n")
4777
+ elif isinstance(node, Nodes.Node):
4778
+ try:
4779
+ tag = node.tag
4780
+ except AttributeError:
4781
+ tag = node.__class__.__name__
4782
+ f.write(f"{tag} @ {node.pos}\n")
4783
+ for name, value in sorted(node.__dict__.items()):
4784
+ if name != 'tag' and name != 'pos':
4785
+ print_parse_tree(f, value, level+1, name)
4786
+ elif type(node) is list:
4787
+ f.write("[\n")
4788
+ for item in node:
4789
+ print_parse_tree(f, item, level+1)
4790
+ f.write(f"{ind}]\n")
4791
+ else:
4792
+ f.write(f"{ind}{node}\n")