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.
- Cython/Build/BuildExecutable.py +169 -0
- Cython/Build/Cache.py +199 -0
- Cython/Build/Cythonize.py +350 -0
- Cython/Build/Dependencies.py +1314 -0
- Cython/Build/Distutils.py +1 -0
- Cython/Build/Inline.py +463 -0
- Cython/Build/IpythonMagic.py +560 -0
- Cython/Build/SharedModule.py +94 -0
- Cython/Build/Tests/TestCyCache.py +194 -0
- Cython/Build/Tests/TestCythonizeArgsParser.py +481 -0
- Cython/Build/Tests/TestDependencies.py +133 -0
- Cython/Build/Tests/TestInline.py +177 -0
- Cython/Build/Tests/TestIpythonMagic.py +287 -0
- Cython/Build/Tests/TestRecythonize.py +212 -0
- Cython/Build/Tests/TestStripLiterals.py +155 -0
- Cython/Build/Tests/__init__.py +1 -0
- Cython/Build/__init__.py +11 -0
- Cython/CodeWriter.py +815 -0
- Cython/Compiler/AnalysedTreeTransforms.py +97 -0
- Cython/Compiler/Annotate.py +328 -0
- Cython/Compiler/AutoDocTransforms.py +320 -0
- Cython/Compiler/Buffer.py +680 -0
- Cython/Compiler/Builtin.py +984 -0
- Cython/Compiler/CmdLine.py +263 -0
- Cython/Compiler/Code.pxd +149 -0
- Cython/Compiler/Code.py +3746 -0
- Cython/Compiler/Code.pyd +0 -0
- Cython/Compiler/CodeGeneration.py +33 -0
- Cython/Compiler/CythonScope.py +191 -0
- Cython/Compiler/Dataclass.py +864 -0
- Cython/Compiler/DebugFlags.py +24 -0
- Cython/Compiler/Errors.py +297 -0
- Cython/Compiler/ExprNodes.py +15562 -0
- Cython/Compiler/FlowControl.pxd +97 -0
- Cython/Compiler/FlowControl.py +1451 -0
- Cython/Compiler/FlowControl.pyd +0 -0
- Cython/Compiler/FusedNode.py +971 -0
- Cython/Compiler/FusedNode.pyd +0 -0
- Cython/Compiler/Future.py +16 -0
- Cython/Compiler/Interpreter.py +57 -0
- Cython/Compiler/Lexicon.py +421 -0
- Cython/Compiler/LineTable.py +114 -0
- Cython/Compiler/LineTable.pyd +0 -0
- Cython/Compiler/Main.py +857 -0
- Cython/Compiler/MatchCaseNodes.py +259 -0
- Cython/Compiler/MemoryView.py +905 -0
- Cython/Compiler/ModuleNode.py +4235 -0
- Cython/Compiler/Naming.py +363 -0
- Cython/Compiler/Nodes.py +10831 -0
- Cython/Compiler/Optimize.py +5288 -0
- Cython/Compiler/Options.py +843 -0
- Cython/Compiler/ParseTreeTransforms.pxd +78 -0
- Cython/Compiler/ParseTreeTransforms.py +4638 -0
- Cython/Compiler/Parsing.pxd +9 -0
- Cython/Compiler/Parsing.py +4775 -0
- Cython/Compiler/Parsing.pyd +0 -0
- Cython/Compiler/Pipeline.py +439 -0
- Cython/Compiler/PyrexTypes.py +5870 -0
- Cython/Compiler/Pythran.py +232 -0
- Cython/Compiler/Scanning.pxd +48 -0
- Cython/Compiler/Scanning.py +701 -0
- Cython/Compiler/Scanning.pyd +0 -0
- Cython/Compiler/StringEncoding.py +298 -0
- Cython/Compiler/Symtab.py +3073 -0
- Cython/Compiler/Tests/TestBuffer.py +105 -0
- Cython/Compiler/Tests/TestBuiltin.py +72 -0
- Cython/Compiler/Tests/TestCmdLine.py +586 -0
- Cython/Compiler/Tests/TestCode.py +144 -0
- Cython/Compiler/Tests/TestFlowControl.py +65 -0
- Cython/Compiler/Tests/TestGrammar.py +202 -0
- Cython/Compiler/Tests/TestMemView.py +71 -0
- Cython/Compiler/Tests/TestParseTreeTransforms.py +285 -0
- Cython/Compiler/Tests/TestScanning.py +134 -0
- Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
- Cython/Compiler/Tests/TestStringEncoding.py +21 -0
- Cython/Compiler/Tests/TestTreeFragment.py +63 -0
- Cython/Compiler/Tests/TestTreePath.py +103 -0
- Cython/Compiler/Tests/TestTypes.py +75 -0
- Cython/Compiler/Tests/TestUtilityLoad.py +112 -0
- Cython/Compiler/Tests/TestVisitor.py +61 -0
- Cython/Compiler/Tests/Utils.py +36 -0
- Cython/Compiler/Tests/__init__.py +1 -0
- Cython/Compiler/TreeFragment.py +278 -0
- Cython/Compiler/TreePath.py +303 -0
- Cython/Compiler/TypeInference.py +591 -0
- Cython/Compiler/TypeSlots.py +1174 -0
- Cython/Compiler/UFuncs.py +311 -0
- Cython/Compiler/UtilNodes.py +389 -0
- Cython/Compiler/UtilityCode.py +344 -0
- Cython/Compiler/Version.py +8 -0
- Cython/Compiler/Visitor.pxd +53 -0
- Cython/Compiler/Visitor.py +861 -0
- Cython/Compiler/Visitor.pyd +0 -0
- Cython/Compiler/__init__.py +1 -0
- Cython/Coverage.py +448 -0
- Cython/Debugger/Cygdb.py +177 -0
- Cython/Debugger/DebugWriter.py +82 -0
- Cython/Debugger/Tests/TestLibCython.py +275 -0
- Cython/Debugger/Tests/__init__.py +1 -0
- Cython/Debugger/Tests/cfuncs.c +8 -0
- Cython/Debugger/Tests/codefile +49 -0
- Cython/Debugger/Tests/test_libcython_in_gdb.py +578 -0
- Cython/Debugger/Tests/test_libpython_in_gdb.py +90 -0
- Cython/Debugger/__init__.py +1 -0
- Cython/Debugger/libcython.py +1548 -0
- Cython/Debugger/libpython.py +2821 -0
- Cython/Debugging.py +20 -0
- Cython/Distutils/__init__.py +2 -0
- Cython/Distutils/build_ext.py +139 -0
- Cython/Distutils/extension.py +96 -0
- Cython/Distutils/old_build_ext.py +351 -0
- Cython/Includes/cpython/__init__.pxd +173 -0
- Cython/Includes/cpython/array.pxd +178 -0
- Cython/Includes/cpython/bool.pxd +37 -0
- Cython/Includes/cpython/buffer.pxd +112 -0
- Cython/Includes/cpython/bytearray.pxd +33 -0
- Cython/Includes/cpython/bytes.pxd +200 -0
- Cython/Includes/cpython/cellobject.pxd +35 -0
- Cython/Includes/cpython/ceval.pxd +8 -0
- Cython/Includes/cpython/codecs.pxd +121 -0
- Cython/Includes/cpython/complex.pxd +60 -0
- Cython/Includes/cpython/contextvars.pxd +145 -0
- Cython/Includes/cpython/conversion.pxd +36 -0
- Cython/Includes/cpython/datetime.pxd +395 -0
- Cython/Includes/cpython/descr.pxd +26 -0
- Cython/Includes/cpython/dict.pxd +187 -0
- Cython/Includes/cpython/exc.pxd +263 -0
- Cython/Includes/cpython/fileobject.pxd +57 -0
- Cython/Includes/cpython/float.pxd +47 -0
- Cython/Includes/cpython/function.pxd +65 -0
- Cython/Includes/cpython/genobject.pxd +25 -0
- Cython/Includes/cpython/getargs.pxd +12 -0
- Cython/Includes/cpython/instance.pxd +25 -0
- Cython/Includes/cpython/iterator.pxd +36 -0
- Cython/Includes/cpython/iterobject.pxd +24 -0
- Cython/Includes/cpython/list.pxd +92 -0
- Cython/Includes/cpython/long.pxd +149 -0
- Cython/Includes/cpython/longintrepr.pxd +14 -0
- Cython/Includes/cpython/mapping.pxd +63 -0
- Cython/Includes/cpython/marshal.pxd +66 -0
- Cython/Includes/cpython/mem.pxd +120 -0
- Cython/Includes/cpython/memoryview.pxd +50 -0
- Cython/Includes/cpython/method.pxd +49 -0
- Cython/Includes/cpython/module.pxd +208 -0
- Cython/Includes/cpython/number.pxd +258 -0
- Cython/Includes/cpython/object.pxd +433 -0
- Cython/Includes/cpython/pycapsule.pxd +143 -0
- Cython/Includes/cpython/pylifecycle.pxd +68 -0
- Cython/Includes/cpython/pyport.pxd +8 -0
- Cython/Includes/cpython/pystate.pxd +95 -0
- Cython/Includes/cpython/pythread.pxd +53 -0
- Cython/Includes/cpython/ref.pxd +141 -0
- Cython/Includes/cpython/sequence.pxd +134 -0
- Cython/Includes/cpython/set.pxd +119 -0
- Cython/Includes/cpython/slice.pxd +70 -0
- Cython/Includes/cpython/time.pxd +129 -0
- Cython/Includes/cpython/tuple.pxd +72 -0
- Cython/Includes/cpython/type.pxd +53 -0
- Cython/Includes/cpython/unicode.pxd +639 -0
- Cython/Includes/cpython/version.pxd +32 -0
- Cython/Includes/cpython/weakref.pxd +78 -0
- Cython/Includes/libc/__init__.pxd +1 -0
- Cython/Includes/libc/complex.pxd +35 -0
- Cython/Includes/libc/errno.pxd +127 -0
- Cython/Includes/libc/float.pxd +43 -0
- Cython/Includes/libc/limits.pxd +28 -0
- Cython/Includes/libc/locale.pxd +46 -0
- Cython/Includes/libc/math.pxd +209 -0
- Cython/Includes/libc/setjmp.pxd +10 -0
- Cython/Includes/libc/signal.pxd +64 -0
- Cython/Includes/libc/stddef.pxd +9 -0
- Cython/Includes/libc/stdint.pxd +105 -0
- Cython/Includes/libc/stdio.pxd +80 -0
- Cython/Includes/libc/stdlib.pxd +72 -0
- Cython/Includes/libc/string.pxd +50 -0
- Cython/Includes/libc/threads.pxd +234 -0
- Cython/Includes/libc/time.pxd +52 -0
- Cython/Includes/libcpp/__init__.pxd +4 -0
- Cython/Includes/libcpp/algorithm.pxd +320 -0
- Cython/Includes/libcpp/any.pxd +16 -0
- Cython/Includes/libcpp/atomic.pxd +59 -0
- Cython/Includes/libcpp/barrier.pxd +22 -0
- Cython/Includes/libcpp/bit.pxd +29 -0
- Cython/Includes/libcpp/cast.pxd +12 -0
- Cython/Includes/libcpp/cmath.pxd +518 -0
- Cython/Includes/libcpp/complex.pxd +106 -0
- Cython/Includes/libcpp/condition_variable.pxd +322 -0
- Cython/Includes/libcpp/deque.pxd +165 -0
- Cython/Includes/libcpp/exception.pxd +86 -0
- Cython/Includes/libcpp/execution.pxd +15 -0
- Cython/Includes/libcpp/forward_list.pxd +63 -0
- Cython/Includes/libcpp/functional.pxd +26 -0
- Cython/Includes/libcpp/future.pxd +103 -0
- Cython/Includes/libcpp/iterator.pxd +34 -0
- Cython/Includes/libcpp/latch.pxd +17 -0
- Cython/Includes/libcpp/limits.pxd +61 -0
- Cython/Includes/libcpp/list.pxd +117 -0
- Cython/Includes/libcpp/map.pxd +252 -0
- Cython/Includes/libcpp/memory.pxd +115 -0
- Cython/Includes/libcpp/mutex.pxd +387 -0
- Cython/Includes/libcpp/numbers.pxd +15 -0
- Cython/Includes/libcpp/numeric.pxd +131 -0
- Cython/Includes/libcpp/optional.pxd +34 -0
- Cython/Includes/libcpp/pair.pxd +1 -0
- Cython/Includes/libcpp/queue.pxd +25 -0
- Cython/Includes/libcpp/random.pxd +166 -0
- Cython/Includes/libcpp/semaphore.pxd +43 -0
- Cython/Includes/libcpp/set.pxd +228 -0
- Cython/Includes/libcpp/shared_mutex.pxd +96 -0
- Cython/Includes/libcpp/span.pxd +87 -0
- Cython/Includes/libcpp/stack.pxd +11 -0
- Cython/Includes/libcpp/stop_token.pxd +117 -0
- Cython/Includes/libcpp/string.pxd +355 -0
- Cython/Includes/libcpp/string_view.pxd +183 -0
- Cython/Includes/libcpp/typeindex.pxd +15 -0
- Cython/Includes/libcpp/typeinfo.pxd +10 -0
- Cython/Includes/libcpp/unordered_map.pxd +193 -0
- Cython/Includes/libcpp/unordered_set.pxd +152 -0
- Cython/Includes/libcpp/utility.pxd +30 -0
- Cython/Includes/libcpp/vector.pxd +186 -0
- Cython/Includes/numpy/math.pxd +150 -0
- Cython/Includes/openmp.pxd +50 -0
- Cython/Includes/posix/__init__.pxd +1 -0
- Cython/Includes/posix/dlfcn.pxd +14 -0
- Cython/Includes/posix/fcntl.pxd +86 -0
- Cython/Includes/posix/ioctl.pxd +4 -0
- Cython/Includes/posix/mman.pxd +101 -0
- Cython/Includes/posix/resource.pxd +57 -0
- Cython/Includes/posix/select.pxd +21 -0
- Cython/Includes/posix/signal.pxd +73 -0
- Cython/Includes/posix/stat.pxd +98 -0
- Cython/Includes/posix/stdio.pxd +37 -0
- Cython/Includes/posix/stdlib.pxd +29 -0
- Cython/Includes/posix/strings.pxd +9 -0
- Cython/Includes/posix/time.pxd +71 -0
- Cython/Includes/posix/types.pxd +30 -0
- Cython/Includes/posix/uio.pxd +26 -0
- Cython/Includes/posix/unistd.pxd +271 -0
- Cython/Includes/posix/wait.pxd +38 -0
- Cython/Plex/Actions.pxd +24 -0
- Cython/Plex/Actions.py +119 -0
- Cython/Plex/Actions.pyd +0 -0
- Cython/Plex/DFA.pxd +14 -0
- Cython/Plex/DFA.py +164 -0
- Cython/Plex/DFA.pyd +0 -0
- Cython/Plex/Errors.py +48 -0
- Cython/Plex/Lexicons.py +178 -0
- Cython/Plex/Machines.pxd +36 -0
- Cython/Plex/Machines.py +238 -0
- Cython/Plex/Machines.pyd +0 -0
- Cython/Plex/Regexps.py +535 -0
- Cython/Plex/Scanners.pxd +45 -0
- Cython/Plex/Scanners.py +328 -0
- Cython/Plex/Scanners.pyd +0 -0
- Cython/Plex/Transitions.pxd +14 -0
- Cython/Plex/Transitions.py +239 -0
- Cython/Plex/Transitions.pyd +0 -0
- Cython/Plex/__init__.py +34 -0
- Cython/Runtime/__init__.py +1 -0
- Cython/Runtime/refnanny.pyd +0 -0
- Cython/Runtime/refnanny.pyx +237 -0
- Cython/Shadow.py +690 -0
- Cython/Shadow.pyi +521 -0
- Cython/StringIOTree.py +170 -0
- Cython/StringIOTree.pyd +0 -0
- Cython/Tempita/__init__.py +4 -0
- Cython/Tempita/_looper.py +154 -0
- Cython/Tempita/_tempita.py +1091 -0
- Cython/Tempita/_tempita.pyd +0 -0
- Cython/TestUtils.py +422 -0
- Cython/Tests/TestCodeWriter.py +128 -0
- Cython/Tests/TestCythonUtils.py +202 -0
- Cython/Tests/TestJediTyper.py +223 -0
- Cython/Tests/TestShadow.py +114 -0
- Cython/Tests/TestStringIOTree.py +67 -0
- Cython/Tests/TestTestUtils.py +90 -0
- Cython/Tests/__init__.py +1 -0
- Cython/Tests/xmlrunner.py +390 -0
- Cython/Utility/AsyncGen.c +1031 -0
- Cython/Utility/Buffer.c +865 -0
- Cython/Utility/BufferFormatFromTypeInfo.pxd +2 -0
- Cython/Utility/Builtins.c +810 -0
- Cython/Utility/CConvert.pyx +134 -0
- Cython/Utility/CMath.c +104 -0
- Cython/Utility/CommonStructures.c +226 -0
- Cython/Utility/Complex.c +378 -0
- Cython/Utility/Coroutine.c +2300 -0
- Cython/Utility/CpdefEnums.pyx +103 -0
- Cython/Utility/CppConvert.pyx +282 -0
- Cython/Utility/CppSupport.cpp +151 -0
- Cython/Utility/CythonFunction.c +1832 -0
- Cython/Utility/Dataclasses.c +101 -0
- Cython/Utility/Embed.c +121 -0
- Cython/Utility/Exceptions.c +1016 -0
- Cython/Utility/ExtensionTypes.c +996 -0
- Cython/Utility/FunctionArguments.c +1043 -0
- Cython/Utility/FusedFunction.pyx +44 -0
- Cython/Utility/ImportExport.c +907 -0
- Cython/Utility/MemoryView.pxd +188 -0
- Cython/Utility/MemoryView.pyx +1482 -0
- Cython/Utility/MemoryView_C.c +927 -0
- Cython/Utility/ModuleSetupCode.c +3203 -0
- Cython/Utility/NumpyImportArray.c +46 -0
- Cython/Utility/ObjectHandling.c +3273 -0
- Cython/Utility/Optimize.c +1603 -0
- Cython/Utility/Overflow.c +384 -0
- Cython/Utility/Printing.c +86 -0
- Cython/Utility/Profile.c +732 -0
- Cython/Utility/StringTools.c +1379 -0
- Cython/Utility/Synchronization.c +399 -0
- Cython/Utility/TString.c +356 -0
- Cython/Utility/TestCyUtilityLoader.pyx +8 -0
- Cython/Utility/TestCythonScope.pyx +75 -0
- Cython/Utility/TestUtilityLoader.c +12 -0
- Cython/Utility/TypeConversion.c +1385 -0
- Cython/Utility/UFuncs.pyx +50 -0
- Cython/Utility/UFuncs_C.c +89 -0
- Cython/Utility/__init__.py +28 -0
- Cython/Utility/arrayarray.h +167 -0
- Cython/Utils.py +687 -0
- Cython/Utils.pyd +0 -0
- Cython/__init__.py +10 -0
- Cython/__init__.pyi +7 -0
- Cython/py.typed +0 -0
- cython-3.2.0.dist-info/METADATA +85 -0
- cython-3.2.0.dist-info/RECORD +333 -0
- cython-3.2.0.dist-info/WHEEL +5 -0
- cython-3.2.0.dist-info/entry_points.txt +4 -0
- cython-3.2.0.dist-info/top_level.txt +3 -0
- cython.py +29 -0
- pyximport/__init__.py +4 -0
- pyximport/pyxbuild.py +160 -0
- pyximport/pyximport.py +482 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
import Cython.Compiler.PyrexTypes as PT
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TestMethodDispatcherTransform(unittest.TestCase):
|
|
7
|
+
|
|
8
|
+
def test_widest_numeric_type(self):
|
|
9
|
+
def assert_widest(type1, type2, widest):
|
|
10
|
+
self.assertEqual(widest, PT.widest_numeric_type(type1, type2))
|
|
11
|
+
|
|
12
|
+
assert_widest(PT.c_int_type, PT.c_long_type, PT.c_long_type)
|
|
13
|
+
assert_widest(PT.c_double_type, PT.c_long_type, PT.c_double_type)
|
|
14
|
+
assert_widest(PT.c_longdouble_type, PT.c_long_type, PT.c_longdouble_type)
|
|
15
|
+
|
|
16
|
+
cenum = PT.CEnumType("E", "cenum", typedef_flag=False)
|
|
17
|
+
assert_widest(PT.c_int_type, cenum, PT.c_int_type)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestTypeIdentifiers(unittest.TestCase):
|
|
21
|
+
|
|
22
|
+
TEST_DATA = [
|
|
23
|
+
("char*", "char__ptr"),
|
|
24
|
+
("char *", "char__ptr"),
|
|
25
|
+
("char **", "char__ptr__ptr"),
|
|
26
|
+
("_typedef", "_typedef"),
|
|
27
|
+
("__typedef", "__dundertypedef"),
|
|
28
|
+
("___typedef", "__dunder_typedef"),
|
|
29
|
+
("____typedef", "__dunder__dundertypedef"),
|
|
30
|
+
("_____typedef", "__dunder__dunder_typedef"),
|
|
31
|
+
("const __typedef", "__const___dundertypedef"),
|
|
32
|
+
("int[42]", "int__lArr42__rArr"),
|
|
33
|
+
("int[:]", "int__lArr__D__rArr"),
|
|
34
|
+
("int[:,:]", "int__lArr__D__comma___D__rArr"),
|
|
35
|
+
("int[:,:,:]", "int__lArr__D__comma___D__comma___D__rArr"),
|
|
36
|
+
("int[:,:,...]", "int__lArr__D__comma___D__comma___EL__rArr"),
|
|
37
|
+
("std::vector", "std__in_vector"),
|
|
38
|
+
("std::vector&&", "std__in_vector__fwref"),
|
|
39
|
+
("const std::vector", "__const_std__in_vector"),
|
|
40
|
+
("const std::vector&", "__const_std__in_vector__ref"),
|
|
41
|
+
("const_std", "const_std"),
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
def test_escape_special_type_characters(self):
|
|
45
|
+
test_func = PT._escape_special_type_characters # keep test usage visible for IDEs
|
|
46
|
+
function_name = "_escape_special_type_characters"
|
|
47
|
+
self._test_escape(function_name)
|
|
48
|
+
|
|
49
|
+
def test_type_identifier_for_declaration(self):
|
|
50
|
+
test_func = PT.type_identifier_from_declaration # keep test usage visible for IDEs
|
|
51
|
+
function_name = test_func.__name__
|
|
52
|
+
self._test_escape(function_name)
|
|
53
|
+
|
|
54
|
+
# differences due to whitespace removal
|
|
55
|
+
test_data = [
|
|
56
|
+
("const &std::vector", "const__refstd__in_vector"),
|
|
57
|
+
("const &std::vector<int>", "const__refstd__in_vector__lAngint__rAng"),
|
|
58
|
+
("const &&std::vector", "const__fwrefstd__in_vector"),
|
|
59
|
+
("const &&&std::vector", "const__fwref__refstd__in_vector"),
|
|
60
|
+
("const &&std::vector", "const__fwrefstd__in_vector"),
|
|
61
|
+
("void (*func)(int x, float y)",
|
|
62
|
+
"975d51__void__lParen__ptrfunc__rParen__lParenint__spac__etc"),
|
|
63
|
+
("float ** (*func)(int x, int[:] y)",
|
|
64
|
+
"31883a__float__ptr__ptr__lParen__ptrfunc__rParen__lPar__etc"),
|
|
65
|
+
]
|
|
66
|
+
self._test_escape(function_name, test_data)
|
|
67
|
+
|
|
68
|
+
def _test_escape(self, func_name, test_data=TEST_DATA):
|
|
69
|
+
escape = getattr(PT, func_name)
|
|
70
|
+
for declaration, expected in test_data:
|
|
71
|
+
escaped_value = escape(declaration)
|
|
72
|
+
self.assertEqual(escaped_value, expected, "%s('%s') == '%s' != '%s'" % (
|
|
73
|
+
func_name, declaration, escaped_value, expected))
|
|
74
|
+
# test that the length has been successfully capped
|
|
75
|
+
self.assertLessEqual(len(escaped_value), 64)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from Cython.Compiler import Code, UtilityCode
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def strip_2tup(tup):
|
|
7
|
+
return tup[0] and tup[0].strip(), tup[1] and tup[1].strip()
|
|
8
|
+
|
|
9
|
+
class TestUtilityLoader(unittest.TestCase):
|
|
10
|
+
"""
|
|
11
|
+
Test loading UtilityCodes
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
expected = "test {{loader}} prototype", "test {{loader}} impl"
|
|
15
|
+
|
|
16
|
+
required = "req {{loader}} proto", "req {{loader}} impl"
|
|
17
|
+
|
|
18
|
+
context = dict(loader='Loader')
|
|
19
|
+
|
|
20
|
+
name = "TestUtilityLoader"
|
|
21
|
+
filename = "TestUtilityLoader.c"
|
|
22
|
+
cls = Code.UtilityCode
|
|
23
|
+
|
|
24
|
+
def test_load_as_string(self):
|
|
25
|
+
got = strip_2tup(self.cls.load_as_string(self.name, self.filename))
|
|
26
|
+
self.assertEqual(got, self.expected)
|
|
27
|
+
|
|
28
|
+
def test_load(self):
|
|
29
|
+
utility = self.cls.load(self.name, from_file=self.filename)
|
|
30
|
+
got = strip_2tup((utility.proto, utility.impl))
|
|
31
|
+
self.assertEqual(got, self.expected)
|
|
32
|
+
|
|
33
|
+
required, = utility.requires
|
|
34
|
+
got = strip_2tup((required.proto, required.impl))
|
|
35
|
+
self.assertEqual(got, self.required)
|
|
36
|
+
|
|
37
|
+
utility = self.cls.load_cached(self.name, from_file=self.filename)
|
|
38
|
+
got = strip_2tup((utility.proto, utility.impl))
|
|
39
|
+
self.assertEqual(got, self.expected)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TestTempitaUtilityLoader(TestUtilityLoader):
|
|
43
|
+
"""
|
|
44
|
+
Test loading UtilityCodes with Tempita substitution
|
|
45
|
+
"""
|
|
46
|
+
expected_tempita = (TestUtilityLoader.expected[0].replace('{{loader}}', 'Loader'),
|
|
47
|
+
TestUtilityLoader.expected[1].replace('{{loader}}', 'Loader'))
|
|
48
|
+
|
|
49
|
+
required_tempita = (TestUtilityLoader.required[0].replace('{{loader}}', 'Loader'),
|
|
50
|
+
TestUtilityLoader.required[1].replace('{{loader}}', 'Loader'))
|
|
51
|
+
|
|
52
|
+
cls = Code.TempitaUtilityCode
|
|
53
|
+
|
|
54
|
+
def test_load_as_string(self):
|
|
55
|
+
got = strip_2tup(self.cls.load_as_string(self.name, self.filename, context=self.context))
|
|
56
|
+
self.assertEqual(got, self.expected_tempita)
|
|
57
|
+
|
|
58
|
+
def test_load(self):
|
|
59
|
+
utility = self.cls.load(self.name, self.filename, context=self.context)
|
|
60
|
+
got = strip_2tup((utility.proto, utility.impl))
|
|
61
|
+
self.assertEqual(got, self.expected_tempita)
|
|
62
|
+
|
|
63
|
+
required, = utility.requires
|
|
64
|
+
got = strip_2tup((required.proto, required.impl))
|
|
65
|
+
self.assertEqual(got, self.required_tempita)
|
|
66
|
+
|
|
67
|
+
utility = self.cls.load(self.name, from_file=self.filename, context=self.context)
|
|
68
|
+
got = strip_2tup((utility.proto, utility.impl))
|
|
69
|
+
self.assertEqual(got, self.expected_tempita)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class TestCythonUtilityLoader(TestTempitaUtilityLoader):
|
|
73
|
+
"""
|
|
74
|
+
Test loading CythonUtilityCodes
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
# Just change the attributes and run the same tests
|
|
78
|
+
expected = None, "test {{cy_loader}} impl"
|
|
79
|
+
expected_tempita = None, "test CyLoader impl"
|
|
80
|
+
|
|
81
|
+
required = None, "req {{cy_loader}} impl"
|
|
82
|
+
required_tempita = None, "req CyLoader impl"
|
|
83
|
+
|
|
84
|
+
context = dict(cy_loader='CyLoader')
|
|
85
|
+
|
|
86
|
+
name = "TestCyUtilityLoader"
|
|
87
|
+
filename = "TestCyUtilityLoader.pyx"
|
|
88
|
+
cls = UtilityCode.CythonUtilityCode
|
|
89
|
+
|
|
90
|
+
# Small hack to pass our tests above
|
|
91
|
+
cls.proto = None
|
|
92
|
+
|
|
93
|
+
test_load = TestUtilityLoader.test_load
|
|
94
|
+
test_load_tempita = TestTempitaUtilityLoader.test_load
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class TestUtilityCode(unittest.TestCase):
|
|
98
|
+
def test_equality(self):
|
|
99
|
+
c1 = Code.UtilityCode.load("NumpyImportUFunc", "NumpyImportArray.c")
|
|
100
|
+
c2 = Code.UtilityCode.load("NumpyImportArray", "NumpyImportArray.c")
|
|
101
|
+
c3 = Code.UtilityCode.load("pyunicode_strlen", "StringTools.c")
|
|
102
|
+
c4 = Code.UtilityCode.load("pyunicode_from_unicode", "StringTools.c")
|
|
103
|
+
c5 = Code.UtilityCode.load("IncludeStringH", "StringTools.c")
|
|
104
|
+
c6 = Code.UtilityCode.load("IncludeCppStringH", "StringTools.c")
|
|
105
|
+
|
|
106
|
+
codes = [c1, c2, c3, c4, c5, c6]
|
|
107
|
+
for m in range(len(codes)):
|
|
108
|
+
for n in range(len(codes)):
|
|
109
|
+
if n == m:
|
|
110
|
+
self.assertEqual(codes[m], codes[n])
|
|
111
|
+
else:
|
|
112
|
+
self.assertNotEqual(codes[m], codes[n])
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from Cython.Compiler.ModuleNode import ModuleNode
|
|
2
|
+
from Cython.Compiler.Symtab import ModuleScope
|
|
3
|
+
from Cython.TestUtils import TransformTest
|
|
4
|
+
from Cython.Compiler.Visitor import MethodDispatcherTransform
|
|
5
|
+
from Cython.Compiler.ParseTreeTransforms import (
|
|
6
|
+
NormalizeTree, AnalyseDeclarationsTransform,
|
|
7
|
+
AnalyseExpressionsTransform, InterpretCompilerDirectives)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestMethodDispatcherTransform(TransformTest):
|
|
11
|
+
_tree = None
|
|
12
|
+
|
|
13
|
+
def _build_tree(self):
|
|
14
|
+
if self._tree is None:
|
|
15
|
+
context = None
|
|
16
|
+
|
|
17
|
+
def fake_module(node):
|
|
18
|
+
scope = ModuleScope('test', None, None)
|
|
19
|
+
return ModuleNode(node.pos, doc=None, body=node,
|
|
20
|
+
scope=scope, full_module_name='test',
|
|
21
|
+
directive_comments={})
|
|
22
|
+
pipeline = [
|
|
23
|
+
fake_module,
|
|
24
|
+
NormalizeTree(context),
|
|
25
|
+
InterpretCompilerDirectives(context, {}),
|
|
26
|
+
AnalyseDeclarationsTransform(context),
|
|
27
|
+
AnalyseExpressionsTransform(context),
|
|
28
|
+
]
|
|
29
|
+
self._tree = self.run_pipeline(pipeline, """
|
|
30
|
+
cdef bytes s = b'asdfg'
|
|
31
|
+
cdef dict d = {1:2}
|
|
32
|
+
x = s * 3
|
|
33
|
+
d.get('test')
|
|
34
|
+
""")
|
|
35
|
+
return self._tree
|
|
36
|
+
|
|
37
|
+
def test_builtin_method(self):
|
|
38
|
+
calls = [0]
|
|
39
|
+
class Test(MethodDispatcherTransform):
|
|
40
|
+
def _handle_simple_method_dict_get(self, node, func, args, unbound):
|
|
41
|
+
calls[0] += 1
|
|
42
|
+
return node
|
|
43
|
+
|
|
44
|
+
tree = self._build_tree()
|
|
45
|
+
Test(None)(tree)
|
|
46
|
+
self.assertEqual(1, calls[0])
|
|
47
|
+
|
|
48
|
+
def test_binop_method(self):
|
|
49
|
+
calls = {'bytes': 0, 'object': 0}
|
|
50
|
+
class Test(MethodDispatcherTransform):
|
|
51
|
+
def _handle_simple_method_bytes___mul__(self, node, func, args, unbound):
|
|
52
|
+
calls['bytes'] += 1
|
|
53
|
+
return node
|
|
54
|
+
def _handle_simple_method_object___mul__(self, node, func, args, unbound):
|
|
55
|
+
calls['object'] += 1
|
|
56
|
+
return node
|
|
57
|
+
|
|
58
|
+
tree = self._build_tree()
|
|
59
|
+
Test(None)(tree)
|
|
60
|
+
self.assertEqual(1, calls['bytes'])
|
|
61
|
+
self.assertEqual(0, calls['object'])
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
|
|
3
|
+
from .. import Options
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def backup_Options():
|
|
7
|
+
backup = {}
|
|
8
|
+
for name, value in vars(Options).items():
|
|
9
|
+
# we need a deep copy of _directive_defaults, because they can be changed
|
|
10
|
+
if name == '_directive_defaults':
|
|
11
|
+
value = copy.deepcopy(value)
|
|
12
|
+
backup[name] = value
|
|
13
|
+
return backup
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def restore_Options(backup):
|
|
17
|
+
no_value = object()
|
|
18
|
+
for name, orig_value in backup.items():
|
|
19
|
+
if getattr(Options, name, no_value) != orig_value:
|
|
20
|
+
setattr(Options, name, orig_value)
|
|
21
|
+
# strip Options from new keys that might have been added:
|
|
22
|
+
for name in vars(Options).keys():
|
|
23
|
+
if name not in backup:
|
|
24
|
+
delattr(Options, name)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def check_global_options(expected_options, white_list=[]):
|
|
28
|
+
"""
|
|
29
|
+
returns error message of "" if check Ok
|
|
30
|
+
"""
|
|
31
|
+
no_value = object()
|
|
32
|
+
for name, orig_value in expected_options.items():
|
|
33
|
+
if name not in white_list:
|
|
34
|
+
if getattr(Options, name, no_value) != orig_value:
|
|
35
|
+
return "error in option " + name
|
|
36
|
+
return ""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# empty file
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
#
|
|
2
|
+
# TreeFragments - parsing of strings to trees
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Support for parsing strings into code trees.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
from io import StringIO
|
|
12
|
+
|
|
13
|
+
from .Scanning import PyrexScanner, StringSourceDescriptor
|
|
14
|
+
from .Symtab import ModuleScope
|
|
15
|
+
from . import PyrexTypes
|
|
16
|
+
from .Visitor import VisitorTransform
|
|
17
|
+
from .Nodes import Node, StatListNode
|
|
18
|
+
from .ExprNodes import NameNode
|
|
19
|
+
from . import Parsing
|
|
20
|
+
from . import Main
|
|
21
|
+
from . import UtilNodes
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class StringParseContext(Main.Context):
|
|
25
|
+
def __init__(self, name, include_directories=None, compiler_directives=None, cpp=False):
|
|
26
|
+
if include_directories is None:
|
|
27
|
+
include_directories = []
|
|
28
|
+
if compiler_directives is None:
|
|
29
|
+
compiler_directives = {}
|
|
30
|
+
Main.Context.__init__(self, include_directories, compiler_directives, cpp=cpp, language_level='3')
|
|
31
|
+
self.module_name = name
|
|
32
|
+
|
|
33
|
+
def find_module(self, module_name, from_module=None, pos=None, need_pxd=1, absolute_fallback=True, relative_import=False):
|
|
34
|
+
if module_name not in (self.module_name, 'cython'):
|
|
35
|
+
raise AssertionError("Not yet supporting any cimports/includes from string code snippets")
|
|
36
|
+
return ModuleScope(module_name, parent_module=None, context=self)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def parse_from_strings(name, code, pxds=None, level=None, initial_pos=None,
|
|
40
|
+
context=None, allow_struct_enum_decorator=False,
|
|
41
|
+
in_utility_code=False):
|
|
42
|
+
"""
|
|
43
|
+
Utility method to parse a (unicode) string of code. This is mostly
|
|
44
|
+
used for internal Cython compiler purposes (creating code snippets
|
|
45
|
+
that transforms should emit, as well as unit testing).
|
|
46
|
+
|
|
47
|
+
code - a unicode string containing Cython (module-level) code
|
|
48
|
+
name - a descriptive name for the code source (to use in error messages etc.)
|
|
49
|
+
in_utility_code - used to suppress some messages from utility code. False by default
|
|
50
|
+
because some generated code snippets like properties and dataclasses
|
|
51
|
+
probably want to see those messages.
|
|
52
|
+
|
|
53
|
+
RETURNS
|
|
54
|
+
|
|
55
|
+
The tree, i.e. a ModuleNode. The ModuleNode's scope attribute is
|
|
56
|
+
set to the scope used when parsing.
|
|
57
|
+
"""
|
|
58
|
+
if context is None:
|
|
59
|
+
context = StringParseContext(name)
|
|
60
|
+
# Since source files carry an encoding, it makes sense in this context
|
|
61
|
+
# to use a unicode string so that code fragments don't have to bother
|
|
62
|
+
# with encoding. This means that test code passed in should not have an
|
|
63
|
+
# encoding header.
|
|
64
|
+
assert isinstance(code, str), "unicode code snippets only please"
|
|
65
|
+
encoding = "UTF-8"
|
|
66
|
+
|
|
67
|
+
module_name = name
|
|
68
|
+
if initial_pos is None:
|
|
69
|
+
initial_pos = (name, 1, 0)
|
|
70
|
+
code_source = StringSourceDescriptor(name, code)
|
|
71
|
+
if in_utility_code:
|
|
72
|
+
code_source.in_utility_code = True
|
|
73
|
+
|
|
74
|
+
scope = context.find_module(module_name, pos=initial_pos, need_pxd=False)
|
|
75
|
+
|
|
76
|
+
buf = StringIO(code)
|
|
77
|
+
|
|
78
|
+
scanner = PyrexScanner(buf, code_source, source_encoding = encoding,
|
|
79
|
+
scope = scope, context = context, initial_pos = initial_pos)
|
|
80
|
+
ctx = Parsing.Ctx(allow_struct_enum_decorator=allow_struct_enum_decorator)
|
|
81
|
+
|
|
82
|
+
if level is None:
|
|
83
|
+
tree = Parsing.p_module(scanner, 0, module_name, ctx=ctx)
|
|
84
|
+
tree.scope = scope
|
|
85
|
+
tree.is_pxd = False
|
|
86
|
+
else:
|
|
87
|
+
tree = Parsing.p_code(scanner, level=level, ctx=ctx)
|
|
88
|
+
|
|
89
|
+
tree.scope = scope
|
|
90
|
+
return tree
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class TreeCopier(VisitorTransform):
|
|
94
|
+
def visit_Node(self, node):
|
|
95
|
+
if node is None:
|
|
96
|
+
return node
|
|
97
|
+
else:
|
|
98
|
+
c = node.clone_node()
|
|
99
|
+
self.visitchildren(c)
|
|
100
|
+
return c
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class ApplyPositionAndCopy(TreeCopier):
|
|
104
|
+
def __init__(self, pos):
|
|
105
|
+
super().__init__()
|
|
106
|
+
self.pos = pos
|
|
107
|
+
|
|
108
|
+
def visit_Node(self, node):
|
|
109
|
+
copy = super().visit_Node(node)
|
|
110
|
+
copy.pos = self.pos
|
|
111
|
+
return copy
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class TemplateTransform(VisitorTransform):
|
|
115
|
+
"""
|
|
116
|
+
Makes a copy of a template tree while doing substitutions.
|
|
117
|
+
|
|
118
|
+
A dictionary "substitutions" should be passed in when calling
|
|
119
|
+
the transform; mapping names to replacement nodes. Then replacement
|
|
120
|
+
happens like this:
|
|
121
|
+
- If an ExprStatNode contains a single NameNode, whose name is
|
|
122
|
+
a key in the substitutions dictionary, the ExprStatNode is
|
|
123
|
+
replaced with a copy of the tree given in the dictionary.
|
|
124
|
+
It is the responsibility of the caller that the replacement
|
|
125
|
+
node is a valid statement.
|
|
126
|
+
- If a single NameNode is otherwise encountered, it is replaced
|
|
127
|
+
if its name is listed in the substitutions dictionary in the
|
|
128
|
+
same way. It is the responsibility of the caller to make sure
|
|
129
|
+
that the replacement nodes is a valid expression.
|
|
130
|
+
|
|
131
|
+
Also a list "temps" should be passed. Any names listed will
|
|
132
|
+
be transformed into anonymous, temporary names.
|
|
133
|
+
|
|
134
|
+
Currently supported for tempnames is:
|
|
135
|
+
NameNode
|
|
136
|
+
(various function and class definition nodes etc. should be added to this)
|
|
137
|
+
|
|
138
|
+
Each replacement node gets the position of the substituted node
|
|
139
|
+
recursively applied to every member node.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
temp_name_counter = 0
|
|
143
|
+
|
|
144
|
+
def __call__(self, node, substitutions, temps, pos):
|
|
145
|
+
self.substitutions = substitutions
|
|
146
|
+
self.pos = pos
|
|
147
|
+
tempmap = {}
|
|
148
|
+
temphandles = []
|
|
149
|
+
for temp in temps:
|
|
150
|
+
TemplateTransform.temp_name_counter += 1
|
|
151
|
+
handle = UtilNodes.TempHandle(PyrexTypes.py_object_type)
|
|
152
|
+
tempmap[temp] = handle
|
|
153
|
+
temphandles.append(handle)
|
|
154
|
+
self.tempmap = tempmap
|
|
155
|
+
result = super().__call__(node)
|
|
156
|
+
if temps:
|
|
157
|
+
result = UtilNodes.TempsBlockNode(self.get_pos(node),
|
|
158
|
+
temps=temphandles,
|
|
159
|
+
body=result)
|
|
160
|
+
return result
|
|
161
|
+
|
|
162
|
+
def get_pos(self, node):
|
|
163
|
+
if self.pos:
|
|
164
|
+
return self.pos
|
|
165
|
+
else:
|
|
166
|
+
return node.pos
|
|
167
|
+
|
|
168
|
+
def visit_Node(self, node):
|
|
169
|
+
if node is None:
|
|
170
|
+
return None
|
|
171
|
+
else:
|
|
172
|
+
c = node.clone_node()
|
|
173
|
+
if self.pos is not None:
|
|
174
|
+
c.pos = self.pos
|
|
175
|
+
self.visitchildren(c)
|
|
176
|
+
return c
|
|
177
|
+
|
|
178
|
+
def try_substitution(self, node, key):
|
|
179
|
+
sub = self.substitutions.get(key)
|
|
180
|
+
if sub is not None:
|
|
181
|
+
pos = self.pos
|
|
182
|
+
if pos is None: pos = node.pos
|
|
183
|
+
return ApplyPositionAndCopy(pos)(sub)
|
|
184
|
+
else:
|
|
185
|
+
return self.visit_Node(node) # make copy as usual
|
|
186
|
+
|
|
187
|
+
def visit_NameNode(self, node):
|
|
188
|
+
temphandle = self.tempmap.get(node.name)
|
|
189
|
+
if temphandle:
|
|
190
|
+
# Replace name with temporary
|
|
191
|
+
return temphandle.ref(self.get_pos(node))
|
|
192
|
+
else:
|
|
193
|
+
return self.try_substitution(node, node.name)
|
|
194
|
+
|
|
195
|
+
def visit_ExprStatNode(self, node):
|
|
196
|
+
# If an expression-as-statement consists of only a replaceable
|
|
197
|
+
# NameNode, we replace the entire statement, not only the NameNode
|
|
198
|
+
if isinstance(node.expr, NameNode):
|
|
199
|
+
return self.try_substitution(node, node.expr.name)
|
|
200
|
+
else:
|
|
201
|
+
return self.visit_Node(node)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def copy_code_tree(node):
|
|
205
|
+
return TreeCopier()(node)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
_match_indent = re.compile("^ *").match
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def strip_common_indent(lines):
|
|
212
|
+
"""Strips empty lines and common indentation from the list of strings given in lines"""
|
|
213
|
+
# TODO: Facilitate textwrap.indent instead
|
|
214
|
+
lines = [x for x in lines if x.strip() != ""]
|
|
215
|
+
if lines:
|
|
216
|
+
minindent = min([len(_match_indent(x).group(0)) for x in lines])
|
|
217
|
+
lines = [x[minindent:] for x in lines]
|
|
218
|
+
return lines
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class TreeFragment:
|
|
222
|
+
def __init__(self, code, name=None, pxds=None, temps=None, pipeline=None, level=None, initial_pos=None):
|
|
223
|
+
if pxds is None:
|
|
224
|
+
pxds = {}
|
|
225
|
+
if temps is None:
|
|
226
|
+
temps = []
|
|
227
|
+
if pipeline is None:
|
|
228
|
+
pipeline = []
|
|
229
|
+
if not name:
|
|
230
|
+
name = "(tree fragment)"
|
|
231
|
+
|
|
232
|
+
if isinstance(code, str):
|
|
233
|
+
def fmt(x): return u"\n".join(strip_common_indent(x.split(u"\n")))
|
|
234
|
+
|
|
235
|
+
fmt_code = fmt(code)
|
|
236
|
+
fmt_pxds = {}
|
|
237
|
+
for key, value in pxds.items():
|
|
238
|
+
fmt_pxds[key] = fmt(value)
|
|
239
|
+
mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level, initial_pos=initial_pos)
|
|
240
|
+
if level is None:
|
|
241
|
+
t = t.body # Make sure a StatListNode is at the top
|
|
242
|
+
if not isinstance(t, StatListNode):
|
|
243
|
+
t = StatListNode(pos=mod.pos, stats=[t])
|
|
244
|
+
for transform in pipeline:
|
|
245
|
+
if transform is None:
|
|
246
|
+
continue
|
|
247
|
+
t = transform(t)
|
|
248
|
+
self.root = t
|
|
249
|
+
elif isinstance(code, Node):
|
|
250
|
+
if pxds:
|
|
251
|
+
raise NotImplementedError()
|
|
252
|
+
self.root = code
|
|
253
|
+
else:
|
|
254
|
+
raise ValueError("Unrecognized code format (accepts unicode and Node)")
|
|
255
|
+
self.temps = temps
|
|
256
|
+
|
|
257
|
+
def copy(self):
|
|
258
|
+
return copy_code_tree(self.root)
|
|
259
|
+
|
|
260
|
+
def substitute(self, nodes=None, temps=None, pos = None):
|
|
261
|
+
if nodes is None:
|
|
262
|
+
nodes = {}
|
|
263
|
+
if temps is None:
|
|
264
|
+
temps = []
|
|
265
|
+
return TemplateTransform()(self.root,
|
|
266
|
+
substitutions = nodes,
|
|
267
|
+
temps = self.temps + temps, pos = pos)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class SetPosTransform(VisitorTransform):
|
|
271
|
+
def __init__(self, pos):
|
|
272
|
+
super().__init__()
|
|
273
|
+
self.pos = pos
|
|
274
|
+
|
|
275
|
+
def visit_Node(self, node):
|
|
276
|
+
node.pos = self.pos
|
|
277
|
+
self.visitchildren(node)
|
|
278
|
+
return node
|