Cython 3.2.0__cp39-abi3-win32.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 (333) hide show
  1. Cython/Build/BuildExecutable.py +169 -0
  2. Cython/Build/Cache.py +199 -0
  3. Cython/Build/Cythonize.py +350 -0
  4. Cython/Build/Dependencies.py +1314 -0
  5. Cython/Build/Distutils.py +1 -0
  6. Cython/Build/Inline.py +463 -0
  7. Cython/Build/IpythonMagic.py +560 -0
  8. Cython/Build/SharedModule.py +94 -0
  9. Cython/Build/Tests/TestCyCache.py +194 -0
  10. Cython/Build/Tests/TestCythonizeArgsParser.py +481 -0
  11. Cython/Build/Tests/TestDependencies.py +133 -0
  12. Cython/Build/Tests/TestInline.py +177 -0
  13. Cython/Build/Tests/TestIpythonMagic.py +287 -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 +984 -0
  24. Cython/Compiler/CmdLine.py +263 -0
  25. Cython/Compiler/Code.pxd +149 -0
  26. Cython/Compiler/Code.py +3746 -0
  27. Cython/Compiler/Code.pyd +0 -0
  28. Cython/Compiler/CodeGeneration.py +33 -0
  29. Cython/Compiler/CythonScope.py +191 -0
  30. Cython/Compiler/Dataclass.py +864 -0
  31. Cython/Compiler/DebugFlags.py +24 -0
  32. Cython/Compiler/Errors.py +297 -0
  33. Cython/Compiler/ExprNodes.py +15562 -0
  34. Cython/Compiler/FlowControl.pxd +97 -0
  35. Cython/Compiler/FlowControl.py +1451 -0
  36. Cython/Compiler/FlowControl.pyd +0 -0
  37. Cython/Compiler/FusedNode.py +971 -0
  38. Cython/Compiler/FusedNode.pyd +0 -0
  39. Cython/Compiler/Future.py +16 -0
  40. Cython/Compiler/Interpreter.py +57 -0
  41. Cython/Compiler/Lexicon.py +421 -0
  42. Cython/Compiler/LineTable.py +114 -0
  43. Cython/Compiler/LineTable.pyd +0 -0
  44. Cython/Compiler/Main.py +857 -0
  45. Cython/Compiler/MatchCaseNodes.py +259 -0
  46. Cython/Compiler/MemoryView.py +905 -0
  47. Cython/Compiler/ModuleNode.py +4235 -0
  48. Cython/Compiler/Naming.py +363 -0
  49. Cython/Compiler/Nodes.py +10831 -0
  50. Cython/Compiler/Optimize.py +5288 -0
  51. Cython/Compiler/Options.py +843 -0
  52. Cython/Compiler/ParseTreeTransforms.pxd +78 -0
  53. Cython/Compiler/ParseTreeTransforms.py +4638 -0
  54. Cython/Compiler/Parsing.pxd +9 -0
  55. Cython/Compiler/Parsing.py +4775 -0
  56. Cython/Compiler/Parsing.pyd +0 -0
  57. Cython/Compiler/Pipeline.py +439 -0
  58. Cython/Compiler/PyrexTypes.py +5870 -0
  59. Cython/Compiler/Pythran.py +232 -0
  60. Cython/Compiler/Scanning.pxd +48 -0
  61. Cython/Compiler/Scanning.py +701 -0
  62. Cython/Compiler/Scanning.pyd +0 -0
  63. Cython/Compiler/StringEncoding.py +298 -0
  64. Cython/Compiler/Symtab.py +3073 -0
  65. Cython/Compiler/Tests/TestBuffer.py +105 -0
  66. Cython/Compiler/Tests/TestBuiltin.py +72 -0
  67. Cython/Compiler/Tests/TestCmdLine.py +586 -0
  68. Cython/Compiler/Tests/TestCode.py +144 -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 +134 -0
  74. Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
  75. Cython/Compiler/Tests/TestStringEncoding.py +21 -0
  76. Cython/Compiler/Tests/TestTreeFragment.py +63 -0
  77. Cython/Compiler/Tests/TestTreePath.py +103 -0
  78. Cython/Compiler/Tests/TestTypes.py +75 -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 +591 -0
  86. Cython/Compiler/TypeSlots.py +1174 -0
  87. Cython/Compiler/UFuncs.py +311 -0
  88. Cython/Compiler/UtilNodes.py +389 -0
  89. Cython/Compiler/UtilityCode.py +344 -0
  90. Cython/Compiler/Version.py +8 -0
  91. Cython/Compiler/Visitor.pxd +53 -0
  92. Cython/Compiler/Visitor.py +861 -0
  93. Cython/Compiler/Visitor.pyd +0 -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 +275 -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 +578 -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 +178 -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 +187 -0
  127. Cython/Includes/cpython/exc.pxd +263 -0
  128. Cython/Includes/cpython/fileobject.pxd +57 -0
  129. Cython/Includes/cpython/float.pxd +47 -0
  130. Cython/Includes/cpython/function.pxd +65 -0
  131. Cython/Includes/cpython/genobject.pxd +25 -0
  132. Cython/Includes/cpython/getargs.pxd +12 -0
  133. Cython/Includes/cpython/instance.pxd +25 -0
  134. Cython/Includes/cpython/iterator.pxd +36 -0
  135. Cython/Includes/cpython/iterobject.pxd +24 -0
  136. Cython/Includes/cpython/list.pxd +92 -0
  137. Cython/Includes/cpython/long.pxd +149 -0
  138. Cython/Includes/cpython/longintrepr.pxd +14 -0
  139. Cython/Includes/cpython/mapping.pxd +63 -0
  140. Cython/Includes/cpython/marshal.pxd +66 -0
  141. Cython/Includes/cpython/mem.pxd +120 -0
  142. Cython/Includes/cpython/memoryview.pxd +50 -0
  143. Cython/Includes/cpython/method.pxd +49 -0
  144. Cython/Includes/cpython/module.pxd +208 -0
  145. Cython/Includes/cpython/number.pxd +258 -0
  146. Cython/Includes/cpython/object.pxd +433 -0
  147. Cython/Includes/cpython/pycapsule.pxd +143 -0
  148. Cython/Includes/cpython/pylifecycle.pxd +68 -0
  149. Cython/Includes/cpython/pyport.pxd +8 -0
  150. Cython/Includes/cpython/pystate.pxd +95 -0
  151. Cython/Includes/cpython/pythread.pxd +53 -0
  152. Cython/Includes/cpython/ref.pxd +141 -0
  153. Cython/Includes/cpython/sequence.pxd +134 -0
  154. Cython/Includes/cpython/set.pxd +119 -0
  155. Cython/Includes/cpython/slice.pxd +70 -0
  156. Cython/Includes/cpython/time.pxd +129 -0
  157. Cython/Includes/cpython/tuple.pxd +72 -0
  158. Cython/Includes/cpython/type.pxd +53 -0
  159. Cython/Includes/cpython/unicode.pxd +639 -0
  160. Cython/Includes/cpython/version.pxd +32 -0
  161. Cython/Includes/cpython/weakref.pxd +78 -0
  162. Cython/Includes/libc/__init__.pxd +1 -0
  163. Cython/Includes/libc/complex.pxd +35 -0
  164. Cython/Includes/libc/errno.pxd +127 -0
  165. Cython/Includes/libc/float.pxd +43 -0
  166. Cython/Includes/libc/limits.pxd +28 -0
  167. Cython/Includes/libc/locale.pxd +46 -0
  168. Cython/Includes/libc/math.pxd +209 -0
  169. Cython/Includes/libc/setjmp.pxd +10 -0
  170. Cython/Includes/libc/signal.pxd +64 -0
  171. Cython/Includes/libc/stddef.pxd +9 -0
  172. Cython/Includes/libc/stdint.pxd +105 -0
  173. Cython/Includes/libc/stdio.pxd +80 -0
  174. Cython/Includes/libc/stdlib.pxd +72 -0
  175. Cython/Includes/libc/string.pxd +50 -0
  176. Cython/Includes/libc/threads.pxd +234 -0
  177. Cython/Includes/libc/time.pxd +52 -0
  178. Cython/Includes/libcpp/__init__.pxd +4 -0
  179. Cython/Includes/libcpp/algorithm.pxd +320 -0
  180. Cython/Includes/libcpp/any.pxd +16 -0
  181. Cython/Includes/libcpp/atomic.pxd +59 -0
  182. Cython/Includes/libcpp/barrier.pxd +22 -0
  183. Cython/Includes/libcpp/bit.pxd +29 -0
  184. Cython/Includes/libcpp/cast.pxd +12 -0
  185. Cython/Includes/libcpp/cmath.pxd +518 -0
  186. Cython/Includes/libcpp/complex.pxd +106 -0
  187. Cython/Includes/libcpp/condition_variable.pxd +322 -0
  188. Cython/Includes/libcpp/deque.pxd +165 -0
  189. Cython/Includes/libcpp/exception.pxd +86 -0
  190. Cython/Includes/libcpp/execution.pxd +15 -0
  191. Cython/Includes/libcpp/forward_list.pxd +63 -0
  192. Cython/Includes/libcpp/functional.pxd +26 -0
  193. Cython/Includes/libcpp/future.pxd +103 -0
  194. Cython/Includes/libcpp/iterator.pxd +34 -0
  195. Cython/Includes/libcpp/latch.pxd +17 -0
  196. Cython/Includes/libcpp/limits.pxd +61 -0
  197. Cython/Includes/libcpp/list.pxd +117 -0
  198. Cython/Includes/libcpp/map.pxd +252 -0
  199. Cython/Includes/libcpp/memory.pxd +115 -0
  200. Cython/Includes/libcpp/mutex.pxd +387 -0
  201. Cython/Includes/libcpp/numbers.pxd +15 -0
  202. Cython/Includes/libcpp/numeric.pxd +131 -0
  203. Cython/Includes/libcpp/optional.pxd +34 -0
  204. Cython/Includes/libcpp/pair.pxd +1 -0
  205. Cython/Includes/libcpp/queue.pxd +25 -0
  206. Cython/Includes/libcpp/random.pxd +166 -0
  207. Cython/Includes/libcpp/semaphore.pxd +43 -0
  208. Cython/Includes/libcpp/set.pxd +228 -0
  209. Cython/Includes/libcpp/shared_mutex.pxd +96 -0
  210. Cython/Includes/libcpp/span.pxd +87 -0
  211. Cython/Includes/libcpp/stack.pxd +11 -0
  212. Cython/Includes/libcpp/stop_token.pxd +117 -0
  213. Cython/Includes/libcpp/string.pxd +355 -0
  214. Cython/Includes/libcpp/string_view.pxd +183 -0
  215. Cython/Includes/libcpp/typeindex.pxd +15 -0
  216. Cython/Includes/libcpp/typeinfo.pxd +10 -0
  217. Cython/Includes/libcpp/unordered_map.pxd +193 -0
  218. Cython/Includes/libcpp/unordered_set.pxd +152 -0
  219. Cython/Includes/libcpp/utility.pxd +30 -0
  220. Cython/Includes/libcpp/vector.pxd +186 -0
  221. Cython/Includes/numpy/math.pxd +150 -0
  222. Cython/Includes/openmp.pxd +50 -0
  223. Cython/Includes/posix/__init__.pxd +1 -0
  224. Cython/Includes/posix/dlfcn.pxd +14 -0
  225. Cython/Includes/posix/fcntl.pxd +86 -0
  226. Cython/Includes/posix/ioctl.pxd +4 -0
  227. Cython/Includes/posix/mman.pxd +101 -0
  228. Cython/Includes/posix/resource.pxd +57 -0
  229. Cython/Includes/posix/select.pxd +21 -0
  230. Cython/Includes/posix/signal.pxd +73 -0
  231. Cython/Includes/posix/stat.pxd +98 -0
  232. Cython/Includes/posix/stdio.pxd +37 -0
  233. Cython/Includes/posix/stdlib.pxd +29 -0
  234. Cython/Includes/posix/strings.pxd +9 -0
  235. Cython/Includes/posix/time.pxd +71 -0
  236. Cython/Includes/posix/types.pxd +30 -0
  237. Cython/Includes/posix/uio.pxd +26 -0
  238. Cython/Includes/posix/unistd.pxd +271 -0
  239. Cython/Includes/posix/wait.pxd +38 -0
  240. Cython/Plex/Actions.pxd +24 -0
  241. Cython/Plex/Actions.py +119 -0
  242. Cython/Plex/Actions.pyd +0 -0
  243. Cython/Plex/DFA.pxd +14 -0
  244. Cython/Plex/DFA.py +164 -0
  245. Cython/Plex/DFA.pyd +0 -0
  246. Cython/Plex/Errors.py +48 -0
  247. Cython/Plex/Lexicons.py +178 -0
  248. Cython/Plex/Machines.pxd +36 -0
  249. Cython/Plex/Machines.py +238 -0
  250. Cython/Plex/Machines.pyd +0 -0
  251. Cython/Plex/Regexps.py +535 -0
  252. Cython/Plex/Scanners.pxd +45 -0
  253. Cython/Plex/Scanners.py +328 -0
  254. Cython/Plex/Scanners.pyd +0 -0
  255. Cython/Plex/Transitions.pxd +14 -0
  256. Cython/Plex/Transitions.py +239 -0
  257. Cython/Plex/Transitions.pyd +0 -0
  258. Cython/Plex/__init__.py +34 -0
  259. Cython/Runtime/__init__.py +1 -0
  260. Cython/Runtime/refnanny.pyd +0 -0
  261. Cython/Runtime/refnanny.pyx +237 -0
  262. Cython/Shadow.py +690 -0
  263. Cython/Shadow.pyi +521 -0
  264. Cython/StringIOTree.py +170 -0
  265. Cython/StringIOTree.pyd +0 -0
  266. Cython/Tempita/__init__.py +4 -0
  267. Cython/Tempita/_looper.py +154 -0
  268. Cython/Tempita/_tempita.py +1091 -0
  269. Cython/Tempita/_tempita.pyd +0 -0
  270. Cython/TestUtils.py +422 -0
  271. Cython/Tests/TestCodeWriter.py +128 -0
  272. Cython/Tests/TestCythonUtils.py +202 -0
  273. Cython/Tests/TestJediTyper.py +223 -0
  274. Cython/Tests/TestShadow.py +114 -0
  275. Cython/Tests/TestStringIOTree.py +67 -0
  276. Cython/Tests/TestTestUtils.py +90 -0
  277. Cython/Tests/__init__.py +1 -0
  278. Cython/Tests/xmlrunner.py +390 -0
  279. Cython/Utility/AsyncGen.c +1031 -0
  280. Cython/Utility/Buffer.c +865 -0
  281. Cython/Utility/BufferFormatFromTypeInfo.pxd +2 -0
  282. Cython/Utility/Builtins.c +810 -0
  283. Cython/Utility/CConvert.pyx +134 -0
  284. Cython/Utility/CMath.c +104 -0
  285. Cython/Utility/CommonStructures.c +226 -0
  286. Cython/Utility/Complex.c +378 -0
  287. Cython/Utility/Coroutine.c +2300 -0
  288. Cython/Utility/CpdefEnums.pyx +103 -0
  289. Cython/Utility/CppConvert.pyx +282 -0
  290. Cython/Utility/CppSupport.cpp +151 -0
  291. Cython/Utility/CythonFunction.c +1832 -0
  292. Cython/Utility/Dataclasses.c +101 -0
  293. Cython/Utility/Embed.c +121 -0
  294. Cython/Utility/Exceptions.c +1016 -0
  295. Cython/Utility/ExtensionTypes.c +996 -0
  296. Cython/Utility/FunctionArguments.c +1043 -0
  297. Cython/Utility/FusedFunction.pyx +44 -0
  298. Cython/Utility/ImportExport.c +907 -0
  299. Cython/Utility/MemoryView.pxd +188 -0
  300. Cython/Utility/MemoryView.pyx +1482 -0
  301. Cython/Utility/MemoryView_C.c +927 -0
  302. Cython/Utility/ModuleSetupCode.c +3203 -0
  303. Cython/Utility/NumpyImportArray.c +46 -0
  304. Cython/Utility/ObjectHandling.c +3273 -0
  305. Cython/Utility/Optimize.c +1603 -0
  306. Cython/Utility/Overflow.c +384 -0
  307. Cython/Utility/Printing.c +86 -0
  308. Cython/Utility/Profile.c +732 -0
  309. Cython/Utility/StringTools.c +1379 -0
  310. Cython/Utility/Synchronization.c +399 -0
  311. Cython/Utility/TString.c +356 -0
  312. Cython/Utility/TestCyUtilityLoader.pyx +8 -0
  313. Cython/Utility/TestCythonScope.pyx +75 -0
  314. Cython/Utility/TestUtilityLoader.c +12 -0
  315. Cython/Utility/TypeConversion.c +1385 -0
  316. Cython/Utility/UFuncs.pyx +50 -0
  317. Cython/Utility/UFuncs_C.c +89 -0
  318. Cython/Utility/__init__.py +28 -0
  319. Cython/Utility/arrayarray.h +167 -0
  320. Cython/Utils.py +687 -0
  321. Cython/Utils.pyd +0 -0
  322. Cython/__init__.py +10 -0
  323. Cython/__init__.pyi +7 -0
  324. Cython/py.typed +0 -0
  325. cython-3.2.0.dist-info/METADATA +85 -0
  326. cython-3.2.0.dist-info/RECORD +333 -0
  327. cython-3.2.0.dist-info/WHEEL +5 -0
  328. cython-3.2.0.dist-info/entry_points.txt +4 -0
  329. cython-3.2.0.dist-info/top_level.txt +3 -0
  330. cython.py +29 -0
  331. pyximport/__init__.py +4 -0
  332. pyximport/pyxbuild.py +160 -0
  333. pyximport/pyximport.py +482 -0
@@ -0,0 +1,4775 @@
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, Utils=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, CompileError
32
+ from .. import Utils
33
+ from . import Future
34
+ from . import Options
35
+
36
+
37
+ _CDEF_MODIFIERS = ('inline', 'nogil', 'api')
38
+ statement_terminators = cython.declare(frozenset, frozenset((
39
+ ';', 'NEWLINE', 'EOF')))
40
+
41
+ class Ctx:
42
+ # Parsing context
43
+ level = 'other'
44
+ visibility = 'private'
45
+ cdef_flag = False
46
+ typedef_flag = False
47
+ api = False
48
+ overridable = False
49
+ nogil = False
50
+ namespace = None
51
+ templates = None
52
+ allow_struct_enum_decorator = False
53
+
54
+ def __init__(self, **kwds):
55
+ self.__dict__.update(kwds)
56
+
57
+ def __call__(self, **kwds):
58
+ ctx = Ctx()
59
+ d = ctx.__dict__
60
+ d.update(self.__dict__)
61
+ d.update(kwds)
62
+ return ctx
63
+
64
+
65
+ @cython.cfunc
66
+ def p_ident(s: PyrexScanner, message="Expected an identifier"):
67
+ if s.sy == 'IDENT':
68
+ name = s.context.intern_ustring(s.systring)
69
+ s.next()
70
+ return name
71
+ else:
72
+ s.error(message)
73
+
74
+
75
+ @cython.cfunc
76
+ def p_ident_list(s: PyrexScanner):
77
+ names = []
78
+ while s.sy == 'IDENT':
79
+ names.append(s.context.intern_ustring(s.systring))
80
+ s.next()
81
+ if s.sy != ',':
82
+ break
83
+ s.next()
84
+ return names
85
+
86
+ #------------------------------------------
87
+ #
88
+ # Expressions
89
+ #
90
+ #------------------------------------------
91
+
92
+ @cython.cfunc
93
+ def p_binop_operator(s: PyrexScanner) -> tuple:
94
+ pos = s.position()
95
+ op = s.sy
96
+ s.next()
97
+ return op, pos
98
+
99
+
100
+ # signature is currently overridden in pxd file
101
+ def p_binop_expr(s: PyrexScanner, ops, p_sub_expr):
102
+ n1 = p_sub_expr(s)
103
+ while s.sy in ops:
104
+ op, pos = p_binop_operator(s)
105
+ n2 = p_sub_expr(s)
106
+ n1 = ExprNodes.binop_node(pos, op, n1, n2)
107
+ if op == '/':
108
+ if Future.division in s.context.future_directives:
109
+ n1.truedivision = True
110
+ else:
111
+ n1.truedivision = None # unknown
112
+ return n1
113
+
114
+
115
+ #lambdef: 'lambda' [varargslist] ':' test
116
+
117
+ @cython.cfunc
118
+ def p_lambdef(s: PyrexScanner):
119
+ # s.sy == 'lambda'
120
+ pos = s.position()
121
+ s.next()
122
+ if s.sy == ':':
123
+ args = []
124
+ star_arg = starstar_arg = None
125
+ else:
126
+ args, star_arg, starstar_arg = p_varargslist(
127
+ s, terminator=':', annotated=False)
128
+ s.expect(':')
129
+ expr = p_test(s)
130
+ return ExprNodes.LambdaNode(
131
+ pos, args = args,
132
+ star_arg = star_arg, starstar_arg = starstar_arg,
133
+ result_expr = expr)
134
+
135
+
136
+ #test: or_test ['if' or_test 'else' test] | lambdef
137
+
138
+ @cython.cfunc
139
+ def p_test(s: PyrexScanner):
140
+ # The check for a following ':=' is only for error reporting purposes.
141
+ # It simply changes a
142
+ # expected ')', found ':='
143
+ # message into something a bit more descriptive.
144
+ # It is close to what the PEG parser does in CPython, where an expression has
145
+ # a lookahead assertion that it isn't followed by ':='
146
+ expr = p_test_allow_walrus_after(s)
147
+ if s.sy == ':=':
148
+ s.error("invalid syntax: assignment expression not allowed in this context")
149
+ return expr
150
+
151
+
152
+ @cython.cfunc
153
+ def p_test_allow_walrus_after(s: PyrexScanner):
154
+ if s.sy == 'lambda':
155
+ return p_lambdef(s)
156
+ pos = s.position()
157
+ expr = p_or_test(s)
158
+ if s.sy == 'if':
159
+ s.next()
160
+ test = p_or_test(s)
161
+ s.expect('else')
162
+ other = p_test(s)
163
+ return ExprNodes.CondExprNode(pos, test=test, true_val=expr, false_val=other)
164
+ else:
165
+ return expr
166
+
167
+
168
+ @cython.cfunc
169
+ def p_namedexpr_test(s: PyrexScanner):
170
+ # defined in the LL parser as
171
+ # namedexpr_test: test [':=' test]
172
+ # The requirement that the LHS is a name is not enforced in the grammar.
173
+ # For comparison the PEG parser does:
174
+ # 1. look for "name :=", if found it's definitely a named expression
175
+ # so look for expression
176
+ # 2. Otherwise, look for expression
177
+ lhs = p_test_allow_walrus_after(s)
178
+ if s.sy == ':=':
179
+ position = s.position()
180
+ if not lhs.is_name:
181
+ s.error("Left-hand side of assignment expression must be an identifier", fatal=False)
182
+ s.next()
183
+ rhs = p_test(s)
184
+ return ExprNodes.AssignmentExpressionNode(position, lhs=lhs, rhs=rhs)
185
+ return lhs
186
+
187
+
188
+ #or_test: and_test ('or' and_test)*
189
+
190
+ COMMON_BINOP_MISTAKES = {'||': 'or', '&&': 'and'}
191
+
192
+ @cython.cfunc
193
+ def p_or_test(s: PyrexScanner):
194
+ return p_rassoc_binop_expr(s, 'or', p_and_test)
195
+
196
+
197
+ # signature is currently overridden in pxd file
198
+ def p_rassoc_binop_expr(s: PyrexScanner, op, p_subexpr):
199
+ n1 = p_subexpr(s)
200
+ if s.sy == op:
201
+ pos = s.position()
202
+ op = s.sy
203
+ s.next()
204
+ n2 = p_rassoc_binop_expr(s, op, p_subexpr)
205
+ n1 = ExprNodes.binop_node(pos, op, n1, n2)
206
+ elif s.sy in COMMON_BINOP_MISTAKES and COMMON_BINOP_MISTAKES[s.sy] == op:
207
+ # Only report this for the current operator since we pass through here twice for 'and' and 'or'.
208
+ warning(s.position(),
209
+ "Found the C operator '%s', did you mean the Python operator '%s'?" % (s.sy, op),
210
+ level=1)
211
+ return n1
212
+
213
+
214
+ #and_test: not_test ('and' not_test)*
215
+
216
+ @cython.cfunc
217
+ def p_and_test(s: PyrexScanner):
218
+ #return p_binop_expr(s, ('and',), p_not_test)
219
+ return p_rassoc_binop_expr(s, 'and', p_not_test)
220
+
221
+
222
+ #not_test: 'not' not_test | comparison
223
+
224
+ @cython.cfunc
225
+ def p_not_test(s: PyrexScanner):
226
+ if s.sy == 'not':
227
+ pos = s.position()
228
+ s.next()
229
+ return ExprNodes.NotNode(pos, operand = p_not_test(s))
230
+ else:
231
+ return p_comparison(s)
232
+
233
+
234
+ #comparison: expr (comp_op expr)*
235
+ #comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
236
+
237
+ @cython.cfunc
238
+ def p_comparison(s: PyrexScanner):
239
+ n1 = p_starred_expr(s)
240
+ if s.sy in comparison_ops:
241
+ pos = s.position()
242
+ op = p_cmp_op(s)
243
+ n2 = p_starred_expr(s)
244
+ n1 = ExprNodes.PrimaryCmpNode(pos,
245
+ operator = op, operand1 = n1, operand2 = n2)
246
+ if s.sy in comparison_ops:
247
+ n1.cascade = p_cascaded_cmp(s)
248
+ return n1
249
+
250
+
251
+ @cython.cfunc
252
+ def p_test_or_starred_expr(s: PyrexScanner):
253
+ if s.sy == '*':
254
+ return p_starred_expr(s)
255
+ else:
256
+ return p_test(s)
257
+
258
+
259
+ @cython.cfunc
260
+ def p_namedexpr_test_or_starred_expr(s: PyrexScanner):
261
+ if s.sy == '*':
262
+ return p_starred_expr(s)
263
+ else:
264
+ return p_namedexpr_test(s)
265
+
266
+
267
+ @cython.cfunc
268
+ def p_starred_expr(s: PyrexScanner):
269
+ pos = s.position()
270
+ if s.sy == '*':
271
+ starred = True
272
+ s.next()
273
+ else:
274
+ starred = False
275
+ expr = p_bit_expr(s)
276
+ if starred:
277
+ expr = ExprNodes.StarredUnpackingNode(pos, expr)
278
+ return expr
279
+
280
+
281
+ @cython.cfunc
282
+ def p_cascaded_cmp(s: PyrexScanner):
283
+ pos = s.position()
284
+ op = p_cmp_op(s)
285
+ n2 = p_starred_expr(s)
286
+ result = ExprNodes.CascadedCmpNode(pos,
287
+ operator = op, operand2 = n2)
288
+ if s.sy in comparison_ops:
289
+ result.cascade = p_cascaded_cmp(s)
290
+ return result
291
+
292
+
293
+ @cython.cfunc
294
+ def p_cmp_op(s: PyrexScanner):
295
+ if s.sy == 'not':
296
+ s.next()
297
+ s.expect('in')
298
+ op = 'not_in'
299
+ elif s.sy == 'is':
300
+ s.next()
301
+ if s.sy == 'not':
302
+ s.next()
303
+ op = 'is_not'
304
+ else:
305
+ op = 'is'
306
+ else:
307
+ op = s.sy
308
+ s.next()
309
+ if op == '<>':
310
+ op = '!='
311
+ return op
312
+
313
+
314
+ comparison_ops = cython.declare(frozenset, frozenset((
315
+ '<', '>', '==', '>=', '<=', '<>', '!=',
316
+ 'in', 'is', 'not'
317
+ )))
318
+
319
+
320
+ #expr: xor_expr ('|' xor_expr)*
321
+
322
+ @cython.cfunc
323
+ def p_bit_expr(s: PyrexScanner):
324
+ return p_binop_expr(s, ('|',), p_xor_expr)
325
+
326
+
327
+ #xor_expr: and_expr ('^' and_expr)*
328
+
329
+ @cython.cfunc
330
+ def p_xor_expr(s: PyrexScanner):
331
+ return p_binop_expr(s, ('^',), p_and_expr)
332
+
333
+
334
+ #and_expr: shift_expr ('&' shift_expr)*
335
+
336
+ @cython.cfunc
337
+ def p_and_expr(s: PyrexScanner):
338
+ return p_binop_expr(s, ('&',), p_shift_expr)
339
+
340
+
341
+ #shift_expr: arith_expr (('<<'|'>>') arith_expr)*
342
+
343
+ @cython.cfunc
344
+ def p_shift_expr(s: PyrexScanner):
345
+ return p_binop_expr(s, ('<<', '>>'), p_arith_expr)
346
+
347
+
348
+ #arith_expr: term (('+'|'-') term)*
349
+
350
+ @cython.cfunc
351
+ def p_arith_expr(s: PyrexScanner):
352
+ return p_binop_expr(s, ('+', '-'), p_term)
353
+
354
+
355
+ #term: factor (('*'|'@'|'/'|'%'|'//') factor)*
356
+
357
+ @cython.cfunc
358
+ def p_term(s: PyrexScanner):
359
+ return p_binop_expr(s, ('*', '@', '/', '%', '//'), p_factor)
360
+
361
+
362
+ #factor: ('+'|'-'|'~'|'&'|typecast|sizeof) factor | power
363
+
364
+ @cython.cfunc
365
+ def p_factor(s: PyrexScanner):
366
+ # little indirection for C-ification purposes
367
+ return _p_factor(s)
368
+
369
+
370
+ @cython.cfunc
371
+ def _p_factor(s: PyrexScanner):
372
+ sy = s.sy
373
+ if sy in ('+', '-', '~'):
374
+ op = s.sy
375
+ pos = s.position()
376
+ s.next()
377
+ return ExprNodes.unop_node(pos, op, p_factor(s))
378
+ elif not s.in_python_file:
379
+ if sy == '&':
380
+ pos = s.position()
381
+ s.next()
382
+ arg = p_factor(s)
383
+ return ExprNodes.AmpersandNode(pos, operand = arg)
384
+ elif sy == "<":
385
+ return p_typecast(s)
386
+ elif sy == 'IDENT' and s.systring == "sizeof":
387
+ return p_sizeof(s)
388
+ return p_power(s)
389
+
390
+
391
+ @cython.cfunc
392
+ def p_typecast(s: PyrexScanner):
393
+ # s.sy == "<"
394
+ pos = s.position()
395
+ s.next()
396
+ base_type = p_c_base_type(s)
397
+ is_memslice = isinstance(base_type, Nodes.MemoryViewSliceTypeNode)
398
+ is_other_unnamed_type = isinstance(base_type, (
399
+ Nodes.TemplatedTypeNode,
400
+ Nodes.CConstOrVolatileTypeNode,
401
+ Nodes.CTupleBaseTypeNode,
402
+ ))
403
+ if not (is_memslice or is_other_unnamed_type) and base_type.name is None:
404
+ s.error("Unknown type")
405
+ declarator = p_c_declarator(s, empty=True)
406
+ if s.sy == '?':
407
+ s.next()
408
+ typecheck = True
409
+ else:
410
+ typecheck = False
411
+ s.expect(">")
412
+ operand = p_factor(s)
413
+ if is_memslice:
414
+ return ExprNodes.CythonArrayNode(pos, base_type_node=base_type, operand=operand)
415
+
416
+ return ExprNodes.TypecastNode(pos,
417
+ base_type = base_type,
418
+ declarator = declarator,
419
+ operand = operand,
420
+ typecheck = typecheck)
421
+
422
+
423
+ @cython.cfunc
424
+ def p_sizeof(s: PyrexScanner):
425
+ # s.sy == ident "sizeof"
426
+ pos = s.position()
427
+ s.next()
428
+ s.expect('(')
429
+ # Here we decide if we are looking at an expression or type
430
+ # If it is actually a type, but parsable as an expression,
431
+ # we treat it as an expression here.
432
+ if looking_at_expr(s):
433
+ operand = p_test(s)
434
+ node = ExprNodes.SizeofVarNode(pos, operand = operand)
435
+ else:
436
+ base_type = p_c_base_type(s)
437
+ declarator = p_c_declarator(s, empty=True)
438
+ node = ExprNodes.SizeofTypeNode(pos,
439
+ base_type = base_type, declarator = declarator)
440
+ s.expect(')')
441
+ return node
442
+
443
+
444
+ @cython.cfunc
445
+ def p_yield_expression(s: PyrexScanner, statement_terminators: frozenset = statement_terminators):
446
+ # s.sy == "yield"
447
+ pos = s.position()
448
+ s.next()
449
+ is_yield_from = False
450
+ if s.sy == 'from':
451
+ is_yield_from = True
452
+ s.next()
453
+ if s.sy != ')' and s.sy not in statement_terminators:
454
+ # "yield from" does not support implicit tuples, but "yield" does ("yield 1,2")
455
+ arg = p_test(s) if is_yield_from else p_testlist(s)
456
+ else:
457
+ if is_yield_from:
458
+ s.error("'yield from' requires a source argument",
459
+ pos=pos, fatal=False)
460
+ arg = None
461
+ if is_yield_from:
462
+ return ExprNodes.YieldFromExprNode(pos, arg=arg)
463
+ else:
464
+ return ExprNodes.YieldExprNode(pos, arg=arg)
465
+
466
+
467
+ @cython.cfunc
468
+ def p_yield_statement(s: PyrexScanner):
469
+ # s.sy == "yield"
470
+ yield_expr = p_yield_expression(s)
471
+ return Nodes.ExprStatNode(yield_expr.pos, expr=yield_expr)
472
+
473
+
474
+ @cython.cfunc
475
+ def p_async_statement(s: PyrexScanner, ctx, decorators):
476
+ # s.sy >> 'async' ...
477
+ if s.sy == 'def':
478
+ # 'async def' statements aren't allowed in pxd files
479
+ if 'pxd' in ctx.level:
480
+ s.error('def statement not allowed here')
481
+ s.level = ctx.level
482
+ return p_def_statement(s, decorators, is_async_def=True)
483
+ elif decorators:
484
+ s.error("Decorators can only be followed by functions or classes")
485
+ elif s.sy == 'for':
486
+ return p_for_statement(s, is_async=True)
487
+ elif s.sy == 'with':
488
+ s.next()
489
+ return p_with_items(s, is_async=True)
490
+ else:
491
+ s.error("expected one of 'def', 'for', 'with' after 'async'")
492
+
493
+
494
+ #power: atom_expr ('**' factor)*
495
+ #atom_expr: ['await'] atom trailer*
496
+
497
+ @cython.cfunc
498
+ def p_power(s: PyrexScanner):
499
+ if s.systring == 'new' and s.peek()[0] == 'IDENT':
500
+ return p_new_expr(s)
501
+ await_pos = None
502
+ if s.sy == 'await':
503
+ await_pos = s.position()
504
+ s.next()
505
+ n1 = p_atom(s)
506
+ while s.sy in ('(', '[', '.'):
507
+ n1 = p_trailer(s, n1)
508
+ if await_pos:
509
+ n1 = ExprNodes.AwaitExprNode(await_pos, arg=n1)
510
+ if s.sy == '**':
511
+ pos = s.position()
512
+ s.next()
513
+ n2 = p_factor(s)
514
+ n1 = ExprNodes.binop_node(pos, '**', n1, n2)
515
+ return n1
516
+
517
+
518
+ @cython.cfunc
519
+ def p_new_expr(s: PyrexScanner):
520
+ # s.systring == 'new'.
521
+ pos = s.position()
522
+ s.next()
523
+ cppclass = p_c_base_type(s)
524
+ return p_call(s, ExprNodes.NewExprNode(pos, cppclass = cppclass))
525
+
526
+
527
+ #trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
528
+
529
+ @cython.cfunc
530
+ def p_trailer(s: PyrexScanner, node1):
531
+ pos = s.position()
532
+ if s.sy == '(':
533
+ return p_call(s, node1)
534
+ elif s.sy == '[':
535
+ return p_index(s, node1)
536
+ else: # s.sy == '.'
537
+ s.next()
538
+ name = p_ident(s)
539
+ return ExprNodes.AttributeNode(pos,
540
+ obj=node1, attribute=name)
541
+
542
+
543
+ # arglist: argument (',' argument)* [',']
544
+ # argument: [test '='] test # Really [keyword '='] test
545
+
546
+ # since PEP 448:
547
+ # argument: ( test [comp_for] |
548
+ # test '=' test |
549
+ # '**' expr |
550
+ # star_expr )
551
+
552
+ @cython.cfunc
553
+ def p_call_parse_args(s: PyrexScanner, allow_genexp: cython.bint = True):
554
+ # s.sy == '('
555
+ s.next()
556
+ positional_args = []
557
+ keyword_args = []
558
+ starstar_seen = False
559
+ last_was_tuple_unpack = False
560
+ while s.sy != ')':
561
+ if s.sy == '*':
562
+ if starstar_seen:
563
+ s.error("Non-keyword arg following keyword arg", pos=s.position())
564
+ s.next()
565
+ positional_args.append(p_test(s))
566
+ last_was_tuple_unpack = True
567
+ elif s.sy == '**':
568
+ s.next()
569
+ keyword_args.append(p_test(s))
570
+ starstar_seen = True
571
+ else:
572
+ arg = p_namedexpr_test(s)
573
+ if s.sy == '=':
574
+ s.next()
575
+ if not arg.is_name:
576
+ s.error("Expected an identifier before '='",
577
+ pos=arg.pos)
578
+ encoded_name = s.context.intern_ustring(arg.name)
579
+ keyword = ExprNodes.IdentifierStringNode(
580
+ arg.pos, value=encoded_name)
581
+ arg = p_test(s)
582
+ keyword_args.append((keyword, arg))
583
+ else:
584
+ if keyword_args:
585
+ s.error("Non-keyword arg following keyword arg", pos=arg.pos)
586
+ if positional_args and not last_was_tuple_unpack:
587
+ positional_args[-1].append(arg)
588
+ else:
589
+ positional_args.append([arg])
590
+ last_was_tuple_unpack = False
591
+ if s.sy != ',':
592
+ break
593
+ s.next()
594
+
595
+ if s.sy in ('for', 'async') and allow_genexp:
596
+ if not keyword_args and not last_was_tuple_unpack:
597
+ if len(positional_args) == 1 and len(positional_args[0]) == 1:
598
+ positional_args = [[p_genexp(s, positional_args[0][0])]]
599
+ s.expect(')')
600
+ return positional_args or [[]], keyword_args
601
+
602
+
603
+ @cython.cfunc
604
+ def p_call_build_packed_args(pos, positional_args, keyword_args) -> tuple:
605
+ keyword_dict = None
606
+
607
+ subtuples = [
608
+ ExprNodes.TupleNode(pos, args=arg) if isinstance(arg, list) else ExprNodes.AsTupleNode(pos, arg=arg)
609
+ for arg in positional_args
610
+ ]
611
+ # TODO: implement a faster way to join tuples than creating each one and adding them
612
+ arg_tuple = reduce(partial(ExprNodes.binop_node, pos, '+'), subtuples)
613
+
614
+ if keyword_args:
615
+ kwargs = []
616
+ dict_items = []
617
+ for item in keyword_args:
618
+ if isinstance(item, tuple):
619
+ key, value = item
620
+ dict_items.append(ExprNodes.DictItemNode(pos=key.pos, key=key, value=value))
621
+ elif item.is_dict_literal:
622
+ # unpack "**{a:b}" directly
623
+ dict_items.extend(item.key_value_pairs)
624
+ else:
625
+ if dict_items:
626
+ kwargs.append(ExprNodes.DictNode(
627
+ dict_items[0].pos, key_value_pairs=dict_items, reject_duplicates=True))
628
+ dict_items = []
629
+ kwargs.append(item)
630
+
631
+ if dict_items:
632
+ kwargs.append(ExprNodes.DictNode(
633
+ dict_items[0].pos, key_value_pairs=dict_items, reject_duplicates=True))
634
+
635
+ if kwargs:
636
+ if len(kwargs) == 1 and kwargs[0].is_dict_literal:
637
+ # only simple keyword arguments found -> one dict
638
+ keyword_dict = kwargs[0]
639
+ else:
640
+ # at least one **kwargs
641
+ keyword_dict = ExprNodes.MergedDictNode(pos, keyword_args=kwargs)
642
+
643
+ return arg_tuple, keyword_dict
644
+
645
+
646
+ @cython.cfunc
647
+ def p_call(s: PyrexScanner, function):
648
+ # s.sy == '('
649
+ pos = s.position()
650
+ positional_args, keyword_args = p_call_parse_args(s)
651
+
652
+ if not keyword_args and len(positional_args) == 1 and isinstance(positional_args[0], list):
653
+ return ExprNodes.SimpleCallNode(pos, function=function, args=positional_args[0])
654
+ else:
655
+ arg_tuple, keyword_dict = p_call_build_packed_args(pos, positional_args, keyword_args)
656
+ return ExprNodes.GeneralCallNode(
657
+ pos, function=function, positional_args=arg_tuple, keyword_args=keyword_dict)
658
+
659
+
660
+ #lambdef: 'lambda' [varargslist] ':' test
661
+
662
+ #subscriptlist: subscript (',' subscript)* [',']
663
+
664
+ @cython.cfunc
665
+ def p_index(s: PyrexScanner, base):
666
+ # s.sy == '['
667
+ pos = s.position()
668
+ s.next()
669
+ subscripts, is_single_value = p_subscript_list(s)
670
+ if is_single_value and len(subscripts[0]) == 2:
671
+ start, stop = subscripts[0]
672
+ result = ExprNodes.SliceIndexNode(pos,
673
+ base = base, start = start, stop = stop)
674
+ else:
675
+ indexes = make_slice_nodes(pos, subscripts)
676
+ if is_single_value:
677
+ index = indexes[0]
678
+ else:
679
+ index = ExprNodes.TupleNode(pos, args = indexes)
680
+ result = ExprNodes.IndexNode(pos,
681
+ base = base, index = index)
682
+ s.expect(']')
683
+ return result
684
+
685
+
686
+ @cython.cfunc
687
+ def p_subscript_list(s: PyrexScanner) -> tuple:
688
+ is_single_value = True
689
+ items = [p_subscript(s)]
690
+ while s.sy == ',':
691
+ is_single_value = False
692
+ s.next()
693
+ if s.sy == ']':
694
+ break
695
+ items.append(p_subscript(s))
696
+ return items, is_single_value
697
+
698
+
699
+ #subscript: '.' '.' '.' | test | [test] ':' [test] [':' [test]]
700
+
701
+ @cython.cfunc
702
+ def p_subscript(s: PyrexScanner):
703
+ # Parse a subscript and return a list of
704
+ # 1, 2 or 3 ExprNodes, depending on how
705
+ # many slice elements were encountered.
706
+ start = p_slice_element(s, (':',))
707
+ if s.sy != ':':
708
+ return [start]
709
+ s.next()
710
+ stop = p_slice_element(s, (':', ',', ']'))
711
+ if s.sy != ':':
712
+ return [start, stop]
713
+ s.next()
714
+ step = p_slice_element(s, (':', ',', ']'))
715
+ return [start, stop, step]
716
+
717
+
718
+ @cython.cfunc
719
+ def p_slice_element(s: PyrexScanner, follow_set):
720
+ # Simple expression which may be missing iff
721
+ # it is followed by something in follow_set.
722
+ if s.sy not in follow_set:
723
+ return p_test(s)
724
+ else:
725
+ return None
726
+
727
+
728
+ @cython.cfunc
729
+ def expect_ellipsis(s: PyrexScanner):
730
+ s.expect('...')
731
+
732
+
733
+ @cython.cfunc
734
+ def make_slice_nodes(pos, subscripts):
735
+ # Convert a list of subscripts as returned
736
+ # by p_subscript_list into a list of ExprNodes,
737
+ # creating SliceNodes for elements with 2 or
738
+ # more components.
739
+ result = []
740
+ for subscript in subscripts:
741
+ if len(subscript) == 1:
742
+ result.append(subscript[0])
743
+ else:
744
+ result.append(make_slice_node(pos, *subscript))
745
+ return result
746
+
747
+
748
+ @cython.ccall
749
+ def make_slice_node(pos, start, stop = None, step = None):
750
+ if not start:
751
+ start = ExprNodes.NoneNode(pos)
752
+ if not stop:
753
+ stop = ExprNodes.NoneNode(pos)
754
+ if not step:
755
+ step = ExprNodes.NoneNode(pos)
756
+ return ExprNodes.SliceNode(pos,
757
+ start = start, stop = stop, step = step)
758
+
759
+
760
+ #atom: '(' [yield_expr|testlist_comp] ')' | '[' [listmaker] ']' | '{' [dict_or_set_maker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
761
+
762
+ @cython.cfunc
763
+ def p_atom(s: PyrexScanner):
764
+ pos = s.position()
765
+ sy = s.sy
766
+ if sy == '(':
767
+ s.next()
768
+ if s.sy == ')':
769
+ result = ExprNodes.TupleNode(pos, args = [])
770
+ elif s.sy == 'yield':
771
+ result = p_yield_expression(s)
772
+ else:
773
+ result = p_testlist_comp(s)
774
+ s.expect(')')
775
+ return result
776
+ elif sy == '[':
777
+ return p_list_maker(s)
778
+ elif sy == '{':
779
+ return p_dict_or_set_maker(s)
780
+ elif sy == '`':
781
+ return p_backquote_expr(s)
782
+ elif sy == '...':
783
+ expect_ellipsis(s)
784
+ return ExprNodes.EllipsisNode(pos)
785
+ elif sy == 'INT':
786
+ return p_int_literal(s)
787
+ elif sy == 'FLOAT':
788
+ value = s.systring
789
+ s.next()
790
+ return ExprNodes.FloatNode(pos, value = value)
791
+ elif sy == 'IMAG':
792
+ value = s.systring[:-1]
793
+ s.next()
794
+ return ExprNodes.ImagNode(pos, value = value)
795
+ elif sy == 'BEGIN_STRING' or sy == 'BEGIN_FT_STRING':
796
+ return p_atom_string(s)
797
+ elif sy == 'IDENT':
798
+ result = p_atom_ident_constants(s)
799
+ if result is None:
800
+ result = p_name(s, s.systring)
801
+ s.next()
802
+ return result
803
+ else:
804
+ s.error("Expected an identifier or literal")
805
+
806
+
807
+ @cython.cfunc
808
+ def p_atom_string(s: PyrexScanner):
809
+ # s.sy == 'BEGIN_STRING' or s.sy == 'BEGIN_FT_STRING'
810
+ pos = s.position()
811
+ kind, bytes_value, unicode_value = p_cat_string_literal(s)
812
+ if not kind:
813
+ return ExprNodes.UnicodeNode(pos, value=unicode_value, bytes_value=bytes_value)
814
+ kind_char: cython.Py_UCS4 = kind
815
+ if kind_char == 'c':
816
+ return ExprNodes.CharNode(pos, value=bytes_value)
817
+ elif kind_char == 'u':
818
+ return ExprNodes.UnicodeNode(pos, value=unicode_value, bytes_value=bytes_value)
819
+ elif kind_char == 'b':
820
+ return ExprNodes.BytesNode(pos, value=bytes_value)
821
+ elif kind_char == 'f':
822
+ return ExprNodes.JoinedStrNode(pos, values=unicode_value)
823
+ elif kind_char == 't':
824
+ # TODO
825
+ return ExprNodes.TemplateStringNode(pos, values=unicode_value)
826
+ else:
827
+ # This is actually prevented by the scanner (Lexicon.py).
828
+ s.error(f"invalid string kind '{kind}'")
829
+
830
+
831
+ @cython.cfunc
832
+ def p_atom_ident_constants(s: PyrexScanner):
833
+ """
834
+ Returns None if it isn't a special-cased named constant.
835
+ Only calls s.next() if it successfully matches a named constant.
836
+ """
837
+ # s.sy == 'IDENT'
838
+ pos = s.position()
839
+ name = s.systring
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):
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):
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):
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 not ExprNodes.FormattedValueNode.find_conversion_func(conversion_char):
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):
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):
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):
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:
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):
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.CConstOrVolatileTypeNode(pos,
2822
+ base_type=base_type.base_type_node, is_const=is_const, is_volatile=is_volatile)
2823
+ return base_type
2824
+ return Nodes.CConstOrVolatileTypeNode(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_const = s.systring == 'const' and s.sy == 'IDENT'
3184
+ if is_const:
3185
+ s.next()
3186
+
3187
+ base = p_c_declarator(s, ctx, empty=empty, is_type=is_type,
3188
+ cmethod_flag=cmethod_flag,
3189
+ assignable=assignable, nonempty=nonempty)
3190
+ if is_const:
3191
+ base = Nodes.CConstDeclaratorNode(const_pos, base=base)
3192
+ if is_ptrptr:
3193
+ base = Nodes.CPtrDeclaratorNode(pos, base=base)
3194
+ result = Nodes.CPtrDeclaratorNode(pos, base=base)
3195
+ elif s.sy == '&' or (s.sy == '&&' and s.context.cpp):
3196
+ node_class = Nodes.CppRvalueReferenceDeclaratorNode if s.sy == '&&' else Nodes.CReferenceDeclaratorNode
3197
+ s.next()
3198
+ base = p_c_declarator(s, ctx, empty=empty, is_type=is_type,
3199
+ cmethod_flag=cmethod_flag,
3200
+ assignable=assignable, nonempty=nonempty)
3201
+ result = node_class(pos, base=base)
3202
+ else:
3203
+ rhs = None
3204
+ if s.sy == 'IDENT':
3205
+ name = s.systring
3206
+ if empty:
3207
+ error(s.position(), "Declarator should be empty")
3208
+ s.next()
3209
+ cname = p_opt_cname(s)
3210
+ if name != 'operator' and s.sy == '=' and assignable:
3211
+ s.next()
3212
+ rhs = p_test(s)
3213
+ else:
3214
+ if nonempty:
3215
+ error(s.position(), "Empty declarator")
3216
+ name = ""
3217
+ cname = None
3218
+ if cname is None and ctx.namespace is not None and nonempty:
3219
+ cname = ctx.namespace + "::" + name
3220
+ if name == 'operator' and ctx.visibility == 'extern' and nonempty:
3221
+ op = s.sy
3222
+ if [1 for c in op if c in '+-*/<=>!%&|([^~,']:
3223
+ s.next()
3224
+ # Handle diphthong operators.
3225
+ if op == '(':
3226
+ s.expect(')')
3227
+ op = '()'
3228
+ elif op == '[':
3229
+ s.expect(']')
3230
+ op = '[]'
3231
+ elif op in ('-', '+', '|', '&') and s.sy == op:
3232
+ op *= 2 # ++, --, ...
3233
+ s.next()
3234
+ elif s.sy == '=':
3235
+ op += s.sy # +=, -=, ...
3236
+ s.next()
3237
+ if op not in supported_overloaded_operators:
3238
+ s.error("Overloading operator '%s' not yet supported." % op,
3239
+ fatal=False)
3240
+ name += op
3241
+ elif op == 'IDENT':
3242
+ op = s.systring
3243
+ if op not in supported_overloaded_operators:
3244
+ s.error("Overloading operator '%s' not yet supported." % op,
3245
+ fatal=False)
3246
+ name = name + ' ' + op
3247
+ s.next()
3248
+ result = Nodes.CNameDeclaratorNode(pos,
3249
+ name = name, cname = cname, default = rhs)
3250
+ result.calling_convention = calling_convention
3251
+ return result
3252
+
3253
+
3254
+ @cython.cfunc
3255
+ def p_nogil(s: PyrexScanner) -> cython.bint:
3256
+ if s.sy == 'IDENT' and s.systring == 'nogil':
3257
+ s.next()
3258
+ return True
3259
+ else:
3260
+ return False
3261
+
3262
+
3263
+ @cython.cfunc
3264
+ def p_with_gil(s: PyrexScanner) -> cython.bint:
3265
+ if s.sy == 'with':
3266
+ s.next()
3267
+ s.expect_keyword('gil')
3268
+ return True
3269
+ else:
3270
+ return False
3271
+
3272
+
3273
+ @cython.cfunc
3274
+ def p_exception_value_clause(s: PyrexScanner, is_extern: cython.bint) -> tuple:
3275
+ """
3276
+ Parse exception value clause.
3277
+
3278
+ Maps clauses to exc_check / exc_value / exc_clause as follows:
3279
+ ______________________________________________________________________
3280
+ | | | | |
3281
+ | Clause | exc_check | exc_value | exc_clause |
3282
+ | ___________________________ | ___________ | ___________ | __________ |
3283
+ | | | | |
3284
+ | <nothing> (default func.) | True | None | False |
3285
+ | <nothing> (cdef extern) | False | None | False |
3286
+ | noexcept | False | None | True |
3287
+ | except <val> | False | <val> | True |
3288
+ | except? <val> | True | <val> | True |
3289
+ | except * | True | None | True |
3290
+ | except + | '+' | None | True |
3291
+ | except +* | '+' | '*' | True |
3292
+ | except +<PyErr> | '+' | <PyErr> | True |
3293
+ | ___________________________ | ___________ | ___________ | __________ |
3294
+
3295
+ Note that the only reason we need `exc_clause` is to raise a
3296
+ warning when `'except'` or `'noexcept'` is placed after the
3297
+ `'nogil'` keyword.
3298
+ """
3299
+ exc_clause: cython.bint = False
3300
+ exc_val = None
3301
+ exc_check = False if is_extern else True
3302
+
3303
+ if s.sy == 'IDENT' and s.systring == 'noexcept':
3304
+ exc_clause = True
3305
+ s.next()
3306
+ exc_check = False
3307
+ elif s.sy == 'except':
3308
+ exc_clause = True
3309
+ s.next()
3310
+ if s.sy == '*':
3311
+ exc_check = True
3312
+ s.next()
3313
+ elif s.sy == '+':
3314
+ exc_check = '+'
3315
+ plus_char_pos = s.position()[2]
3316
+ s.next()
3317
+ if s.sy == 'IDENT':
3318
+ name = s.systring
3319
+ if name == 'nogil':
3320
+ if s.position()[2] == plus_char_pos + 1:
3321
+ error(s.position(),
3322
+ "'except +nogil' defines an exception handling function. Use 'except + nogil' for the 'nogil' modifier.")
3323
+ # 'except + nogil' is parsed outside
3324
+ else:
3325
+ exc_val = p_name(s, name)
3326
+ s.next()
3327
+ elif s.sy == '*':
3328
+ exc_val = ExprNodes.CharNode(s.position(), value='*')
3329
+ s.next()
3330
+ else:
3331
+ if s.sy == '?':
3332
+ exc_check = True
3333
+ s.next()
3334
+ else:
3335
+ exc_check = False
3336
+ # exc_val can be non-None even if exc_check is False, c.f. "except -1"
3337
+ exc_val = p_test(s)
3338
+
3339
+ return exc_val, exc_check, exc_clause
3340
+
3341
+
3342
+ c_arg_list_terminators = cython.declare(frozenset, frozenset((
3343
+ '*', '**', '...', ')', ':', '/')))
3344
+
3345
+
3346
+ @cython.ccall
3347
+ def p_c_arg_list(s: PyrexScanner, ctx = Ctx(),
3348
+ in_pyfunc: cython.bint = False, cmethod_flag: cython.bint = False,
3349
+ nonempty_declarators: cython.bint = False, kw_only: cython.bint = False,
3350
+ annotated: cython.bint = True) -> list:
3351
+ # Comma-separated list of C argument declarations, possibly empty.
3352
+ # May have a trailing comma.
3353
+ args = []
3354
+ is_self_arg = cmethod_flag
3355
+ while s.sy not in c_arg_list_terminators:
3356
+ args.append(p_c_arg_decl(s, ctx, in_pyfunc, is_self_arg,
3357
+ nonempty = nonempty_declarators, kw_only = kw_only,
3358
+ annotated = annotated))
3359
+ if s.sy != ',':
3360
+ break
3361
+ s.next()
3362
+ is_self_arg = 0
3363
+ return args
3364
+
3365
+
3366
+ @cython.cfunc
3367
+ def p_optional_ellipsis(s: PyrexScanner) -> cython.bint:
3368
+ if s.sy == '...':
3369
+ expect_ellipsis(s)
3370
+ return True
3371
+ else:
3372
+ return False
3373
+
3374
+
3375
+ @cython.cfunc
3376
+ def p_c_arg_decl(s: PyrexScanner, ctx, in_pyfunc: cython.bint, cmethod_flag: cython.bint = False,
3377
+ nonempty: cython.bint = False,
3378
+ kw_only: cython.bint = False, annotated: cython.bint = True):
3379
+ pos = s.position()
3380
+ not_none = or_none = False
3381
+ default = None
3382
+ annotation = None
3383
+ if s.in_python_file:
3384
+ # empty type declaration
3385
+ base_type = Nodes.CSimpleBaseTypeNode(pos,
3386
+ name = None, module_path = [],
3387
+ is_basic_c_type = False, signed = 0,
3388
+ complex = False, longness = 0,
3389
+ is_self_arg = cmethod_flag, templates = None)
3390
+ else:
3391
+ base_type = p_c_base_type(s, nonempty=nonempty)
3392
+ declarator = p_c_declarator(s, ctx, nonempty = nonempty)
3393
+ if s.sy in ('not', 'or') and not s.in_python_file:
3394
+ kind = s.sy
3395
+ s.next()
3396
+ if s.sy == 'IDENT' and s.systring == 'None':
3397
+ s.next()
3398
+ else:
3399
+ s.error("Expected 'None'")
3400
+ if not in_pyfunc:
3401
+ error(pos, "'%s None' only allowed in Python functions" % kind)
3402
+ or_none = kind == 'or'
3403
+ not_none = kind == 'not'
3404
+ if annotated and s.sy == ':':
3405
+ s.next()
3406
+ annotation = p_annotation(s)
3407
+ if s.sy == '=':
3408
+ s.next()
3409
+ if 'pxd' in ctx.level:
3410
+ if s.sy in ['*', '?']:
3411
+ # TODO(github/1736): Make this an error for inline declarations.
3412
+ default = ExprNodes.NoneNode(pos)
3413
+ s.next()
3414
+ elif 'inline' in ctx.modifiers:
3415
+ default = p_test(s)
3416
+ else:
3417
+ error(pos, "default values cannot be specified in pxd files, use ? or *")
3418
+ else:
3419
+ default = p_test(s)
3420
+ return Nodes.CArgDeclNode(pos,
3421
+ base_type = base_type,
3422
+ declarator = declarator,
3423
+ not_none = not_none,
3424
+ or_none = or_none,
3425
+ default = default,
3426
+ annotation = annotation,
3427
+ kw_only = kw_only)
3428
+
3429
+
3430
+ @cython.cfunc
3431
+ def p_annotation(s: PyrexScanner):
3432
+ """An annotation just has the "test" syntax, but also stores the string it came from
3433
+
3434
+ Note that the string is *allowed* to be changed/processed (although isn't here)
3435
+ so may not exactly match the string generated by Python, and if it doesn't
3436
+ then it is not a bug.
3437
+ """
3438
+ pos = s.position()
3439
+ expr = p_test(s)
3440
+ return ExprNodes.AnnotationNode(pos, expr=expr)
3441
+
3442
+
3443
+ @cython.cfunc
3444
+ def p_api(s: PyrexScanner) -> cython.bint:
3445
+ if s.sy == 'IDENT' and s.systring == 'api':
3446
+ s.next()
3447
+ return True
3448
+ else:
3449
+ return False
3450
+
3451
+
3452
+ @cython.cfunc
3453
+ def p_cdef_statement(s: PyrexScanner, pos, ctx):
3454
+ ctx.visibility = p_visibility(s, ctx.visibility)
3455
+ ctx.api = ctx.api or p_api(s)
3456
+ if ctx.api:
3457
+ if ctx.visibility not in ('private', 'public'):
3458
+ error(pos, "Cannot combine 'api' with '%s'" % ctx.visibility)
3459
+ if (ctx.visibility == 'extern') and s.sy == 'from':
3460
+ return p_cdef_extern_block(s, pos, ctx)
3461
+ elif s.sy == 'import':
3462
+ s.next()
3463
+ return p_cdef_extern_block(s, pos, ctx)
3464
+ elif p_nogil(s):
3465
+ ctx.nogil = True
3466
+ if ctx.overridable:
3467
+ error(pos, "cdef blocks cannot be declared cpdef")
3468
+ return p_cdef_block(s, ctx)
3469
+ elif s.sy == ':':
3470
+ if ctx.overridable:
3471
+ error(pos, "cdef blocks cannot be declared cpdef")
3472
+ return p_cdef_block(s, ctx)
3473
+ elif s.sy == 'class':
3474
+ if ctx.level not in ('module', 'module_pxd'):
3475
+ error(pos, "Extension type definition not allowed here")
3476
+ if ctx.overridable:
3477
+ error(pos, "Extension types cannot be declared cpdef")
3478
+ return p_c_class_definition(s, pos, ctx)
3479
+ elif s.sy == 'IDENT' and s.systring == 'cppclass':
3480
+ return p_cpp_class_definition(s, pos, ctx)
3481
+ elif s.sy == 'IDENT' and s.systring in struct_enum_union:
3482
+ if ctx.level not in ('module', 'module_pxd'):
3483
+ error(pos, "C struct/union/enum definition not allowed here")
3484
+ if ctx.overridable:
3485
+ if s.systring != 'enum':
3486
+ error(pos, "C struct/union cannot be declared cpdef")
3487
+ return p_struct_enum(s, pos, ctx)
3488
+ elif s.sy == 'IDENT' and s.systring == 'fused':
3489
+ return p_fused_definition(s, pos, ctx)
3490
+ else:
3491
+ return p_c_func_or_var_declaration(s, pos, ctx)
3492
+
3493
+
3494
+ @cython.cfunc
3495
+ def p_cdef_block(s: PyrexScanner, ctx):
3496
+ return p_suite(s, ctx(cdef_flag = True))
3497
+
3498
+
3499
+ @cython.cfunc
3500
+ def p_cdef_extern_block(s: PyrexScanner, pos, ctx):
3501
+ if ctx.overridable:
3502
+ error(pos, "cdef extern blocks cannot be declared cpdef")
3503
+ include_file = None
3504
+ s.expect('from')
3505
+ if s.sy == '*':
3506
+ s.next()
3507
+ else:
3508
+ include_file = p_string_literal(s, 'u')[2]
3509
+ ctx = ctx(cdef_flag = True, visibility = 'extern')
3510
+ if s.systring == "namespace":
3511
+ s.next()
3512
+ ctx.namespace = p_string_literal(s, 'u')[2]
3513
+ if p_nogil(s):
3514
+ ctx.nogil = True
3515
+
3516
+ # Use "docstring" as verbatim string to include
3517
+ verbatim_include, body = p_suite_with_docstring(s, ctx, True)
3518
+
3519
+ return Nodes.CDefExternNode(pos,
3520
+ include_file = include_file,
3521
+ verbatim_include = verbatim_include,
3522
+ body = body,
3523
+ namespace = ctx.namespace)
3524
+
3525
+
3526
+ @cython.cfunc
3527
+ def p_c_enum_definition(s: PyrexScanner, pos, ctx):
3528
+ # s.sy == ident 'enum'
3529
+ s.next()
3530
+
3531
+ scoped = False
3532
+ if s.context.cpp and (s.sy == 'class' or (s.sy == 'IDENT' and s.systring == 'struct')):
3533
+ scoped = True
3534
+ s.next()
3535
+
3536
+ if s.sy == 'IDENT':
3537
+ name = s.systring
3538
+ s.next()
3539
+ cname = p_opt_cname(s)
3540
+ if cname is None and ctx.namespace is not None:
3541
+ cname = ctx.namespace + "::" + name
3542
+ else:
3543
+ name = cname = None
3544
+ if scoped:
3545
+ s.error("Unnamed scoped enum not allowed")
3546
+
3547
+ if scoped and s.sy == '(':
3548
+ s.next()
3549
+ underlying_type = p_c_base_type(s)
3550
+ s.expect(')')
3551
+ else:
3552
+ underlying_type = Nodes.CSimpleBaseTypeNode(
3553
+ pos,
3554
+ name="int",
3555
+ module_path = [],
3556
+ is_basic_c_type = True,
3557
+ signed = 1,
3558
+ complex = False,
3559
+ longness = 0
3560
+ )
3561
+
3562
+ s.expect(':')
3563
+ items = []
3564
+
3565
+ doc = None
3566
+ if s.sy != 'NEWLINE':
3567
+ p_c_enum_line(s, ctx, items)
3568
+ else:
3569
+ s.next() # 'NEWLINE'
3570
+ s.expect_indent()
3571
+ doc = p_doc_string(s)
3572
+
3573
+ while s.sy not in ('DEDENT', 'EOF'):
3574
+ p_c_enum_line(s, ctx, items)
3575
+
3576
+ s.expect_dedent()
3577
+
3578
+ if not items and ctx.visibility != "extern":
3579
+ error(pos, "Empty enum definition not allowed outside a 'cdef extern from' block")
3580
+
3581
+ return Nodes.CEnumDefNode(
3582
+ pos, name=name, cname=cname,
3583
+ scoped=scoped, items=items,
3584
+ underlying_type=underlying_type,
3585
+ typedef_flag=ctx.typedef_flag, visibility=ctx.visibility,
3586
+ create_wrapper=ctx.overridable,
3587
+ api=ctx.api, in_pxd=ctx.level == 'module_pxd', doc=doc)
3588
+
3589
+
3590
+ @cython.cfunc
3591
+ def p_c_enum_line(s: PyrexScanner, ctx, items: list):
3592
+ if s.sy != 'pass':
3593
+ p_c_enum_item(s, ctx, items)
3594
+ while s.sy == ',':
3595
+ s.next()
3596
+ if s.sy in ('NEWLINE', 'EOF'):
3597
+ break
3598
+ p_c_enum_item(s, ctx, items)
3599
+ else:
3600
+ s.next()
3601
+ s.expect_newline("Syntax error in enum item list")
3602
+
3603
+
3604
+ @cython.cfunc
3605
+ def p_c_enum_item(s: PyrexScanner, ctx, items: list):
3606
+ pos = s.position()
3607
+ name = p_ident(s)
3608
+ cname = p_opt_cname(s)
3609
+ if cname is None and ctx.namespace is not None:
3610
+ cname = ctx.namespace + "::" + name
3611
+ value = None
3612
+ if s.sy == '=':
3613
+ s.next()
3614
+ value = p_test(s)
3615
+ items.append(Nodes.CEnumDefItemNode(pos,
3616
+ name = name, cname = cname, value = value))
3617
+
3618
+
3619
+ @cython.cfunc
3620
+ def p_c_struct_or_union_definition(s: PyrexScanner, pos, ctx):
3621
+ packed = False
3622
+ if s.systring == 'packed':
3623
+ packed = True
3624
+ s.next()
3625
+ if s.sy != 'IDENT' or s.systring != 'struct':
3626
+ s.expected('struct')
3627
+ # s.sy == ident 'struct' or 'union'
3628
+ kind = s.systring
3629
+ s.next()
3630
+ name = p_ident(s)
3631
+ cname = p_opt_cname(s)
3632
+ if cname is None and ctx.namespace is not None:
3633
+ cname = ctx.namespace + "::" + name
3634
+ attributes = None
3635
+ if s.sy == ':':
3636
+ s.next()
3637
+ attributes = []
3638
+ if s.sy == 'pass':
3639
+ s.next()
3640
+ s.expect_newline("Expected a newline", ignore_semicolon=True)
3641
+ else:
3642
+ s.expect('NEWLINE')
3643
+ s.expect_indent()
3644
+ body_ctx = Ctx(visibility=ctx.visibility)
3645
+ while s.sy != 'DEDENT':
3646
+ if s.sy != 'pass':
3647
+ attributes.append(
3648
+ p_c_func_or_var_declaration(s, s.position(), body_ctx))
3649
+ else:
3650
+ s.next()
3651
+ s.expect_newline("Expected a newline")
3652
+ s.expect_dedent()
3653
+
3654
+ if not attributes and ctx.visibility != "extern":
3655
+ error(pos, "Empty struct or union definition not allowed outside a 'cdef extern from' block")
3656
+ else:
3657
+ s.expect_newline("Syntax error in struct or union definition")
3658
+
3659
+ return Nodes.CStructOrUnionDefNode(pos,
3660
+ name = name, cname = cname, kind = kind, attributes = attributes,
3661
+ typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
3662
+ api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
3663
+
3664
+
3665
+ @cython.cfunc
3666
+ def p_fused_definition(s: PyrexScanner, pos, ctx):
3667
+ """
3668
+ c(type)def fused my_fused_type:
3669
+ ...
3670
+ """
3671
+ # s.systring == 'fused'
3672
+
3673
+ if ctx.level not in ('module', 'module_pxd'):
3674
+ error(pos, "Fused type definition not allowed here")
3675
+
3676
+ s.next()
3677
+ name = p_ident(s)
3678
+
3679
+ s.expect(":")
3680
+ s.expect_newline()
3681
+ s.expect_indent()
3682
+
3683
+ types = []
3684
+ while s.sy != 'DEDENT':
3685
+ if s.sy != 'pass':
3686
+ #types.append(p_c_declarator(s))
3687
+ types.append(p_c_base_type(s)) #, nonempty=1))
3688
+ else:
3689
+ s.next()
3690
+
3691
+ s.expect_newline()
3692
+
3693
+ s.expect_dedent()
3694
+
3695
+ if not types:
3696
+ error(pos, "Need at least one type")
3697
+
3698
+ return Nodes.FusedTypeNode(pos, name=name, types=types)
3699
+
3700
+
3701
+ @cython.cfunc
3702
+ def p_struct_enum(s: PyrexScanner, pos, ctx):
3703
+ if s.systring == 'enum':
3704
+ return p_c_enum_definition(s, pos, ctx)
3705
+ else:
3706
+ return p_c_struct_or_union_definition(s, pos, ctx)
3707
+
3708
+
3709
+ @cython.cfunc
3710
+ def p_visibility(s: PyrexScanner, prev_visibility):
3711
+ visibility = prev_visibility
3712
+ if s.sy == 'IDENT' and s.systring in ('extern', 'public', 'readonly'):
3713
+ visibility = s.systring
3714
+ if prev_visibility != 'private' and visibility != prev_visibility:
3715
+ s.error("Conflicting visibility options '%s' and '%s'"
3716
+ % (prev_visibility, visibility), fatal=False)
3717
+ s.next()
3718
+ return visibility
3719
+
3720
+
3721
+ @cython.cfunc
3722
+ def p_c_modifiers(s: PyrexScanner) -> list:
3723
+ if s.sy == 'IDENT' and s.systring in ('inline',):
3724
+ modifier = s.systring
3725
+ s.next()
3726
+ return [modifier] + p_c_modifiers(s)
3727
+ return []
3728
+
3729
+
3730
+ @cython.cfunc
3731
+ def p_c_func_or_var_declaration(s: PyrexScanner, pos, ctx):
3732
+ cmethod_flag: cython.bint = ctx.level in ('c_class', 'c_class_pxd')
3733
+ modifiers = p_c_modifiers(s)
3734
+ base_type = p_c_base_type(s, nonempty=True, templates = ctx.templates)
3735
+ declarator = p_c_declarator(s, ctx(modifiers=modifiers), cmethod_flag = cmethod_flag,
3736
+ assignable=True, nonempty =True)
3737
+ declarator.overridable = ctx.overridable
3738
+
3739
+ if s.sy == 'IDENT' and s.systring == 'const' and ctx.level == 'cpp_class':
3740
+ s.next()
3741
+ is_const_method = True
3742
+ else:
3743
+ is_const_method = False
3744
+
3745
+ if s.sy == '->':
3746
+ # Special enough to give a better error message and keep going.
3747
+ s.error(
3748
+ "Return type annotation is not allowed in cdef/cpdef signatures. "
3749
+ "Please define it before the function name, as in C signatures.",
3750
+ fatal=False)
3751
+ s.next()
3752
+ p_test(s) # Keep going, but ignore result.
3753
+
3754
+ if s.sy == ':':
3755
+ if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class') and not ctx.templates:
3756
+ s.error("C function definition not allowed here")
3757
+ doc, suite = p_suite_with_docstring(s, Ctx(level='function'))
3758
+ result = Nodes.CFuncDefNode(pos,
3759
+ visibility = ctx.visibility,
3760
+ base_type = base_type,
3761
+ declarator = declarator,
3762
+ body = suite,
3763
+ doc = doc,
3764
+ modifiers = modifiers,
3765
+ api = ctx.api,
3766
+ overridable = ctx.overridable,
3767
+ is_const_method = is_const_method)
3768
+ else:
3769
+ #if api:
3770
+ # s.error("'api' not allowed with variable declaration")
3771
+ if is_const_method:
3772
+ declarator.is_const_method = is_const_method
3773
+ declarators = [declarator]
3774
+ while s.sy == ',':
3775
+ s.next()
3776
+ if s.sy == 'NEWLINE':
3777
+ break
3778
+ declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag,
3779
+ assignable=True, nonempty=True)
3780
+ declarators.append(declarator)
3781
+ doc_line = s.start_line + 1
3782
+ s.expect_newline("Syntax error in C variable declaration", ignore_semicolon=True)
3783
+ if ctx.level in ('c_class', 'c_class_pxd') and s.start_line == doc_line:
3784
+ doc = p_doc_string(s)
3785
+ else:
3786
+ doc = None
3787
+ result = Nodes.CVarDefNode(pos,
3788
+ visibility = ctx.visibility,
3789
+ base_type = base_type,
3790
+ declarators = declarators,
3791
+ in_pxd = ctx.level in ('module_pxd', 'c_class_pxd'),
3792
+ doc = doc,
3793
+ api = ctx.api,
3794
+ modifiers = modifiers,
3795
+ overridable = ctx.overridable)
3796
+ return result
3797
+
3798
+
3799
+ @cython.cfunc
3800
+ def p_ctypedef_statement(s: PyrexScanner, ctx):
3801
+ # s.sy == 'ctypedef'
3802
+ pos = s.position()
3803
+ s.next()
3804
+ visibility = p_visibility(s, ctx.visibility)
3805
+ api = p_api(s)
3806
+ ctx = ctx(typedef_flag=True, visibility = visibility)
3807
+ if api:
3808
+ ctx.api = True
3809
+ if s.sy == 'class':
3810
+ return p_c_class_definition(s, pos, ctx)
3811
+ elif s.sy == 'IDENT' and s.systring in struct_enum_union:
3812
+ return p_struct_enum(s, pos, ctx)
3813
+ elif s.sy == 'IDENT' and s.systring == 'fused':
3814
+ return p_fused_definition(s, pos, ctx)
3815
+ else:
3816
+ base_type = p_c_base_type(s, nonempty=True)
3817
+ declarator = p_c_declarator(s, ctx, is_type=True, nonempty=True)
3818
+ s.expect_newline("Syntax error in ctypedef statement", ignore_semicolon=True)
3819
+ return Nodes.CTypeDefNode(
3820
+ pos, base_type = base_type,
3821
+ declarator = declarator,
3822
+ visibility = visibility, api = api,
3823
+ in_pxd = ctx.level == 'module_pxd')
3824
+
3825
+
3826
+ @cython.cfunc
3827
+ def p_decorators(s: PyrexScanner) -> list:
3828
+ decorators = []
3829
+ while s.sy == '@':
3830
+ pos = s.position()
3831
+ s.next()
3832
+ decorator = p_namedexpr_test(s)
3833
+ decorators.append(Nodes.DecoratorNode(pos, decorator=decorator))
3834
+ s.expect_newline("Expected a newline after decorator")
3835
+ return decorators
3836
+
3837
+
3838
+ @cython.cfunc
3839
+ def _reject_cdef_modifier_in_py(s: PyrexScanner, name):
3840
+ """Step over incorrectly placed cdef modifiers (@see _CDEF_MODIFIERS) to provide a good error message for them.
3841
+ """
3842
+ if s.sy == 'IDENT' and name in _CDEF_MODIFIERS:
3843
+ # Special enough to provide a good error message.
3844
+ s.error("Cannot use cdef modifier '%s' in Python function signature. Use a decorator instead." % name, fatal=False)
3845
+ return p_ident(s) # Keep going, in case there are other errors.
3846
+ return name
3847
+
3848
+
3849
+ @cython.cfunc
3850
+ def p_def_statement(s: PyrexScanner, decorators: list = None, is_async_def: cython.bint = False):
3851
+ # s.sy == 'def'
3852
+ pos = decorators[0].pos if decorators else s.position()
3853
+ # PEP 492 switches the async/await keywords on in "async def" functions
3854
+ if is_async_def:
3855
+ s.enter_async()
3856
+ s.next()
3857
+ name = _reject_cdef_modifier_in_py(s, p_ident(s))
3858
+ s.expect(
3859
+ '(',
3860
+ "Expected '(', found '%s'. Did you use cdef syntax in a Python declaration? "
3861
+ "Use decorators and Python type annotations instead." % (
3862
+ s.systring if s.sy == 'IDENT' else s.sy))
3863
+ args, star_arg, starstar_arg = p_varargslist(s, terminator=')')
3864
+ s.expect(')')
3865
+ _reject_cdef_modifier_in_py(s, s.systring)
3866
+ return_type_annotation = None
3867
+ if s.sy == '->':
3868
+ s.next()
3869
+ return_type_annotation = p_annotation(s)
3870
+ _reject_cdef_modifier_in_py(s, s.systring)
3871
+
3872
+ doc, body = p_suite_with_docstring(s, Ctx(level='function'))
3873
+ if is_async_def:
3874
+ s.exit_async()
3875
+
3876
+ return Nodes.DefNode(
3877
+ pos, name=name, args=args, star_arg=star_arg, starstar_arg=starstar_arg,
3878
+ doc=doc, body=body, decorators=decorators, is_async_def=is_async_def,
3879
+ return_type_annotation=return_type_annotation)
3880
+
3881
+
3882
+ @cython.cfunc
3883
+ def p_varargslist(s: PyrexScanner, terminator: cython.Py_UCS4 = ')', annotated: cython.bint = True) -> tuple:
3884
+ args = p_c_arg_list(s, in_pyfunc=True, nonempty_declarators=True,
3885
+ annotated = annotated)
3886
+ star_arg = None
3887
+ starstar_arg = None
3888
+ if s.sy == '/':
3889
+ if len(args) == 0:
3890
+ s.error("Got zero positional-only arguments despite presence of "
3891
+ "positional-only specifier '/'")
3892
+ s.next()
3893
+ # Mark all args to the left as pos only
3894
+ for arg in args:
3895
+ arg.pos_only = 1
3896
+ if s.sy == ',':
3897
+ s.next()
3898
+ args.extend(p_c_arg_list(
3899
+ s, in_pyfunc=True, nonempty_declarators=True, annotated = annotated))
3900
+ elif s.sy != terminator:
3901
+ s.error("Syntax error in Python function argument list")
3902
+ if s.sy == '*':
3903
+ s.next()
3904
+ if s.sy == 'IDENT':
3905
+ star_arg = p_py_arg_decl(s, annotated=annotated)
3906
+ if s.sy == ',':
3907
+ s.next()
3908
+ args.extend(p_c_arg_list(
3909
+ s, in_pyfunc =True, nonempty_declarators=True, kw_only=True, annotated = annotated))
3910
+ elif s.sy != terminator:
3911
+ s.error("Syntax error in Python function argument list")
3912
+ if s.sy == '**':
3913
+ s.next()
3914
+ starstar_arg = p_py_arg_decl(s, annotated=annotated)
3915
+ if s.sy == ',':
3916
+ s.next()
3917
+ return (args, star_arg, starstar_arg)
3918
+
3919
+
3920
+ @cython.cfunc
3921
+ def p_py_arg_decl(s: PyrexScanner, annotated: cython.bint = True):
3922
+ pos = s.position()
3923
+ name = p_ident(s)
3924
+ annotation = None
3925
+ if annotated and s.sy == ':':
3926
+ s.next()
3927
+ annotation = p_annotation(s)
3928
+ return Nodes.PyArgDeclNode(pos, name = name, annotation = annotation)
3929
+
3930
+
3931
+ @cython.cfunc
3932
+ def p_class_statement(s: PyrexScanner, decorators):
3933
+ # s.sy == 'class'
3934
+ pos = s.position()
3935
+ s.next()
3936
+ class_name = EncodedString(p_ident(s))
3937
+ class_name.encoding = s.source_encoding # FIXME: why is this needed?
3938
+ arg_tuple = None
3939
+ keyword_dict = None
3940
+ if s.sy == '(':
3941
+ positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False)
3942
+ arg_tuple, keyword_dict = p_call_build_packed_args(pos, positional_args, keyword_args)
3943
+ if arg_tuple is None:
3944
+ # XXX: empty arg_tuple
3945
+ arg_tuple = ExprNodes.TupleNode(pos, args=[])
3946
+ doc, body = p_suite_with_docstring(s, Ctx(level='class'))
3947
+ return Nodes.PyClassDefNode(
3948
+ pos, name=class_name,
3949
+ bases=arg_tuple,
3950
+ keyword_args=keyword_dict,
3951
+ doc=doc, body=body, decorators=decorators,
3952
+ force_py3_semantics=s.context.language_level >= 3)
3953
+
3954
+
3955
+ @cython.cfunc
3956
+ def p_c_class_definition(s: PyrexScanner, pos, ctx):
3957
+ # s.sy == 'class'
3958
+ s.next()
3959
+ module_path = []
3960
+ class_name = p_ident(s)
3961
+ while s.sy == '.':
3962
+ s.next()
3963
+ module_path.append(class_name)
3964
+ class_name = p_ident(s)
3965
+ if module_path and ctx.visibility != 'extern':
3966
+ error(pos, "Qualified class name only allowed for 'extern' C class")
3967
+ if module_path and s.sy == 'IDENT' and s.systring == 'as':
3968
+ s.next()
3969
+ as_name = p_ident(s)
3970
+ else:
3971
+ as_name = class_name
3972
+ objstruct_name = None
3973
+ typeobj_name = None
3974
+ bases = None
3975
+ check_size = None
3976
+ if s.sy == '(':
3977
+ positional_args, keyword_args = p_call_parse_args(s, allow_genexp=False)
3978
+ if keyword_args:
3979
+ s.error("C classes cannot take keyword bases.")
3980
+ bases, _ = p_call_build_packed_args(pos, positional_args, keyword_args)
3981
+ if bases is None:
3982
+ bases = ExprNodes.TupleNode(pos, args=[])
3983
+
3984
+ if s.sy == '[':
3985
+ if ctx.visibility not in ('public', 'extern') and not ctx.api:
3986
+ error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
3987
+ objstruct_name, typeobj_name, check_size = p_c_class_options(s)
3988
+ if s.sy == ':':
3989
+ if ctx.level == 'module_pxd':
3990
+ body_level = 'c_class_pxd'
3991
+ else:
3992
+ body_level = 'c_class'
3993
+ doc, body = p_suite_with_docstring(s, Ctx(level=body_level))
3994
+ else:
3995
+ s.expect_newline("Syntax error in C class definition")
3996
+ doc = None
3997
+ body = None
3998
+ if ctx.visibility == 'extern':
3999
+ if not module_path:
4000
+ error(pos, "Module name required for 'extern' C class")
4001
+ if typeobj_name:
4002
+ error(pos, "Type object name specification not allowed for 'extern' C class")
4003
+ elif ctx.visibility == 'public':
4004
+ if not objstruct_name:
4005
+ error(pos, "Object struct name specification required for 'public' C class")
4006
+ if not typeobj_name:
4007
+ error(pos, "Type object name specification required for 'public' C class")
4008
+ elif ctx.visibility == 'private':
4009
+ if ctx.api:
4010
+ if not objstruct_name:
4011
+ error(pos, "Object struct name specification required for 'api' C class")
4012
+ if not typeobj_name:
4013
+ error(pos, "Type object name specification required for 'api' C class")
4014
+ else:
4015
+ error(pos, "Invalid class visibility '%s'" % ctx.visibility)
4016
+ return Nodes.CClassDefNode(pos,
4017
+ visibility = ctx.visibility,
4018
+ typedef_flag = ctx.typedef_flag,
4019
+ api = ctx.api,
4020
+ module_name = ".".join(module_path),
4021
+ class_name = class_name,
4022
+ as_name = as_name,
4023
+ bases = bases,
4024
+ objstruct_name = objstruct_name,
4025
+ typeobj_name = typeobj_name,
4026
+ check_size = check_size,
4027
+ in_pxd = ctx.level == 'module_pxd',
4028
+ doc = doc,
4029
+ body = body)
4030
+
4031
+
4032
+ @cython.cfunc
4033
+ def p_c_class_options(s: PyrexScanner) -> tuple:
4034
+ objstruct_name = None
4035
+ typeobj_name = None
4036
+ check_size = None
4037
+ s.expect('[')
4038
+ while 1:
4039
+ if s.sy != 'IDENT':
4040
+ break
4041
+ if s.systring == 'object':
4042
+ s.next()
4043
+ objstruct_name = p_ident(s)
4044
+ elif s.systring == 'type':
4045
+ s.next()
4046
+ typeobj_name = p_ident(s)
4047
+ elif s.systring == 'check_size':
4048
+ s.next()
4049
+ check_size = p_ident(s)
4050
+ if check_size not in ('ignore', 'warn', 'error'):
4051
+ s.error("Expected one of ignore, warn or error, found %r" % check_size)
4052
+ if s.sy != ',':
4053
+ break
4054
+ s.next()
4055
+ s.expect(']', "Expected 'object', 'type' or 'check_size'")
4056
+ return objstruct_name, typeobj_name, check_size
4057
+
4058
+
4059
+ @cython.cfunc
4060
+ def p_property_decl(s: PyrexScanner):
4061
+ pos = s.position()
4062
+ s.next() # 'property'
4063
+ name = p_ident(s)
4064
+ doc, body = p_suite_with_docstring(
4065
+ s, Ctx(level='property'), with_doc_only=True)
4066
+ return Nodes.PropertyNode(pos, name=name, doc=doc, body=body)
4067
+
4068
+
4069
+ @cython.cfunc
4070
+ def p_ignorable_statement(s: PyrexScanner):
4071
+ """
4072
+ Parses any kind of ignorable statement that is allowed in .pxd files.
4073
+ """
4074
+ if s.sy == 'BEGIN_STRING':
4075
+ pos = s.position()
4076
+ string_node = p_atom(s)
4077
+ s.expect_newline("Syntax error in string", ignore_semicolon=True)
4078
+ return Nodes.ExprStatNode(pos, expr=string_node)
4079
+ return None
4080
+
4081
+
4082
+ @cython.cfunc
4083
+ def p_doc_string(s: PyrexScanner):
4084
+ if s.sy == 'BEGIN_STRING':
4085
+ pos = s.position()
4086
+ kind, bytes_result, unicode_result = p_cat_string_literal(s)
4087
+ s.expect_newline("Syntax error in doc string", ignore_semicolon=True)
4088
+ if kind in ('u', ''):
4089
+ return unicode_result
4090
+ warning(pos, "Python 3 requires docstrings to be unicode strings")
4091
+ return bytes_result
4092
+ else:
4093
+ return None
4094
+
4095
+
4096
+ @cython.cfunc
4097
+ def _extract_docstring(node) -> tuple:
4098
+ """
4099
+ Extract a docstring from a statement or from the first statement
4100
+ in a list. Remove the statement if found. Return a tuple
4101
+ (plain-docstring or None, node).
4102
+ """
4103
+ doc_node = None
4104
+ if node is None:
4105
+ pass
4106
+ elif isinstance(node, Nodes.ExprStatNode):
4107
+ if node.expr.is_string_literal:
4108
+ doc_node = node.expr
4109
+ node = Nodes.StatListNode(node.pos, stats=[])
4110
+ elif isinstance(node, Nodes.StatListNode) and node.stats:
4111
+ stats = node.stats
4112
+ if isinstance(stats[0], Nodes.ExprStatNode):
4113
+ if stats[0].expr.is_string_literal:
4114
+ doc_node = stats[0].expr
4115
+ del stats[0]
4116
+
4117
+ if doc_node is None:
4118
+ doc = None
4119
+ elif isinstance(doc_node, ExprNodes.BytesNode):
4120
+ warning(node.pos,
4121
+ "Python 3 requires docstrings to be unicode strings")
4122
+ doc = doc_node.value
4123
+ else:
4124
+ doc = doc_node.value
4125
+ return doc, node
4126
+
4127
+
4128
+ @cython.ccall
4129
+ def p_code(s: PyrexScanner, level=None, ctx=Ctx):
4130
+ body = p_statement_list(s, ctx(level = level), first_statement=True)
4131
+ if s.sy != 'EOF':
4132
+ s.error("Syntax error in statement [%s,%s]" % (
4133
+ repr(s.sy), repr(s.systring)))
4134
+ return body
4135
+
4136
+
4137
+ _match_compiler_directive_comment = cython.declare(object, re.compile(
4138
+ r"^#\s*cython\s*:\s*((\w|[.])+\s*=.*)$").match)
4139
+
4140
+
4141
+ @cython.cfunc
4142
+ def p_compiler_directive_comments(s: PyrexScanner) -> dict:
4143
+ result = {}
4144
+ while s.sy == 'commentline':
4145
+ pos = s.position()
4146
+ m = _match_compiler_directive_comment(s.systring)
4147
+ if m:
4148
+ directives_string = m.group(1).strip()
4149
+ try:
4150
+ new_directives = Options.parse_directive_list(directives_string, ignore_unknown=True)
4151
+ except ValueError as e:
4152
+ s.error(e.args[0], fatal=False)
4153
+ s.next()
4154
+ continue
4155
+
4156
+ for name in new_directives:
4157
+ if name not in result:
4158
+ pass
4159
+ elif Options.directive_types.get(name) is list:
4160
+ result[name] += new_directives[name]
4161
+ new_directives[name] = result[name]
4162
+ elif new_directives[name] == result[name]:
4163
+ warning(pos, "Duplicate directive found: %s" % (name,))
4164
+ else:
4165
+ s.error("Conflicting settings found for top-level directive %s: %r and %r" % (
4166
+ name, result[name], new_directives[name]), pos=pos)
4167
+
4168
+ if 'language_level' in new_directives:
4169
+ # Make sure we apply the language level already to the first token that follows the comments.
4170
+ s.context.set_language_level(new_directives['language_level'])
4171
+ if 'legacy_implicit_noexcept' in new_directives:
4172
+ s.context.legacy_implicit_noexcept = new_directives['legacy_implicit_noexcept']
4173
+
4174
+
4175
+ result.update(new_directives)
4176
+
4177
+ s.next()
4178
+ return result
4179
+
4180
+
4181
+ @cython.ccall
4182
+ def p_module(s: PyrexScanner, pxd, full_module_name, ctx=Ctx):
4183
+ pos = s.position()
4184
+
4185
+ directive_comments = p_compiler_directive_comments(s)
4186
+ s.parse_comments = False
4187
+
4188
+ if s.context.language_level is None:
4189
+ s.context.set_language_level('3')
4190
+
4191
+ level = 'module_pxd' if pxd else 'module'
4192
+ doc = p_doc_string(s)
4193
+ body = p_statement_list(s, ctx(level=level), first_statement=True)
4194
+ if s.sy != 'EOF':
4195
+ s.error("Syntax error in statement [%s,%s]" % (
4196
+ repr(s.sy), repr(s.systring)))
4197
+ return ModuleNode(pos, doc = doc, body = body,
4198
+ full_module_name = full_module_name,
4199
+ directive_comments = directive_comments)
4200
+
4201
+
4202
+ @cython.cfunc
4203
+ def p_template_definition(s: PyrexScanner) -> tuple:
4204
+ name = p_ident(s)
4205
+ if s.sy == '=':
4206
+ s.expect('=')
4207
+ s.expect('*')
4208
+ required = False
4209
+ else:
4210
+ required = True
4211
+ return name, required
4212
+
4213
+
4214
+ @cython.cfunc
4215
+ def p_cpp_class_definition(s: PyrexScanner, pos, ctx):
4216
+ # s.sy == 'cppclass'
4217
+ s.next()
4218
+ class_name = p_ident(s)
4219
+ cname = p_opt_cname(s)
4220
+ if cname is None and ctx.namespace is not None:
4221
+ cname = ctx.namespace + "::" + class_name
4222
+ if s.sy == '.':
4223
+ error(pos, "Qualified class name not allowed C++ class")
4224
+ if s.sy == '[':
4225
+ s.next()
4226
+ templates = [p_template_definition(s)]
4227
+ while s.sy == ',':
4228
+ s.next()
4229
+ templates.append(p_template_definition(s))
4230
+ s.expect(']')
4231
+ template_names = [name for name, required in templates]
4232
+ else:
4233
+ templates = None
4234
+ template_names = None
4235
+ if s.sy == '(':
4236
+ s.next()
4237
+ base_classes = [p_c_base_type(s, templates = template_names)]
4238
+ while s.sy == ',':
4239
+ s.next()
4240
+ base_classes.append(p_c_base_type(s, templates = template_names))
4241
+ s.expect(')')
4242
+ else:
4243
+ base_classes = []
4244
+ if s.sy == '[':
4245
+ error(s.position(), "Name options not allowed for C++ class")
4246
+ nogil = p_nogil(s)
4247
+ if s.sy == ':':
4248
+ s.next()
4249
+ s.expect('NEWLINE')
4250
+ s.expect_indent()
4251
+ # Allow a cppclass to have docstrings. It will be discarded as comment.
4252
+ # The goal of this is consistency: we can make docstrings inside cppclass methods,
4253
+ # so why not on the cppclass itself ?
4254
+ p_doc_string(s)
4255
+ attributes = []
4256
+ body_ctx = Ctx(visibility = ctx.visibility, level='cpp_class', nogil=nogil or ctx.nogil)
4257
+ body_ctx.templates = template_names
4258
+ while s.sy != 'DEDENT':
4259
+ if s.sy != 'pass':
4260
+ attributes.append(p_cpp_class_attribute(s, body_ctx))
4261
+ else:
4262
+ s.next()
4263
+ s.expect_newline("Expected a newline")
4264
+ s.expect_dedent()
4265
+ else:
4266
+ attributes = None
4267
+ s.expect_newline("Syntax error in C++ class definition")
4268
+ return Nodes.CppClassNode(pos,
4269
+ name = class_name,
4270
+ cname = cname,
4271
+ base_classes = base_classes,
4272
+ visibility = ctx.visibility,
4273
+ in_pxd = ctx.level == 'module_pxd',
4274
+ attributes = attributes,
4275
+ templates = templates)
4276
+
4277
+
4278
+ @cython.cfunc
4279
+ def p_cpp_class_attribute(s: PyrexScanner, ctx):
4280
+ pos = s.position()
4281
+ decorators = None
4282
+ if s.sy == '@':
4283
+ decorators = p_decorators(s)
4284
+ if s.systring == 'cppclass':
4285
+ return p_cpp_class_definition(s, pos, ctx)
4286
+ elif s.systring == 'ctypedef':
4287
+ return p_ctypedef_statement(s, ctx)
4288
+ elif s.sy == 'IDENT' and s.systring in struct_enum_union:
4289
+ if s.systring != 'enum':
4290
+ return p_cpp_class_definition(s, pos, ctx)
4291
+ else:
4292
+ return p_struct_enum(s, pos, ctx)
4293
+ else:
4294
+ node = p_c_func_or_var_declaration(s, pos, ctx)
4295
+ if decorators is not None:
4296
+ tup = Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode
4297
+ if ctx.allow_struct_enum_decorator:
4298
+ tup += Nodes.CStructOrUnionDefNode, Nodes.CEnumDefNode
4299
+ if not isinstance(node, tup):
4300
+ s.error("Decorators can only be followed by functions or classes")
4301
+ node.decorators = decorators
4302
+ return node
4303
+
4304
+
4305
+ @cython.cfunc
4306
+ def p_match_statement(s: PyrexScanner, ctx):
4307
+ assert s.sy == "IDENT" and s.systring == "match"
4308
+ pos = s.position()
4309
+ with tentatively_scan(s) as errors:
4310
+ s.next()
4311
+ subject = p_namedexpr_test(s)
4312
+ subjects = None
4313
+ if s.sy == ",":
4314
+ subjects = [subject]
4315
+ while s.sy == ",":
4316
+ s.next()
4317
+ if s.sy == ":":
4318
+ break
4319
+ subjects.append(p_test(s))
4320
+ if subjects is not None:
4321
+ subject = ExprNodes.TupleNode(pos, args=subjects)
4322
+ s.expect(":")
4323
+ if errors:
4324
+ return None
4325
+
4326
+ # at this stage we are committed to it being a match block so continue
4327
+ # outside "with tentatively_scan"
4328
+ # (I think this deviates from the PEG parser slightly, and it'd
4329
+ # backtrack on the whole thing)
4330
+ s.expect_newline()
4331
+ s.expect_indent()
4332
+ cases = []
4333
+ while s.sy != "DEDENT":
4334
+ cases.append(p_case_block(s, ctx))
4335
+ s.expect_dedent()
4336
+ return MatchCaseNodes.MatchNode(pos, subject=subject, cases=cases)
4337
+
4338
+
4339
+ @cython.cfunc
4340
+ def p_case_block(s: PyrexScanner, ctx):
4341
+ if not (s.sy == "IDENT" and s.systring == "case"):
4342
+ s.expected("case")
4343
+ s.next()
4344
+ pos = s.position()
4345
+ pattern = p_patterns(s)
4346
+ guard = None
4347
+ if s.sy == 'if':
4348
+ s.next()
4349
+ guard = p_test(s)
4350
+ body = p_suite(s, ctx)
4351
+
4352
+ return MatchCaseNodes.MatchCaseNode(pos, pattern=pattern, body=body, guard=guard)
4353
+
4354
+
4355
+ @cython.cfunc
4356
+ def p_patterns(s: PyrexScanner):
4357
+ # note - in slight contrast to the name (which comes from the Python grammar),
4358
+ # returns a single pattern
4359
+ patterns = []
4360
+ seq = False
4361
+ pos = s.position()
4362
+ while True:
4363
+ with tentatively_scan(s) as errors:
4364
+ pattern = p_maybe_star_pattern(s)
4365
+ if errors:
4366
+ if patterns:
4367
+ break # all is good provided we have at least 1 pattern
4368
+ else:
4369
+ e = errors[0]
4370
+ s.error(e.args[1], pos=e.args[0])
4371
+ patterns.append(pattern)
4372
+
4373
+ if s.sy == ",":
4374
+ seq = True
4375
+ s.next()
4376
+ if s.sy in [":", "if"]:
4377
+ break # common reasons to break
4378
+ else:
4379
+ break
4380
+
4381
+ if seq:
4382
+ return MatchCaseNodes.MatchSequencePatternNode(pos, patterns=patterns)
4383
+ else:
4384
+ return patterns[0]
4385
+
4386
+
4387
+ @cython.cfunc
4388
+ def p_maybe_star_pattern(s: PyrexScanner):
4389
+ # For match case. Either star_pattern or pattern
4390
+ if s.sy == "*":
4391
+ # star pattern
4392
+ s.next()
4393
+ target = None
4394
+ if s.systring != "_": # for match-case '_' is treated as a special wildcard
4395
+ target = p_pattern_capture_target(s)
4396
+ else:
4397
+ s.next()
4398
+ pattern = MatchCaseNodes.MatchAndAssignPatternNode(
4399
+ s.position(), target=target, is_star=True
4400
+ )
4401
+ return pattern
4402
+ else:
4403
+ pattern = p_pattern(s)
4404
+ return pattern
4405
+
4406
+
4407
+ @cython.cfunc
4408
+ def p_pattern(s: PyrexScanner):
4409
+ # try "as_pattern" then "or_pattern"
4410
+ # (but practically "as_pattern" starts with "or_pattern" too)
4411
+ patterns = []
4412
+ pos = s.position()
4413
+ while True:
4414
+ patterns.append(p_closed_pattern(s))
4415
+ if s.sy != "|":
4416
+ break
4417
+ s.next()
4418
+
4419
+ if len(patterns) > 1:
4420
+ pattern = MatchCaseNodes.OrPatternNode(
4421
+ pos,
4422
+ alternatives=patterns
4423
+ )
4424
+ else:
4425
+ pattern = patterns[0]
4426
+
4427
+ if s.sy == 'IDENT' and s.systring == 'as':
4428
+ s.next()
4429
+ with tentatively_scan(s) as errors:
4430
+ pattern.as_targets.append(p_pattern_capture_target(s))
4431
+ if errors and s.sy == "_":
4432
+ s.next()
4433
+ # make this a specific error
4434
+ return Nodes.ErrorNode(errors[0].args[0], what=errors[0].args[1])
4435
+ elif errors:
4436
+ with tentatively_scan(s):
4437
+ expr = p_test(s)
4438
+ return Nodes.ErrorNode(expr.pos, what="Invalid pattern target")
4439
+ s.error(errors[0])
4440
+ return pattern
4441
+
4442
+
4443
+ @cython.cfunc
4444
+ def p_closed_pattern(s: PyrexScanner):
4445
+ """
4446
+ The PEG parser specifies it as
4447
+ | literal_pattern
4448
+ | capture_pattern
4449
+ | wildcard_pattern
4450
+ | value_pattern
4451
+ | group_pattern
4452
+ | sequence_pattern
4453
+ | mapping_pattern
4454
+ | class_pattern
4455
+
4456
+ For the sake avoiding too much backtracking, we know:
4457
+ * starts with "{" is a sequence_pattern
4458
+ * starts with "[" is a mapping_pattern
4459
+ * starts with "(" is a group_pattern or sequence_pattern
4460
+ * wildcard pattern is just identifier=='_'
4461
+ The rest are then tried in order with backtracking
4462
+ """
4463
+ if s.sy == 'IDENT' and s.systring == '_':
4464
+ pos = s.position()
4465
+ s.next()
4466
+ return MatchCaseNodes.MatchAndAssignPatternNode(pos)
4467
+ elif s.sy == '{':
4468
+ return p_mapping_pattern(s)
4469
+ elif s.sy == '[':
4470
+ return p_sequence_pattern(s)
4471
+ elif s.sy == '(':
4472
+ with tentatively_scan(s) as errors:
4473
+ result = p_group_pattern(s)
4474
+ if not errors:
4475
+ return result
4476
+ return p_sequence_pattern(s)
4477
+
4478
+ with tentatively_scan(s) as errors:
4479
+ result = p_literal_pattern(s)
4480
+ if not errors:
4481
+ return result
4482
+ with tentatively_scan(s) as errors:
4483
+ result = p_capture_pattern(s)
4484
+ if not errors:
4485
+ return result
4486
+ with tentatively_scan(s) as errors:
4487
+ result = p_value_pattern(s)
4488
+ if not errors:
4489
+ return result
4490
+ return p_class_pattern(s)
4491
+
4492
+
4493
+ @cython.cfunc
4494
+ def p_literal_pattern(s: PyrexScanner):
4495
+ # a lot of duplication in this function with "p_atom"
4496
+ next_must_be_a_number = False
4497
+ sign = ''
4498
+ if s.sy == '-':
4499
+ sign = s.sy
4500
+ sign_pos = s.position()
4501
+ s.next()
4502
+ next_must_be_a_number = True
4503
+
4504
+ sy = s.sy
4505
+ pos = s.position()
4506
+
4507
+ res = None
4508
+ if sy == 'INT':
4509
+ res = p_int_literal(s)
4510
+ elif sy == 'FLOAT':
4511
+ value = s.systring
4512
+ s.next()
4513
+ res = ExprNodes.FloatNode(pos, value=value)
4514
+
4515
+ if res is not None and sign == "-":
4516
+ res = ExprNodes.UnaryMinusNode(sign_pos, operand=res)
4517
+
4518
+ if res is not None and s.sy in ['+', '-']:
4519
+ sign = s.sy
4520
+ s.next()
4521
+ if s.sy != 'IMAG':
4522
+ s.error("Expected imaginary number")
4523
+ else:
4524
+ add_pos = s.position()
4525
+ value = s.systring[:-1]
4526
+ s.next()
4527
+ res = ExprNodes.binop_node(
4528
+ add_pos,
4529
+ sign,
4530
+ operand1=res,
4531
+ operand2=ExprNodes.ImagNode(s.position(), value=value)
4532
+ )
4533
+
4534
+ if res is None and sy == 'IMAG':
4535
+ value = s.systring[:-1]
4536
+ s.next()
4537
+ res = ExprNodes.ImagNode(pos, value=sign+value)
4538
+ if sign == "-":
4539
+ res = ExprNodes.UnaryMinusNode(sign_pos, operand=res)
4540
+
4541
+ if res is not None:
4542
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=res)
4543
+
4544
+ if next_must_be_a_number:
4545
+ s.error("Expected a number")
4546
+ if sy == 'BEGIN_STRING':
4547
+ res = p_atom_string(s)
4548
+ # Whether f-strings are suitable is validated in PostParse.
4549
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=res)
4550
+ elif sy == 'IDENT':
4551
+ # Note that p_atom_ident_constants includes NULL.
4552
+ # This is a deliberate Cython addition to the pattern matching specification
4553
+ result = p_atom_ident_constants(s)
4554
+ if result:
4555
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=result, is_is_check=True)
4556
+
4557
+ s.error("Failed to match literal")
4558
+
4559
+
4560
+ @cython.cfunc
4561
+ def p_capture_pattern(s: PyrexScanner):
4562
+ return MatchCaseNodes.MatchAndAssignPatternNode(
4563
+ s.position(),
4564
+ target=p_pattern_capture_target(s)
4565
+ )
4566
+
4567
+
4568
+ @cython.cfunc
4569
+ def p_value_pattern(s: PyrexScanner):
4570
+ if s.sy != "IDENT":
4571
+ s.error("Expected identifier")
4572
+ pos = s.position()
4573
+ res = p_name(s, s.systring)
4574
+ s.next()
4575
+ if s.sy != '.':
4576
+ s.error(".")
4577
+ while s.sy == '.':
4578
+ attr_pos = s.position()
4579
+ s.next()
4580
+ attr = p_ident(s)
4581
+ res = ExprNodes.AttributeNode(attr_pos, obj=res, attribute=attr)
4582
+ if s.sy in ['(', '=']:
4583
+ s.error("Unexpected symbol '%s'" % s.sy)
4584
+ return MatchCaseNodes.MatchValuePatternNode(pos, value=res)
4585
+
4586
+
4587
+ @cython.cfunc
4588
+ def p_group_pattern(s: PyrexScanner):
4589
+ s.expect("(")
4590
+ pattern = p_pattern(s)
4591
+ s.expect(")")
4592
+ return pattern
4593
+
4594
+
4595
+ @cython.cfunc
4596
+ def p_sequence_pattern(s: PyrexScanner):
4597
+ opener = s.sy
4598
+ pos = s.position()
4599
+ if opener in ['[', '(']:
4600
+ closer = ']' if opener == '[' else ')'
4601
+ s.next()
4602
+ # maybe_sequence_pattern and open_sequence_pattern
4603
+ patterns = []
4604
+ while s.sy != closer:
4605
+ patterns.append(p_maybe_star_pattern(s))
4606
+ if s.sy == ",":
4607
+ s.next()
4608
+ else:
4609
+ if opener == '(' and len(patterns) == 1:
4610
+ s.error("tuple-like pattern of length 1 must finish with ','")
4611
+ break
4612
+ s.expect(closer)
4613
+ return MatchCaseNodes.MatchSequencePatternNode(pos, patterns=patterns)
4614
+ else:
4615
+ s.error("Expected '[' or '('")
4616
+
4617
+
4618
+ @cython.cfunc
4619
+ def p_mapping_pattern(s: PyrexScanner):
4620
+ pos = s.position()
4621
+ s.expect('{')
4622
+ if s.sy == '}':
4623
+ # trivial empty mapping
4624
+ s.next()
4625
+ return MatchCaseNodes.MatchMappingPatternNode(pos)
4626
+
4627
+ double_star_capture_target = None
4628
+ items_patterns = []
4629
+ star_star_arg_pos = None
4630
+ while s.sy != '}':
4631
+ if double_star_capture_target and not star_star_arg_pos:
4632
+ star_star_arg_pos = s.position()
4633
+ if s.sy == '**':
4634
+ s.next()
4635
+ double_star_capture_target = p_pattern_capture_target(s)
4636
+ else:
4637
+ # key=(literal_expr | attr)
4638
+ with tentatively_scan(s) as errors:
4639
+ pattern = p_literal_pattern(s)
4640
+ key = pattern.value
4641
+ if errors:
4642
+ pattern = p_value_pattern(s)
4643
+ key = pattern.value
4644
+ s.expect(':')
4645
+ value = p_pattern(s)
4646
+ items_patterns.append((key, value))
4647
+ if s.sy != ',':
4648
+ break
4649
+ s.next()
4650
+ s.expect('}')
4651
+
4652
+ if star_star_arg_pos is not None:
4653
+ return Nodes.ErrorNode(
4654
+ star_star_arg_pos,
4655
+ what = "** pattern must be the final part of a mapping pattern."
4656
+ )
4657
+ return MatchCaseNodes.MatchMappingPatternNode(
4658
+ pos,
4659
+ keys = [kv[0] for kv in items_patterns],
4660
+ value_patterns = [kv[1] for kv in items_patterns],
4661
+ double_star_capture_target = double_star_capture_target
4662
+ )
4663
+
4664
+
4665
+ @cython.cfunc
4666
+ def p_class_pattern(s: PyrexScanner):
4667
+ # start by parsing the class as name_or_attr
4668
+ pos = s.position()
4669
+ res = p_name(s, s.systring)
4670
+ s.next()
4671
+ while s.sy == '.':
4672
+ attr_pos = s.position()
4673
+ s.next()
4674
+ attr = p_ident(s)
4675
+ res = ExprNodes.AttributeNode(attr_pos, obj=res, attribute=attr)
4676
+ class_ = res
4677
+
4678
+ s.expect("(")
4679
+ if s.sy == ")":
4680
+ # trivial case with no arguments matched
4681
+ s.next()
4682
+ return MatchCaseNodes.ClassPatternNode(pos, class_=class_)
4683
+
4684
+ # parse the arguments
4685
+ positional_patterns = []
4686
+ keyword_patterns = []
4687
+ keyword_patterns_error = None
4688
+ while s.sy != ')':
4689
+ with tentatively_scan(s) as errors:
4690
+ positional_patterns.append(p_pattern(s))
4691
+ if not errors:
4692
+ if keyword_patterns:
4693
+ keyword_patterns_error = s.position()
4694
+ else:
4695
+ with tentatively_scan(s) as errors:
4696
+ keyword_patterns.append(p_keyword_pattern(s))
4697
+ if s.sy != ",":
4698
+ break
4699
+ s.next()
4700
+ s.expect(")")
4701
+
4702
+ if keyword_patterns_error is not None:
4703
+ return Nodes.ErrorNode(
4704
+ keyword_patterns_error,
4705
+ what="Positional patterns follow keyword patterns"
4706
+ )
4707
+ return MatchCaseNodes.ClassPatternNode(
4708
+ pos, class_ = class_,
4709
+ positional_patterns = positional_patterns,
4710
+ keyword_pattern_names = [kv[0] for kv in keyword_patterns],
4711
+ keyword_pattern_patterns = [kv[1] for kv in keyword_patterns],
4712
+ )
4713
+
4714
+
4715
+ @cython.cfunc
4716
+ def p_keyword_pattern(s: PyrexScanner):
4717
+ if s.sy != "IDENT":
4718
+ s.error("Expected identifier")
4719
+ arg = p_name(s, s.systring)
4720
+ s.next()
4721
+ s.expect("=")
4722
+ value = p_pattern(s)
4723
+ return arg, value
4724
+
4725
+
4726
+ @cython.cfunc
4727
+ def p_pattern_capture_target(s: PyrexScanner):
4728
+ # any name but '_', and with some constraints on what follows
4729
+ if s.sy != 'IDENT':
4730
+ s.error("Expected identifier")
4731
+ if s.systring == '_':
4732
+ s.error("Pattern capture target cannot be '_'")
4733
+ target = p_name(s, s.systring)
4734
+ s.next()
4735
+ if s.sy in ['.', '(', '=']:
4736
+ s.error("Illegal next symbol '%s'" % s.sy)
4737
+ return target
4738
+
4739
+
4740
+
4741
+ #----------------------------------------------
4742
+ #
4743
+ # Debugging
4744
+ #
4745
+ #----------------------------------------------
4746
+
4747
+ @cython.ccall
4748
+ def print_parse_tree(f, node, level: cython.long, key = None):
4749
+ ind: str = " " * level
4750
+ f.write(ind)
4751
+ if key:
4752
+ f.write(f"{key}: ")
4753
+ if not node:
4754
+ f.write("None\n")
4755
+ elif type(node) is tuple:
4756
+ f.write(f"({node[0]} @ {node[1]}\n")
4757
+ for item in node[2:]:
4758
+ print_parse_tree(f, item, level+1)
4759
+ f.write(f"{ind})\n")
4760
+ elif isinstance(node, Nodes.Node):
4761
+ try:
4762
+ tag = node.tag
4763
+ except AttributeError:
4764
+ tag = node.__class__.__name__
4765
+ f.write(f"{tag} @ {node.pos}\n")
4766
+ for name, value in sorted(node.__dict__.items()):
4767
+ if name != 'tag' and name != 'pos':
4768
+ print_parse_tree(f, value, level+1, name)
4769
+ elif type(node) is list:
4770
+ f.write("[\n")
4771
+ for item in node:
4772
+ print_parse_tree(f, item, level+1)
4773
+ f.write(f"{ind}]\n")
4774
+ else:
4775
+ f.write(f"{ind}{node}\n")