oxython 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. Cython/Build/BuildExecutable.py +156 -0
  2. Cython/Build/Cache.py +198 -0
  3. Cython/Build/Cythonize.py +349 -0
  4. Cython/Build/Dependencies.py +1320 -0
  5. Cython/Build/Distutils.py +1 -0
  6. Cython/Build/Inline.py +467 -0
  7. Cython/Build/IpythonMagic.py +559 -0
  8. Cython/Build/SharedModule.py +165 -0
  9. Cython/Build/Tests/TestCyCache.py +222 -0
  10. Cython/Build/Tests/TestCythonizeArgsParser.py +480 -0
  11. Cython/Build/Tests/TestDependencies.py +133 -0
  12. Cython/Build/Tests/TestInline.py +177 -0
  13. Cython/Build/Tests/TestIpythonMagic.py +303 -0
  14. Cython/Build/Tests/TestRecythonize.py +212 -0
  15. Cython/Build/Tests/TestStripLiterals.py +155 -0
  16. Cython/Build/Tests/__init__.py +1 -0
  17. Cython/Build/__init__.py +11 -0
  18. Cython/CodeWriter.py +825 -0
  19. Cython/Compiler/AnalysedTreeTransforms.py +97 -0
  20. Cython/Compiler/Annotate.py +328 -0
  21. Cython/Compiler/AutoDocTransforms.py +320 -0
  22. Cython/Compiler/Buffer.py +679 -0
  23. Cython/Compiler/Builtin.py +1102 -0
  24. Cython/Compiler/CmdLine.py +373 -0
  25. Cython/Compiler/Code.pxd +154 -0
  26. Cython/Compiler/Code.py +3760 -0
  27. Cython/Compiler/CodeGeneration.py +33 -0
  28. Cython/Compiler/CythonScope.py +208 -0
  29. Cython/Compiler/Dataclass.py +890 -0
  30. Cython/Compiler/DebugFlags.py +24 -0
  31. Cython/Compiler/Errors.py +310 -0
  32. Cython/Compiler/ExprNodes.py +16319 -0
  33. Cython/Compiler/FlowControl.pxd +112 -0
  34. Cython/Compiler/FlowControl.py +1575 -0
  35. Cython/Compiler/FusedNode.py +978 -0
  36. Cython/Compiler/Future.py +16 -0
  37. Cython/Compiler/Interpreter.py +57 -0
  38. Cython/Compiler/Lexicon.py +442 -0
  39. Cython/Compiler/LineTable.py +114 -0
  40. Cython/Compiler/Main.py +879 -0
  41. Cython/Compiler/MatchCaseNodes.py +2200 -0
  42. Cython/Compiler/MemoryView.py +930 -0
  43. Cython/Compiler/ModuleNode.py +4558 -0
  44. Cython/Compiler/Naming.py +370 -0
  45. Cython/Compiler/Nodes.py +11334 -0
  46. Cython/Compiler/Optimize.py +5563 -0
  47. Cython/Compiler/Options.py +841 -0
  48. Cython/Compiler/ParseTreeTransforms.pxd +80 -0
  49. Cython/Compiler/ParseTreeTransforms.py +4808 -0
  50. Cython/Compiler/Parsing.pxd +9 -0
  51. Cython/Compiler/Parsing.py +5442 -0
  52. Cython/Compiler/Pipeline.py +439 -0
  53. Cython/Compiler/PyrexTypes.py +6588 -0
  54. Cython/Compiler/Pythran.py +232 -0
  55. Cython/Compiler/Scanning.pxd +74 -0
  56. Cython/Compiler/Scanning.py +771 -0
  57. Cython/Compiler/StringEncoding.py +354 -0
  58. Cython/Compiler/Symtab.py +3122 -0
  59. Cython/Compiler/Tests/TestBuffer.py +105 -0
  60. Cython/Compiler/Tests/TestBuiltin.py +196 -0
  61. Cython/Compiler/Tests/TestCmdLine.py +652 -0
  62. Cython/Compiler/Tests/TestCode.py +145 -0
  63. Cython/Compiler/Tests/TestFlowControl.py +65 -0
  64. Cython/Compiler/Tests/TestGrammar.py +202 -0
  65. Cython/Compiler/Tests/TestMemView.py +71 -0
  66. Cython/Compiler/Tests/TestParseTreeTransforms.py +285 -0
  67. Cython/Compiler/Tests/TestScanning.py +132 -0
  68. Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
  69. Cython/Compiler/Tests/TestStringEncoding.py +20 -0
  70. Cython/Compiler/Tests/TestTreeFragment.py +63 -0
  71. Cython/Compiler/Tests/TestTreePath.py +103 -0
  72. Cython/Compiler/Tests/TestTypes.py +119 -0
  73. Cython/Compiler/Tests/TestUtilityLoad.py +112 -0
  74. Cython/Compiler/Tests/TestVisitor.py +119 -0
  75. Cython/Compiler/Tests/Utils.py +36 -0
  76. Cython/Compiler/Tests/__init__.py +1 -0
  77. Cython/Compiler/TreeFragment.py +279 -0
  78. Cython/Compiler/TreePath.py +303 -0
  79. Cython/Compiler/TypeInference.py +626 -0
  80. Cython/Compiler/TypeSlots.py +1330 -0
  81. Cython/Compiler/UFuncs.py +317 -0
  82. Cython/Compiler/UtilNodes.py +389 -0
  83. Cython/Compiler/UtilityCode.py +354 -0
  84. Cython/Compiler/Version.py +8 -0
  85. Cython/Compiler/Visitor.pxd +52 -0
  86. Cython/Compiler/Visitor.py +914 -0
  87. Cython/Compiler/__init__.py +1 -0
  88. Cython/Coverage.py +448 -0
  89. Cython/Debugger/Cygdb.py +214 -0
  90. Cython/Debugger/DebugWriter.py +82 -0
  91. Cython/Debugger/Tests/TestLibCython.py +280 -0
  92. Cython/Debugger/Tests/__init__.py +1 -0
  93. Cython/Debugger/Tests/cfuncs.c +8 -0
  94. Cython/Debugger/Tests/codefile +49 -0
  95. Cython/Debugger/Tests/test_libcython_in_gdb.py +580 -0
  96. Cython/Debugger/Tests/test_libpython_in_gdb.py +90 -0
  97. Cython/Debugger/__init__.py +1 -0
  98. Cython/Debugger/libcython.py +1548 -0
  99. Cython/Debugger/libpython.py +2821 -0
  100. Cython/Debugging.py +20 -0
  101. Cython/Distutils/__init__.py +2 -0
  102. Cython/Distutils/build_ext.py +143 -0
  103. Cython/Distutils/extension.py +96 -0
  104. Cython/Distutils/old_build_ext.py +351 -0
  105. Cython/Includes/cpython/__init__.pxd +173 -0
  106. Cython/Includes/cpython/array.pxd +159 -0
  107. Cython/Includes/cpython/bool.pxd +37 -0
  108. Cython/Includes/cpython/buffer.pxd +112 -0
  109. Cython/Includes/cpython/bytearray.pxd +33 -0
  110. Cython/Includes/cpython/bytes.pxd +200 -0
  111. Cython/Includes/cpython/cellobject.pxd +35 -0
  112. Cython/Includes/cpython/ceval.pxd +8 -0
  113. Cython/Includes/cpython/codecs.pxd +121 -0
  114. Cython/Includes/cpython/complex.pxd +60 -0
  115. Cython/Includes/cpython/contextvars.pxd +145 -0
  116. Cython/Includes/cpython/conversion.pxd +36 -0
  117. Cython/Includes/cpython/datetime.pxd +395 -0
  118. Cython/Includes/cpython/descr.pxd +26 -0
  119. Cython/Includes/cpython/dict.pxd +268 -0
  120. Cython/Includes/cpython/exc.pxd +263 -0
  121. Cython/Includes/cpython/fileobject.pxd +57 -0
  122. Cython/Includes/cpython/float.pxd +56 -0
  123. Cython/Includes/cpython/frozendict.pxd +37 -0
  124. Cython/Includes/cpython/function.pxd +65 -0
  125. Cython/Includes/cpython/genobject.pxd +25 -0
  126. Cython/Includes/cpython/getargs.pxd +12 -0
  127. Cython/Includes/cpython/instance.pxd +25 -0
  128. Cython/Includes/cpython/iterator.pxd +36 -0
  129. Cython/Includes/cpython/iterobject.pxd +24 -0
  130. Cython/Includes/cpython/list.pxd +144 -0
  131. Cython/Includes/cpython/long.pxd +180 -0
  132. Cython/Includes/cpython/longintrepr.pxd +14 -0
  133. Cython/Includes/cpython/mapping.pxd +63 -0
  134. Cython/Includes/cpython/marshal.pxd +66 -0
  135. Cython/Includes/cpython/mem.pxd +120 -0
  136. Cython/Includes/cpython/memoryview.pxd +50 -0
  137. Cython/Includes/cpython/method.pxd +49 -0
  138. Cython/Includes/cpython/module.pxd +208 -0
  139. Cython/Includes/cpython/number.pxd +258 -0
  140. Cython/Includes/cpython/object.pxd +430 -0
  141. Cython/Includes/cpython/pycapsule.pxd +143 -0
  142. Cython/Includes/cpython/pylifecycle.pxd +68 -0
  143. Cython/Includes/cpython/pyport.pxd +8 -0
  144. Cython/Includes/cpython/pystate.pxd +95 -0
  145. Cython/Includes/cpython/pythread.pxd +53 -0
  146. Cython/Includes/cpython/ref.pxd +141 -0
  147. Cython/Includes/cpython/sentinel.pxd +17 -0
  148. Cython/Includes/cpython/sequence.pxd +134 -0
  149. Cython/Includes/cpython/set.pxd +119 -0
  150. Cython/Includes/cpython/slice.pxd +70 -0
  151. Cython/Includes/cpython/time.pxd +129 -0
  152. Cython/Includes/cpython/tuple.pxd +72 -0
  153. Cython/Includes/cpython/type.pxd +146 -0
  154. Cython/Includes/cpython/unicode.pxd +639 -0
  155. Cython/Includes/cpython/version.pxd +32 -0
  156. Cython/Includes/cpython/weakref.pxd +78 -0
  157. Cython/Includes/libc/__init__.pxd +1 -0
  158. Cython/Includes/libc/complex.pxd +35 -0
  159. Cython/Includes/libc/errno.pxd +127 -0
  160. Cython/Includes/libc/float.pxd +43 -0
  161. Cython/Includes/libc/limits.pxd +28 -0
  162. Cython/Includes/libc/locale.pxd +46 -0
  163. Cython/Includes/libc/math.pxd +209 -0
  164. Cython/Includes/libc/setjmp.pxd +10 -0
  165. Cython/Includes/libc/signal.pxd +64 -0
  166. Cython/Includes/libc/stdbool.pxd +5 -0
  167. Cython/Includes/libc/stddef.pxd +9 -0
  168. Cython/Includes/libc/stdint.pxd +105 -0
  169. Cython/Includes/libc/stdio.pxd +80 -0
  170. Cython/Includes/libc/stdlib.pxd +72 -0
  171. Cython/Includes/libc/string.pxd +50 -0
  172. Cython/Includes/libc/threads.pxd +234 -0
  173. Cython/Includes/libc/time.pxd +52 -0
  174. Cython/Includes/libcpp/__init__.pxd +4 -0
  175. Cython/Includes/libcpp/algorithm.pxd +320 -0
  176. Cython/Includes/libcpp/any.pxd +16 -0
  177. Cython/Includes/libcpp/atomic.pxd +59 -0
  178. Cython/Includes/libcpp/barrier.pxd +22 -0
  179. Cython/Includes/libcpp/bit.pxd +29 -0
  180. Cython/Includes/libcpp/cast.pxd +12 -0
  181. Cython/Includes/libcpp/cmath.pxd +518 -0
  182. Cython/Includes/libcpp/complex.pxd +106 -0
  183. Cython/Includes/libcpp/condition_variable.pxd +322 -0
  184. Cython/Includes/libcpp/deque.pxd +165 -0
  185. Cython/Includes/libcpp/exception.pxd +216 -0
  186. Cython/Includes/libcpp/execution.pxd +15 -0
  187. Cython/Includes/libcpp/forward_list.pxd +63 -0
  188. Cython/Includes/libcpp/functional.pxd +26 -0
  189. Cython/Includes/libcpp/future.pxd +103 -0
  190. Cython/Includes/libcpp/iterator.pxd +34 -0
  191. Cython/Includes/libcpp/latch.pxd +17 -0
  192. Cython/Includes/libcpp/limits.pxd +61 -0
  193. Cython/Includes/libcpp/list.pxd +117 -0
  194. Cython/Includes/libcpp/map.pxd +252 -0
  195. Cython/Includes/libcpp/memory.pxd +115 -0
  196. Cython/Includes/libcpp/mutex.pxd +387 -0
  197. Cython/Includes/libcpp/numbers.pxd +15 -0
  198. Cython/Includes/libcpp/numeric.pxd +131 -0
  199. Cython/Includes/libcpp/optional.pxd +34 -0
  200. Cython/Includes/libcpp/pair.pxd +1 -0
  201. Cython/Includes/libcpp/queue.pxd +25 -0
  202. Cython/Includes/libcpp/random.pxd +166 -0
  203. Cython/Includes/libcpp/semaphore.pxd +43 -0
  204. Cython/Includes/libcpp/set.pxd +228 -0
  205. Cython/Includes/libcpp/shared_mutex.pxd +96 -0
  206. Cython/Includes/libcpp/span.pxd +87 -0
  207. Cython/Includes/libcpp/stack.pxd +11 -0
  208. Cython/Includes/libcpp/stop_token.pxd +117 -0
  209. Cython/Includes/libcpp/string.pxd +355 -0
  210. Cython/Includes/libcpp/string_view.pxd +183 -0
  211. Cython/Includes/libcpp/typeindex.pxd +15 -0
  212. Cython/Includes/libcpp/typeinfo.pxd +10 -0
  213. Cython/Includes/libcpp/unordered_map.pxd +193 -0
  214. Cython/Includes/libcpp/unordered_set.pxd +152 -0
  215. Cython/Includes/libcpp/utility.pxd +30 -0
  216. Cython/Includes/libcpp/vector.pxd +186 -0
  217. Cython/Includes/numpy/math.pxd +150 -0
  218. Cython/Includes/openmp.pxd +50 -0
  219. Cython/Includes/posix/__init__.pxd +1 -0
  220. Cython/Includes/posix/dlfcn.pxd +14 -0
  221. Cython/Includes/posix/fcntl.pxd +86 -0
  222. Cython/Includes/posix/ioctl.pxd +4 -0
  223. Cython/Includes/posix/mman.pxd +101 -0
  224. Cython/Includes/posix/resource.pxd +57 -0
  225. Cython/Includes/posix/select.pxd +21 -0
  226. Cython/Includes/posix/signal.pxd +73 -0
  227. Cython/Includes/posix/stat.pxd +98 -0
  228. Cython/Includes/posix/stdio.pxd +37 -0
  229. Cython/Includes/posix/stdlib.pxd +29 -0
  230. Cython/Includes/posix/strings.pxd +9 -0
  231. Cython/Includes/posix/time.pxd +71 -0
  232. Cython/Includes/posix/types.pxd +30 -0
  233. Cython/Includes/posix/uio.pxd +26 -0
  234. Cython/Includes/posix/unistd.pxd +271 -0
  235. Cython/Includes/posix/wait.pxd +38 -0
  236. Cython/LZSS.py +184 -0
  237. Cython/Plex/Actions.pxd +24 -0
  238. Cython/Plex/Actions.py +119 -0
  239. Cython/Plex/DFA.pxd +14 -0
  240. Cython/Plex/DFA.py +164 -0
  241. Cython/Plex/Errors.py +48 -0
  242. Cython/Plex/Lexicons.py +178 -0
  243. Cython/Plex/Machines.pxd +36 -0
  244. Cython/Plex/Machines.py +238 -0
  245. Cython/Plex/Regexps.py +535 -0
  246. Cython/Plex/Scanners.pxd +45 -0
  247. Cython/Plex/Scanners.py +328 -0
  248. Cython/Plex/Transitions.pxd +14 -0
  249. Cython/Plex/Transitions.py +239 -0
  250. Cython/Plex/__init__.py +34 -0
  251. Cython/Runtime/__init__.py +1 -0
  252. Cython/Runtime/refnanny.pyx +237 -0
  253. Cython/Shadow.py +1172 -0
  254. Cython/StringIOTree.py +169 -0
  255. Cython/Tempita/__init__.py +4 -0
  256. Cython/Tempita/_looper.py +154 -0
  257. Cython/Tempita/_tempita.py +1087 -0
  258. Cython/TestUtils.py +472 -0
  259. Cython/Tests/TestCodeWriter.py +128 -0
  260. Cython/Tests/TestCythonUtils.py +237 -0
  261. Cython/Tests/TestJediTyper.py +223 -0
  262. Cython/Tests/TestShadow.py +125 -0
  263. Cython/Tests/TestStringIOTree.py +68 -0
  264. Cython/Tests/TestTestUtils.py +89 -0
  265. Cython/Tests/__init__.py +1 -0
  266. Cython/Tests/xmlrunner.py +390 -0
  267. Cython/Utility/AsyncGen.c +1152 -0
  268. Cython/Utility/Buffer.c +866 -0
  269. Cython/Utility/BufferFormatFromTypeInfo.pxd +2 -0
  270. Cython/Utility/Builtins.c +1068 -0
  271. Cython/Utility/CConvert.pyx +153 -0
  272. Cython/Utility/CMath.c +104 -0
  273. Cython/Utility/CommonStructures.c +244 -0
  274. Cython/Utility/Complex.c +378 -0
  275. Cython/Utility/Coroutine.c +2344 -0
  276. Cython/Utility/CpdefEnums.pyx +119 -0
  277. Cython/Utility/CppConvert.pyx +284 -0
  278. Cython/Utility/CppSupport.cpp +151 -0
  279. Cython/Utility/CythonFunction.c +2143 -0
  280. Cython/Utility/Dataclasses.c +101 -0
  281. Cython/Utility/Embed.c +129 -0
  282. Cython/Utility/Exceptions.c +1331 -0
  283. Cython/Utility/Exceptions_Cy.pyx +109 -0
  284. Cython/Utility/ExtensionTypes.c +1199 -0
  285. Cython/Utility/FunctionArguments.c +1052 -0
  286. Cython/Utility/FusedFunction.pyx +44 -0
  287. Cython/Utility/ImportExport.c +972 -0
  288. Cython/Utility/MatchCase.c +985 -0
  289. Cython/Utility/MatchCase_Cy.pyx +12 -0
  290. Cython/Utility/MemoryView.pxd +108 -0
  291. Cython/Utility/MemoryView.pyx +1499 -0
  292. Cython/Utility/MemoryView_C.c +1056 -0
  293. Cython/Utility/ModuleSetupCode.c +3349 -0
  294. Cython/Utility/NumpyImportArray.c +46 -0
  295. Cython/Utility/ObjectHandling.c +3404 -0
  296. Cython/Utility/Optimize.c +2575 -0
  297. Cython/Utility/Overflow.c +378 -0
  298. Cython/Utility/Profile.c +736 -0
  299. Cython/Utility/StringTools.c +1534 -0
  300. Cython/Utility/Synchronization.c +438 -0
  301. Cython/Utility/TString.c +369 -0
  302. Cython/Utility/TestCyUtilityLoader.pyx +8 -0
  303. Cython/Utility/TestCythonScope.pyx +75 -0
  304. Cython/Utility/TestUtilityLoader.c +12 -0
  305. Cython/Utility/TypeConversion.c +1588 -0
  306. Cython/Utility/UFuncs.pyx +50 -0
  307. Cython/Utility/UFuncs_C.c +89 -0
  308. Cython/Utility/__init__.py +28 -0
  309. Cython/Utility/arrayarray.h +190 -0
  310. Cython/Utils.py +682 -0
  311. Cython/__init__.py +12 -0
  312. Cython/py.typed +0 -0
  313. cython.py +29 -0
  314. oxython-0.1.0.dist-info/METADATA +138 -0
  315. oxython-0.1.0.dist-info/RECORD +321 -0
  316. oxython-0.1.0.dist-info/WHEEL +5 -0
  317. oxython-0.1.0.dist-info/entry_points.txt +4 -0
  318. oxython-0.1.0.dist-info/top_level.txt +3 -0
  319. pyximport/__init__.py +4 -0
  320. pyximport/pyxbuild.py +160 -0
  321. pyximport/pyximport.py +482 -0
@@ -0,0 +1,771 @@
1
+ # cython: infer_types=True
2
+ #
3
+ # Cython Scanner
4
+ #
5
+
6
+
7
+ import cython
8
+
9
+ cython.declare(make_lexicon=object, lexicon=object, oxython_lexicon=object,
10
+ print_function=object, error=object, warning=object,
11
+ os=object, platform=object, Path=object)
12
+
13
+ import os
14
+ import platform
15
+ from contextlib import contextmanager
16
+ from pathlib import Path
17
+ from unicodedata import normalize
18
+
19
+ from .. import Utils
20
+ from ..Plex.Errors import UnrecognizedInput
21
+ from ..Plex.Scanners import Scanner
22
+ from .Errors import error, warning, hold_errors, release_errors, CompileError
23
+ from .Lexicon import any_string_prefix, ft_string_prefixes, make_lexicon, IDENT
24
+ from .Future import print_function
25
+ from .Lexicon import IDENT, any_string_prefix, make_lexicon
26
+
27
+ debug_scanner = 0
28
+ trace_scanner = 0
29
+ scanner_debug_flags = 0
30
+ scanner_dump_file = None
31
+
32
+ lexicon = None
33
+ oxython_lexicon = None
34
+
35
+
36
+ def get_lexicon(oxython=False):
37
+ global lexicon, oxython_lexicon
38
+ if oxython:
39
+ if not oxython_lexicon:
40
+ oxython_lexicon = make_lexicon(oxython=True)
41
+ return oxython_lexicon
42
+ if not lexicon:
43
+ lexicon = make_lexicon()
44
+ return lexicon
45
+
46
+
47
+ # oxython file extensions and the Cython extension each one stands for
48
+ oxython_extensions = {'.oxy': '.pyx', '.oxd': '.pxd', '.oxi': '.pxi'}
49
+
50
+
51
+ def source_is_oxython(source_desc):
52
+ """
53
+ oxython syntax is used for .oxy, .oxd and .oxi files. The environment
54
+ variable CYTHON_FORCE_OXYTHON applies it to every Cython file, which lets
55
+ the upstream test suite check that existing code still parses.
56
+ """
57
+ if getattr(source_desc, 'in_utility_code', False) or source_desc.is_python_file():
58
+ return False
59
+ if source_desc.is_oxython_file:
60
+ return True
61
+ return bool(os.environ.get('CYTHON_FORCE_OXYTHON'))
62
+
63
+
64
+ #------------------------------------------------------------------
65
+
66
+ py_reserved_words = [
67
+ "global", "nonlocal", "def", "class", "print", "del", "pass", "break",
68
+ "continue", "return", "raise", "import", "exec", "try",
69
+ "except", "finally", "while", "if", "elif", "else", "for",
70
+ "in", "assert", "and", "or", "not", "is", "lambda",
71
+ "from", "yield", "with",
72
+ ]
73
+
74
+ pyx_reserved_words = py_reserved_words + [
75
+ "include", "ctypedef", "cdef", "cpdef",
76
+ "cimport", "DEF", "IF", "ELIF", "ELSE"
77
+ ]
78
+
79
+
80
+ #------------------------------------------------------------------
81
+
82
+ class CompileTimeScope:
83
+
84
+ def __init__(self, outer=None):
85
+ self.entries = {}
86
+ self.outer = outer
87
+
88
+ def declare(self, name, value):
89
+ self.entries[name] = value
90
+
91
+ def update(self, other):
92
+ self.entries.update(other)
93
+
94
+ def lookup_here(self, name):
95
+ return self.entries[name]
96
+
97
+ def __contains__(self, name):
98
+ return name in self.entries
99
+
100
+ def lookup(self, name):
101
+ try:
102
+ return self.lookup_here(name)
103
+ except KeyError:
104
+ outer = self.outer
105
+ if outer:
106
+ return outer.lookup(name)
107
+ else:
108
+ raise
109
+
110
+
111
+ def initial_compile_time_env():
112
+ benv = CompileTimeScope()
113
+ names = ('UNAME_SYSNAME', 'UNAME_NODENAME', 'UNAME_RELEASE', 'UNAME_VERSION', 'UNAME_MACHINE')
114
+ for name, value in zip(names, platform.uname()):
115
+ benv.declare(name, value)
116
+ import builtins
117
+
118
+ names = (
119
+ 'False', 'True',
120
+ 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes',
121
+ 'chr', 'complex', 'dict', 'divmod', 'enumerate', 'filter',
122
+ 'float', 'format', 'frozenset', 'hash', 'hex', 'int', 'len',
123
+ 'list', 'map', 'max', 'min', 'next', 'oct', 'ord', 'pow', 'range',
124
+ 'repr', 'reversed', 'round', 'set', 'slice', 'sorted', 'str',
125
+ 'sum', 'tuple', 'zip',
126
+ ### defined below in a platform independent way
127
+ # 'long', 'unicode', 'reduce', 'xrange'
128
+ )
129
+
130
+ for name in names:
131
+ benv.declare(name, getattr(builtins, name))
132
+
133
+ # legacy Py2 names
134
+ from functools import reduce
135
+ benv.declare('reduce', reduce)
136
+ benv.declare('unicode', str)
137
+ benv.declare('long', int)
138
+ benv.declare('xrange', range)
139
+
140
+ denv = CompileTimeScope(benv)
141
+ return denv
142
+
143
+
144
+ #------------------------------------------------------------------
145
+
146
+ class SourceDescriptor:
147
+ """
148
+ A SourceDescriptor should be considered immutable.
149
+ """
150
+ filename = None
151
+ in_utility_code = False
152
+
153
+ _file_type = 'pyx'
154
+ is_oxython_file = False
155
+
156
+ _escaped_description = None
157
+ _cmp_name = ''
158
+ def __str__(self):
159
+ assert False # To catch all places where a descriptor is used directly as a filename
160
+
161
+ def set_file_type_from_name(self, filename):
162
+ name, ext = os.path.splitext(filename)
163
+ # oxython files: .oxy (module), .oxd (declarations), .oxi (include)
164
+ self.is_oxython_file = ext in oxython_extensions
165
+ ext = oxython_extensions.get(ext, ext)
166
+ self._file_type = ext in ('.pyx', '.pxd', '.py') and ext[1:] or 'pyx'
167
+
168
+ def is_cython_file(self):
169
+ return self._file_type in ('pyx', 'pxd')
170
+
171
+ def is_python_file(self):
172
+ return self._file_type == 'py'
173
+
174
+ def get_escaped_description(self):
175
+ if self._escaped_description is None:
176
+ # Use forward slashes on Windows since these paths
177
+ # will be used in the #line directives in the C/C++ files.
178
+ self._escaped_description = self.get_description().replace('\\', '/')
179
+ return self._escaped_description
180
+
181
+ def __gt__(self, other):
182
+ # this is only used to provide some sort of order
183
+ try:
184
+ return self._cmp_name > other._cmp_name
185
+ except AttributeError:
186
+ return False
187
+
188
+ def __lt__(self, other):
189
+ # this is only used to provide some sort of order
190
+ try:
191
+ return self._cmp_name < other._cmp_name
192
+ except AttributeError:
193
+ return False
194
+
195
+ def __le__(self, other):
196
+ # this is only used to provide some sort of order
197
+ try:
198
+ return self._cmp_name <= other._cmp_name
199
+ except AttributeError:
200
+ return False
201
+
202
+ def __copy__(self):
203
+ return self # immutable, no need to copy
204
+
205
+ def __deepcopy__(self, memo):
206
+ return self # immutable, no need to copy
207
+
208
+
209
+ class FileSourceDescriptor(SourceDescriptor):
210
+ """
211
+ Represents a code source. A code source is a more generic abstraction
212
+ for a "filename" (as sometimes the code doesn't come from a file).
213
+ Instances of code sources are passed to Scanner.__init__ as the
214
+ optional name argument and will be passed back when asking for
215
+ the position()-tuple.
216
+ """
217
+ def __init__(self, filename, path_description=None):
218
+ filename = Utils.decode_filename(filename)
219
+ self.filename = filename
220
+ self.path_description = path_description or filename
221
+ try:
222
+ self._short_path_description = os.path.relpath(self.path_description)
223
+ except ValueError:
224
+ # path not under current directory => use complete file path
225
+ self._short_path_description = self.path_description
226
+ # Prefer relative paths to current directory (which is most likely the project root) over absolute paths.
227
+ workdir = os.path.abspath('.') + os.sep
228
+ self.file_path = filename[len(workdir):] if filename.startswith(workdir) else filename
229
+ self.set_file_type_from_name(filename)
230
+ self._cmp_name = filename
231
+ self._lines = {}
232
+
233
+ def get_lines(self, encoding=None, error_handling=None):
234
+ # we cache the lines only the second time this is called, in
235
+ # order to save memory when they are only used once
236
+ key = (encoding, error_handling)
237
+ lines = self._lines.get(key)
238
+ if lines is not None:
239
+ return lines
240
+
241
+ with self.get_file_object(encoding=encoding, error_handling=error_handling) as f:
242
+ lines = [line.rstrip() for line in f.readlines()]
243
+
244
+ # Do not cache the first access, but add the key to remember that we already read it once.
245
+ self._lines[key] = lines if key in self._lines else None
246
+ return lines
247
+
248
+ def get_file_object(self, encoding=None, error_handling=None):
249
+ return Utils.open_source_file(self.filename, encoding, error_handling)
250
+
251
+ def get_description(self):
252
+ return self._short_path_description
253
+
254
+ def get_relative_path(self) -> Path:
255
+ file_path = Path(self.file_path)
256
+ if file_path.is_absolute():
257
+ return Path(self.get_description())
258
+ else:
259
+ return file_path
260
+
261
+ def get_error_description(self):
262
+ path = self.filename
263
+ cwd = Utils.decode_filename(os.getcwd() + os.path.sep)
264
+ if path.startswith(cwd):
265
+ return path[len(cwd):]
266
+ return path
267
+
268
+ def get_filenametable_entry(self):
269
+ return self.file_path
270
+
271
+ def __eq__(self, other):
272
+ return isinstance(other, FileSourceDescriptor) and self.filename == other.filename
273
+
274
+ def __hash__(self):
275
+ return hash(self.filename)
276
+
277
+ def __repr__(self):
278
+ return "<FileSourceDescriptor:%s>" % self.filename
279
+
280
+
281
+ class StringSourceDescriptor(SourceDescriptor):
282
+ """
283
+ Instances of this class can be used instead of a filenames if the
284
+ code originates from a string object.
285
+ """
286
+ def __init__(self, name, code):
287
+ self.name = name
288
+ #self.set_file_type_from_name(name)
289
+ self.codelines = [line.rstrip() for line in code.splitlines()]
290
+ self._cmp_name = name
291
+
292
+ def get_lines(self, encoding=None, error_handling=None):
293
+ if not encoding:
294
+ return self.codelines
295
+ else:
296
+ return [line.encode(encoding, error_handling).decode(encoding)
297
+ for line in self.codelines]
298
+
299
+ def get_description(self):
300
+ return self.name
301
+
302
+ def get_relative_path(self):
303
+ return Path(self.get_description())
304
+
305
+ get_error_description = get_description
306
+
307
+ def get_filenametable_entry(self):
308
+ return "<stringsource>"
309
+
310
+ def __hash__(self):
311
+ return id(self)
312
+ # Do not hash on the name, an identical string source should be the
313
+ # same object (name is often defaulted in other places)
314
+ # return hash(self.name)
315
+
316
+ def __eq__(self, other):
317
+ return isinstance(other, StringSourceDescriptor) and self.name == other.name
318
+
319
+ def __repr__(self):
320
+ return "<StringSourceDescriptor:%s>" % self.name
321
+
322
+
323
+ class SharedUtilitySourceDescriptor(FileSourceDescriptor):
324
+ """
325
+ A specialized source descriptor for shared utility code only. Not part of public API.
326
+ """
327
+
328
+ def get_file_object(self, encoding=None, error_handling=None):
329
+ from io import StringIO
330
+ return StringIO('')
331
+
332
+ #------------------------------------------------------------------
333
+
334
+ class PyrexScanner(Scanner):
335
+ # context Context Compilation context
336
+ # included_files [string] Files included with 'include' statement
337
+ # compile_time_env dict Environment for conditional compilation
338
+ # compile_time_eval boolean In a true conditional compilation context
339
+ # compile_time_expr boolean In a compile-time expression context
340
+ # put_back_on_failure list or None If set, this records states so the tentatively_scan
341
+ # contextmanager can restore it
342
+
343
+ def __init__(self, file, filename, parent_scanner=None,
344
+ scope=None, context=None, source_encoding=None, parse_comments=True, initial_pos=None):
345
+ if parent_scanner is not None and parent_scanner.oxython:
346
+ self.oxython = True
347
+ else:
348
+ self.oxython = source_is_oxython(filename)
349
+ Scanner.__init__(self, get_lexicon(self.oxython), file, filename, initial_pos)
350
+
351
+ self.raw_ident = False
352
+ self.in_subscript = False
353
+ if filename.is_python_file():
354
+ self.in_python_file = True
355
+ keywords = py_reserved_words
356
+ else:
357
+ self.in_python_file = False
358
+ keywords = pyx_reserved_words
359
+ self.keywords = {keyword: keyword for keyword in keywords}
360
+
361
+ self.async_enabled = 0
362
+
363
+ if parent_scanner:
364
+ self.context = parent_scanner.context
365
+ self.included_files = parent_scanner.included_files
366
+ self.compile_time_env = parent_scanner.compile_time_env
367
+ self.compile_time_eval = parent_scanner.compile_time_eval
368
+ self.compile_time_expr = parent_scanner.compile_time_expr
369
+
370
+ if parent_scanner.async_enabled:
371
+ self.enter_async()
372
+ else:
373
+ self.context = context
374
+ self.included_files = scope.included_files
375
+ self.compile_time_env = initial_compile_time_env()
376
+ self.compile_time_eval = 1
377
+ self.compile_time_expr = 0
378
+ if getattr(context.options, 'compile_time_env', None):
379
+ self.compile_time_env.update(context.options.compile_time_env)
380
+ self.parse_comments = parse_comments
381
+ self.source_encoding = source_encoding
382
+ self.trace = trace_scanner
383
+ self.indentation_stack = [0]
384
+ self.indentation_char = '\0'
385
+ self.bracket_nesting_level = 0
386
+ # fstrings/tstrings
387
+ self.ft_string_state_stack = []
388
+ self.in_ft_string_expr_prescan = 0
389
+
390
+ self.put_back_on_failure = None
391
+
392
+ self.begin('INDENT')
393
+ self.sy = ''
394
+ self.next()
395
+
396
+ def normalize_ident(self, text):
397
+ if not text.isascii():
398
+ text = normalize('NFKC', text)
399
+ if self.oxython and text.startswith('r#'):
400
+ self.produce('RAW_IDENT', text[2:])
401
+ else:
402
+ self.produce(IDENT, text)
403
+
404
+ def commentline(self, text):
405
+ if self.parse_comments:
406
+ self.produce('commentline', text)
407
+
408
+ def strip_underscores(self, text, symbol):
409
+ self.produce(symbol, text.replace('_', ''))
410
+
411
+ def int_before_range_action(self, text):
412
+ # oxython: '1..5' / '1..=5' => INT '1', then the range operator
413
+ op = '..=' if text.endswith('..=') else '..'
414
+ self.produce('INT', text[:-len(op)].replace('_', ''))
415
+ self.produce(op, op)
416
+
417
+ def current_level(self):
418
+ return self.indentation_stack[-1]
419
+
420
+ def open_bracket_action(self, text):
421
+ self.bracket_nesting_level += 1
422
+ return text
423
+
424
+ def close_bracket_action(self, text):
425
+ self.bracket_nesting_level -= 1
426
+ if (self.ft_string_state_stack and
427
+ self.ft_string_state_stack[-1].bracket_nesting_level() > self.bracket_nesting_level):
428
+ self.error_at_scanpos(f"Unmatched '{text}'")
429
+ return text
430
+
431
+ def open_brace_action(self, text):
432
+ return self.open_bracket_action(text)
433
+
434
+ def close_brace_action(self, text):
435
+ assert text == '}'
436
+ if (self.ft_string_state_stack and
437
+ self.ft_string_state_stack[-1].bracket_nesting_level() == self.bracket_nesting_level):
438
+ if not self.ft_string_state_stack[-1].in_format_specifier():
439
+ self.in_ft_string_expr_prescan -= 1
440
+ if self.in_ft_string_expr_prescan == 0:
441
+ self.produce("END_FT_STRING_EXPR")
442
+ self.begin(self.ft_string_state_stack[-1].scanner_state)
443
+ self.ft_string_state_stack[-1].pop_bracket_state()
444
+ self.bracket_nesting_level -= 1
445
+ return text
446
+
447
+ def colon_action(self, text):
448
+ if (self.ft_string_state_stack and
449
+ self.ft_string_state_stack[-1].bracket_nesting_level() == self.bracket_nesting_level):
450
+ self.in_ft_string_expr_prescan -= 1
451
+ if self.in_ft_string_expr_prescan == 0:
452
+ self.produce("END_FT_STRING_EXPR")
453
+ self.begin(self.ft_string_state_stack[-1].scanner_state)
454
+ self.ft_string_state_stack[-1].set_in_format_specifier()
455
+ return text
456
+
457
+ def newline_action(self, text):
458
+ if self.bracket_nesting_level == 0:
459
+ self.begin('INDENT')
460
+ self.produce('NEWLINE', '')
461
+
462
+ string_states = {
463
+ "'": 'SQ_STRING',
464
+ '"': 'DQ_STRING',
465
+ "'''": 'TSQ_STRING',
466
+ '"""': 'TDQ_STRING'
467
+ }
468
+
469
+ def begin_string_action(self, text: str):
470
+ while text and text[0] in any_string_prefix:
471
+ text = text[1:]
472
+ self.begin(self.string_states[text])
473
+ self.produce('BEGIN_STRING')
474
+
475
+ def end_string_action(self, text):
476
+ self.begin('FT_STRING_EXPR_PRESCAN' if self.in_ft_string_expr_prescan else '')
477
+ self.produce('END_STRING')
478
+
479
+ def begin_ft_string_action(self, text):
480
+ is_raw = 'r' in text or 'R' in text
481
+ while text and (text[0] in any_string_prefix or text[0] in ft_string_prefixes):
482
+ text = text[1:]
483
+ ft_string_state = f'{self.string_states[text]}_FT{"R" if is_raw else ""}'
484
+ self.ft_string_state_stack.append(
485
+ FTStringState(ft_string_state)
486
+ )
487
+ self.begin(ft_string_state)
488
+ self.produce('BEGIN_FT_STRING')
489
+
490
+ def end_ft_string_action(self, text):
491
+ self.ft_string_state_stack.pop()
492
+ self.begin('FT_STRING_EXPR_PRESCAN' if self.in_ft_string_expr_prescan else '')
493
+ self.produce('END_FT_STRING')
494
+
495
+ def _handle_open_single_ft_string_brace(self, started_ft_string_expr):
496
+ self.bracket_nesting_level += 1
497
+ if not started_ft_string_expr:
498
+ self.ft_string_state_stack[-1].push_bracket_state(self.bracket_nesting_level)
499
+ self.begin('FT_STRING_EXPR_PRESCAN')
500
+ self.in_ft_string_expr_prescan += 1
501
+ self.produce('{')
502
+
503
+ def open_ft_string_brace_action(self, text):
504
+ len_text = len(text)
505
+ started_ft_string_expr = False
506
+ if self.ft_string_state_stack[-1].in_format_specifier():
507
+ self._handle_open_single_ft_string_brace(started_ft_string_expr)
508
+ len_text -= 1
509
+ started_ft_string_expr = True
510
+ assert not self.ft_string_state_stack[-1].in_format_specifier()
511
+
512
+ double_braces = len_text // 2
513
+ for _ in range(double_braces):
514
+ self.produce('CHARS', '{')
515
+ len_text -= (double_braces*2)
516
+
517
+ if len_text:
518
+ assert len_text == 1
519
+ self._handle_open_single_ft_string_brace(started_ft_string_expr)
520
+
521
+ def _handle_close_single_ft_string_brace(self):
522
+ ft_string_bracket_level = self.ft_string_state_stack[-1].bracket_nesting_level()
523
+ if ft_string_bracket_level is None or self.bracket_nesting_level < ft_string_bracket_level:
524
+ # To help try to parse a little further, don't reduce the bracket
525
+ # nesting level more.
526
+ self.error(
527
+ # Unfortunately the scanner doesn't know which
528
+ "f-string or t-string: single '}' is not allowed",
529
+ pos=self.get_current_scan_pos(),
530
+ fatal=False)
531
+ self.produce('}', '}')
532
+ else:
533
+ self.produce(self.close_brace_action('}'), '}')
534
+
535
+ def close_ft_string_brace_action(self, text):
536
+ len_text = len(text)
537
+ while len_text and self.ft_string_state_stack[-1].in_format_specifier():
538
+ self._handle_close_single_ft_string_brace()
539
+ len_text -= 1
540
+
541
+ double_braces = len_text // 2
542
+ for _ in range(double_braces):
543
+ self.produce('CHARS', '}')
544
+ len_text -= double_braces*2
545
+
546
+ if len_text:
547
+ self._handle_close_single_ft_string_brace()
548
+
549
+ def unclosed_string_action(self, text):
550
+ self.end_string_action(text)
551
+ self.error_at_scanpos("Unclosed string literal")
552
+
553
+ def indentation_action(self, text: str):
554
+ self.begin('')
555
+ # Indentation within brackets should be ignored.
556
+ #if self.bracket_nesting_level > 0:
557
+ # return
558
+ # Check that tabs and spaces are being used consistently.
559
+ if text:
560
+ c = text[0]
561
+ #print "Scanner.indentation_action: indent with", repr(c) ###
562
+ if self.indentation_char == '\0':
563
+ self.indentation_char = c
564
+ #print "Scanner.indentation_action: setting indent_char to", repr(c)
565
+ else:
566
+ if self.indentation_char != c:
567
+ self.error_at_scanpos("Mixed use of tabs and spaces")
568
+ if text.replace(c, "") != "":
569
+ self.error_at_scanpos("Mixed use of tabs and spaces")
570
+ # Figure out how many indents/dedents to do
571
+ current_level: cython.Py_ssize_t = self.current_level()
572
+ new_level: cython.Py_ssize_t = len(text)
573
+ #print "Changing indent level from", current_level, "to", new_level ###
574
+ if new_level == current_level:
575
+ return
576
+ elif new_level > current_level:
577
+ #print "...pushing level", new_level ###
578
+ self.indentation_stack.append(new_level)
579
+ self.produce('INDENT', '')
580
+ else:
581
+ while new_level < self.current_level():
582
+ #print "...popping level", self.indentation_stack[-1] ###
583
+ self.indentation_stack.pop()
584
+ self.produce('DEDENT', '')
585
+ #print "...current level now", self.current_level() ###
586
+ if new_level != self.current_level():
587
+ self.error_at_scanpos("Inconsistent indentation")
588
+
589
+ def eof_action(self, text):
590
+ while len(self.indentation_stack) > 1:
591
+ self.produce('DEDENT', '')
592
+ self.indentation_stack.pop()
593
+ self.produce('EOF', '')
594
+
595
+ def next(self):
596
+ try:
597
+ sy, systring = self.read()
598
+ except UnrecognizedInput:
599
+ self.error_at_scanpos("Unrecognized character")
600
+ return -1 # just a marker, error() always raises
601
+ self.raw_ident = False
602
+ if sy == 'RAW_IDENT':
603
+ # oxython raw identifier (r#name): never a keyword
604
+ sy = IDENT
605
+ self.raw_ident = True
606
+ systring = self.context.intern_ustring(systring)
607
+ elif sy == IDENT:
608
+ if systring in self.keywords:
609
+ if systring == 'print' and print_function in self.context.future_directives:
610
+ self.keywords.pop('print', None)
611
+ elif systring == 'exec' and self.context.language_level >= 3:
612
+ self.keywords.pop('exec', None)
613
+ else:
614
+ sy = self.keywords[systring] # intern
615
+ systring = self.context.intern_ustring(systring)
616
+ if self.put_back_on_failure is not None:
617
+ self.put_back_on_failure.append((sy, systring, self.position()))
618
+ self.sy = sy
619
+ self.systring = systring
620
+ if False: # debug_scanner:
621
+ _, line, col = self.position()
622
+ if not self.systring or self.sy == self.systring:
623
+ t = self.sy
624
+ else:
625
+ t = "%s %s" % (self.sy, self.systring)
626
+ print("--- %3d %2d %s" % (line, col, t))
627
+
628
+ def looking_at_keyword(self, word):
629
+ # oxython contextual keyword: a plain (non-raw) identifier with this spelling
630
+ return self.oxython and self.sy == IDENT and not self.raw_ident and self.systring == word
631
+
632
+ def peek(self):
633
+ saved = self.sy, self.systring
634
+ saved_pos = self.position()
635
+ self.next()
636
+ next = self.sy, self.systring
637
+ self.unread(self.sy, self.systring, self.position())
638
+ self.sy, self.systring = saved
639
+ self.last_token_position_tuple = saved_pos
640
+ return next
641
+
642
+ def put_back(self, sy, systring, pos):
643
+ self.unread(self.sy, self.systring, self.last_token_position_tuple)
644
+ self.sy = sy
645
+ self.systring = systring
646
+ self.last_token_position_tuple = pos
647
+
648
+ def error(self, message, pos=None, fatal=True):
649
+ if pos is None:
650
+ pos = self.position()
651
+ if self.sy == 'INDENT':
652
+ error(pos, "Possible inconsistent indentation")
653
+ err = error(pos, message)
654
+ if fatal: raise err
655
+
656
+ def error_at_scanpos(self, message):
657
+ # Like error(fatal=True), but gets the current scanning position rather than
658
+ # the position of the last token read.
659
+ pos = self.get_current_scan_pos()
660
+ self.error(message, pos, True)
661
+
662
+ def expect(self, what, message=None):
663
+ if self.sy == what:
664
+ self.next()
665
+ else:
666
+ self.expected(what, message)
667
+
668
+ def expect_keyword(self, what, message=None):
669
+ if self.sy == IDENT and self.systring == what:
670
+ self.next()
671
+ else:
672
+ self.expected(what, message)
673
+
674
+ def expected(self, what, message=None):
675
+ if message:
676
+ self.error(message)
677
+ else:
678
+ if self.sy == IDENT:
679
+ found = self.systring
680
+ else:
681
+ found = self.sy
682
+ self.error("Expected '%s', found '%s'" % (what, found))
683
+
684
+ def expect_indent(self):
685
+ self.expect('INDENT', "Expected an increase in indentation level")
686
+
687
+ def expect_dedent(self):
688
+ self.expect('DEDENT', "Expected a decrease in indentation level")
689
+
690
+ def expect_newline(self, message="Expected a newline", ignore_semicolon=False):
691
+ # Expect either a newline or end of file
692
+ useless_trailing_semicolon = None
693
+ if ignore_semicolon and self.sy == ';':
694
+ useless_trailing_semicolon = self.position()
695
+ self.next()
696
+ if self.sy != 'EOF':
697
+ self.expect('NEWLINE', message)
698
+ if useless_trailing_semicolon is not None:
699
+ warning(useless_trailing_semicolon, "useless trailing semicolon")
700
+
701
+ def enter_async(self):
702
+ self.async_enabled += 1
703
+ if self.async_enabled == 1:
704
+ self.keywords['async'] = 'async'
705
+ self.keywords['await'] = 'await'
706
+
707
+ def exit_async(self):
708
+ assert self.async_enabled > 0
709
+ self.async_enabled -= 1
710
+ if not self.async_enabled:
711
+ del self.keywords['await']
712
+ del self.keywords['async']
713
+ if self.sy in ('async', 'await'):
714
+ self.sy, self.systring = IDENT, self.context.intern_ustring(self.sy)
715
+
716
+ @contextmanager
717
+ def tentatively_scan(scanner: PyrexScanner):
718
+ errors = hold_errors()
719
+ try:
720
+ put_back_on_failure = scanner.put_back_on_failure
721
+ scanner.put_back_on_failure = []
722
+ initial_state = (scanner.sy, scanner.systring, scanner.position())
723
+ try:
724
+ yield errors
725
+ except CompileError:
726
+ pass
727
+ finally:
728
+ if errors:
729
+ if scanner.put_back_on_failure:
730
+ for put_back in reversed(scanner.put_back_on_failure[:-1]):
731
+ scanner.put_back(*put_back)
732
+ # we need to restore the initial state too
733
+ scanner.put_back(*initial_state)
734
+ elif put_back_on_failure is not None:
735
+ # the outer "tentatively_scan" block that we're in might still
736
+ # want to undo this block
737
+ put_back_on_failure.extend(scanner.put_back_on_failure)
738
+ scanner.put_back_on_failure = put_back_on_failure
739
+ finally:
740
+ release_errors(ignore=True)
741
+
742
+
743
+ class FTStringState:
744
+ def __init__(self, scanner_state):
745
+ self.scanner_state = scanner_state
746
+ self.bracket_states = []
747
+
748
+ def bracket_nesting_level(self):
749
+ if not self.bracket_states:
750
+ return None
751
+ return self.bracket_states[-1].bracket_nesting_level
752
+
753
+ def in_format_specifier(self):
754
+ if not self.bracket_states:
755
+ return False
756
+ return self.bracket_states[-1].in_format_specifier
757
+
758
+ def set_in_format_specifier(self):
759
+ self.bracket_states[-1].in_format_specifier = True
760
+
761
+ def push_bracket_state(self, bracket_nesting_level: cython.Py_ssize_t):
762
+ self.bracket_states.append(FTStringBracketState(bracket_nesting_level))
763
+
764
+ def pop_bracket_state(self):
765
+ self.bracket_states.pop()
766
+
767
+
768
+ class FTStringBracketState:
769
+ def __init__(self, bracket_nesting_level: cython.Py_ssize_t):
770
+ self.bracket_nesting_level = bracket_nesting_level
771
+ self.in_format_specifier = False