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
Cython/Plex/DFA.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# cython: auto_cpdef=True
|
|
2
|
+
"""
|
|
3
|
+
Python Lexical Analyser
|
|
4
|
+
|
|
5
|
+
Converting NFA to DFA
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import cython
|
|
9
|
+
from . import Machines
|
|
10
|
+
from .Machines import LOWEST_PRIORITY
|
|
11
|
+
from .Transitions import TransitionMap
|
|
12
|
+
|
|
13
|
+
if cython.compiled:
|
|
14
|
+
from cython.cimports.Cython.Plex.Machines import Node, FastMachine
|
|
15
|
+
from cython.cimports.Cython.Plex.Transitions import TransitionMap as type_TransitionMap
|
|
16
|
+
else:
|
|
17
|
+
from Cython.Plex.Machines import Node, FastMachine
|
|
18
|
+
from Cython.Plex.Transitions import TransitionMap as type_TransitionMap
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def nfa_to_dfa(old_machine, debug=None):
|
|
22
|
+
"""
|
|
23
|
+
Given a nondeterministic Machine, return a new equivalent
|
|
24
|
+
Machine which is deterministic.
|
|
25
|
+
"""
|
|
26
|
+
# We build a new machine whose states correspond to sets of states
|
|
27
|
+
# in the old machine. Initially we add a new state corresponding to
|
|
28
|
+
# the epsilon-closure of each initial old state. Then we give transitions
|
|
29
|
+
# to each new state which are the union of all transitions out of any
|
|
30
|
+
# of the corresponding old states. The new state reached on a given
|
|
31
|
+
# character is the one corresponding to the set of states reachable
|
|
32
|
+
# on that character from any of the old states. As new combinations of
|
|
33
|
+
# old states are created, new states are added as needed until closure
|
|
34
|
+
# is reached.
|
|
35
|
+
transitions: type_TransitionMap
|
|
36
|
+
new_machine: FastMachine = Machines.FastMachine()
|
|
37
|
+
state_map: StateMap = StateMap(new_machine)
|
|
38
|
+
|
|
39
|
+
# Seed the process using the initial states of the old machine.
|
|
40
|
+
# Make the corresponding new states into initial states of the new
|
|
41
|
+
# machine with the same names.
|
|
42
|
+
for (key, old_state) in old_machine.initial_states.items():
|
|
43
|
+
new_state = state_map.old_to_new(epsilon_closure(old_state))
|
|
44
|
+
new_machine.make_initial_state(key, new_state)
|
|
45
|
+
|
|
46
|
+
# Tricky bit here: we add things to the end of this list while we're
|
|
47
|
+
# iterating over it. The iteration stops when closure is achieved.
|
|
48
|
+
for new_state in new_machine.states:
|
|
49
|
+
transitions = TransitionMap()
|
|
50
|
+
for old_state in state_map.new_to_old(new_state):
|
|
51
|
+
for event, old_target_states in old_state.transitions.items():
|
|
52
|
+
if event and old_target_states:
|
|
53
|
+
transitions.add_set(event, set_epsilon_closure(old_target_states))
|
|
54
|
+
for event, old_states in transitions.items():
|
|
55
|
+
new_machine.add_transitions(new_state, event, state_map.old_to_new(old_states))
|
|
56
|
+
|
|
57
|
+
if debug:
|
|
58
|
+
debug.write("\n===== State Mapping =====\n")
|
|
59
|
+
state_map.dump(debug)
|
|
60
|
+
return new_machine
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@cython.cfunc
|
|
64
|
+
def set_epsilon_closure(state_set: set) -> set:
|
|
65
|
+
"""
|
|
66
|
+
Given a set of states, return the union of the epsilon
|
|
67
|
+
closures of its member states.
|
|
68
|
+
"""
|
|
69
|
+
result = set()
|
|
70
|
+
for state1 in state_set:
|
|
71
|
+
for state2 in epsilon_closure(state1):
|
|
72
|
+
result.add(state2)
|
|
73
|
+
return result
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@cython.cfunc
|
|
77
|
+
def epsilon_closure(state: Node) -> set:
|
|
78
|
+
"""
|
|
79
|
+
Return the set of states reachable from the given state
|
|
80
|
+
by epsilon moves.
|
|
81
|
+
"""
|
|
82
|
+
# Cache the result
|
|
83
|
+
result = state.epsilon_closure
|
|
84
|
+
if result is None:
|
|
85
|
+
result = set()
|
|
86
|
+
state.epsilon_closure = result
|
|
87
|
+
add_to_epsilon_closure(result, state)
|
|
88
|
+
return result
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@cython.cfunc
|
|
92
|
+
def add_to_epsilon_closure(state_set: set, state: Node):
|
|
93
|
+
"""
|
|
94
|
+
Recursively add to |state_set| states reachable from the given state
|
|
95
|
+
by epsilon moves.
|
|
96
|
+
"""
|
|
97
|
+
state_set_2: set
|
|
98
|
+
state2: Node
|
|
99
|
+
|
|
100
|
+
if state not in state_set:
|
|
101
|
+
state_set.add(state)
|
|
102
|
+
state_set_2 = state.transitions.get_epsilon()
|
|
103
|
+
if state_set_2:
|
|
104
|
+
for state2 in state_set_2:
|
|
105
|
+
add_to_epsilon_closure(state_set, state2)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class StateMap:
|
|
109
|
+
"""
|
|
110
|
+
Helper class used by nfa_to_dfa() to map back and forth between
|
|
111
|
+
sets of states from the old machine and states of the new machine.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def __init__(self, new_machine):
|
|
115
|
+
self.new_machine = new_machine # Machine
|
|
116
|
+
self.old_to_new_dict = {} # {(old_state,...) : new_state}
|
|
117
|
+
self.new_to_old_dict = {} # {id(new_state) : old_state_set}
|
|
118
|
+
|
|
119
|
+
def old_to_new(self, old_state_set: set):
|
|
120
|
+
"""
|
|
121
|
+
Return the state of the new machine corresponding to the
|
|
122
|
+
set of old machine states represented by |state_set|. A new
|
|
123
|
+
state will be created if necessary. If any of the old states
|
|
124
|
+
are accepting states, the new state will be an accepting state
|
|
125
|
+
with the highest priority action from the old states.
|
|
126
|
+
"""
|
|
127
|
+
key = self.make_key(old_state_set)
|
|
128
|
+
new_state = self.old_to_new_dict.get(key, None)
|
|
129
|
+
if not new_state:
|
|
130
|
+
action = self.highest_priority_action(old_state_set)
|
|
131
|
+
new_state = self.new_machine.new_state(action)
|
|
132
|
+
self.old_to_new_dict[key] = new_state
|
|
133
|
+
self.new_to_old_dict[id(new_state)] = old_state_set
|
|
134
|
+
return new_state
|
|
135
|
+
|
|
136
|
+
def highest_priority_action(self, state_set: set):
|
|
137
|
+
best_action = None
|
|
138
|
+
best_priority = LOWEST_PRIORITY
|
|
139
|
+
state: Node
|
|
140
|
+
for state in state_set:
|
|
141
|
+
priority = state.action_priority
|
|
142
|
+
if priority > best_priority:
|
|
143
|
+
best_action = state.action
|
|
144
|
+
best_priority = priority
|
|
145
|
+
return best_action
|
|
146
|
+
|
|
147
|
+
def new_to_old(self, new_state):
|
|
148
|
+
"""Given a new state, return a set of corresponding old states."""
|
|
149
|
+
return self.new_to_old_dict[id(new_state)]
|
|
150
|
+
|
|
151
|
+
def make_key(self, state_set: set):
|
|
152
|
+
"""
|
|
153
|
+
Convert a set of states into a uniquified
|
|
154
|
+
sorted tuple suitable for use as a dictionary key.
|
|
155
|
+
"""
|
|
156
|
+
return tuple(sorted(state_set))
|
|
157
|
+
|
|
158
|
+
def dump(self, file):
|
|
159
|
+
from .Transitions import state_set_str
|
|
160
|
+
|
|
161
|
+
for new_state in self.new_machine.states:
|
|
162
|
+
old_state_set = self.new_to_old_dict[id(new_state)]
|
|
163
|
+
file.write(" State %s <-- %s\n" % (
|
|
164
|
+
new_state['number'], state_set_str(old_state_set)))
|
Cython/Plex/DFA.pyd
ADDED
|
Binary file
|
Cython/Plex/Errors.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python Lexical Analyser
|
|
3
|
+
|
|
4
|
+
Exception classes
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PlexError(Exception):
|
|
9
|
+
message = ""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PlexTypeError(PlexError, TypeError):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PlexValueError(PlexError, ValueError):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class InvalidToken(PlexError):
|
|
21
|
+
def __init__(self, token_number, message):
|
|
22
|
+
PlexError.__init__(self, "Token number %d: %s" % (token_number, message))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class InvalidScanner(PlexError):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AmbiguousAction(PlexError):
|
|
30
|
+
message = "Two tokens with different actions can match the same string"
|
|
31
|
+
|
|
32
|
+
def __init__(self):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class UnrecognizedInput(PlexError):
|
|
37
|
+
scanner = None
|
|
38
|
+
position = None
|
|
39
|
+
state_name = None
|
|
40
|
+
|
|
41
|
+
def __init__(self, scanner, state_name):
|
|
42
|
+
self.scanner = scanner
|
|
43
|
+
self.position = scanner.get_position()
|
|
44
|
+
self.state_name = state_name
|
|
45
|
+
|
|
46
|
+
def __str__(self):
|
|
47
|
+
return ("'%s', line %d, char %d: Token not recognised in state %r" % (
|
|
48
|
+
self.position + (self.state_name,)))
|
Cython/Plex/Lexicons.py
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python Lexical Analyser
|
|
3
|
+
|
|
4
|
+
Lexical Analyser Specification
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from . import Actions
|
|
8
|
+
from . import DFA
|
|
9
|
+
from . import Errors
|
|
10
|
+
from . import Machines
|
|
11
|
+
from . import Regexps
|
|
12
|
+
|
|
13
|
+
# debug_flags for Lexicon constructor
|
|
14
|
+
DUMP_NFA = 1
|
|
15
|
+
DUMP_DFA = 2
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class State:
|
|
19
|
+
"""
|
|
20
|
+
This class is used as part of a Plex.Lexicon specification to
|
|
21
|
+
introduce a user-defined state.
|
|
22
|
+
|
|
23
|
+
Constructor:
|
|
24
|
+
|
|
25
|
+
State(name, token_specifications)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
name = None
|
|
29
|
+
tokens = None
|
|
30
|
+
|
|
31
|
+
def __init__(self, name, tokens):
|
|
32
|
+
self.name = name
|
|
33
|
+
self.tokens = tokens
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Lexicon:
|
|
37
|
+
"""
|
|
38
|
+
Lexicon(specification) builds a lexical analyser from the given
|
|
39
|
+
|specification|. The specification consists of a list of
|
|
40
|
+
specification items. Each specification item may be either:
|
|
41
|
+
|
|
42
|
+
1) A token definition, which is a tuple:
|
|
43
|
+
|
|
44
|
+
(pattern, action)
|
|
45
|
+
|
|
46
|
+
The |pattern| is a regular axpression built using the
|
|
47
|
+
constructors defined in the Plex module.
|
|
48
|
+
|
|
49
|
+
The |action| is the action to be performed when this pattern
|
|
50
|
+
is recognised (see below).
|
|
51
|
+
|
|
52
|
+
2) A state definition:
|
|
53
|
+
|
|
54
|
+
State(name, tokens)
|
|
55
|
+
|
|
56
|
+
where |name| is a character string naming the state,
|
|
57
|
+
and |tokens| is a list of token definitions as
|
|
58
|
+
above. The meaning and usage of states is described
|
|
59
|
+
below.
|
|
60
|
+
|
|
61
|
+
Actions
|
|
62
|
+
-------
|
|
63
|
+
|
|
64
|
+
The |action| in a token specification may be one of three things:
|
|
65
|
+
|
|
66
|
+
1) A function, which is called as follows:
|
|
67
|
+
|
|
68
|
+
function(scanner, text)
|
|
69
|
+
|
|
70
|
+
where |scanner| is the relevant Scanner instance, and |text|
|
|
71
|
+
is the matched text. If the function returns anything
|
|
72
|
+
other than None, that value is returned as the value of the
|
|
73
|
+
token. If it returns None, scanning continues as if the IGNORE
|
|
74
|
+
action were specified (see below).
|
|
75
|
+
|
|
76
|
+
2) One of the following special actions:
|
|
77
|
+
|
|
78
|
+
IGNORE means that the recognised characters will be treated as
|
|
79
|
+
white space and ignored. Scanning will continue until
|
|
80
|
+
the next non-ignored token is recognised before returning.
|
|
81
|
+
|
|
82
|
+
TEXT causes the scanned text itself to be returned as the
|
|
83
|
+
value of the token.
|
|
84
|
+
|
|
85
|
+
3) Any other value, which is returned as the value of the token.
|
|
86
|
+
|
|
87
|
+
States
|
|
88
|
+
------
|
|
89
|
+
|
|
90
|
+
At any given time, the scanner is in one of a number of states.
|
|
91
|
+
Associated with each state is a set of possible tokens. When scanning,
|
|
92
|
+
only tokens associated with the current state are recognised.
|
|
93
|
+
|
|
94
|
+
There is a default state, whose name is the empty string. Token
|
|
95
|
+
definitions which are not inside any State definition belong to
|
|
96
|
+
the default state.
|
|
97
|
+
|
|
98
|
+
The initial state of the scanner is the default state. The state can
|
|
99
|
+
be changed in one of two ways:
|
|
100
|
+
|
|
101
|
+
1) Using Begin(state_name) as the action of a token.
|
|
102
|
+
|
|
103
|
+
2) Calling the begin(state_name) method of the Scanner.
|
|
104
|
+
|
|
105
|
+
To change back to the default state, use '' as the state name.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
machine = None # Machine
|
|
109
|
+
tables = None # StateTableMachine
|
|
110
|
+
|
|
111
|
+
def __init__(self, specifications, debug=None, debug_flags=7):
|
|
112
|
+
if not isinstance(specifications, list):
|
|
113
|
+
raise Errors.InvalidScanner("Scanner definition is not a list")
|
|
114
|
+
|
|
115
|
+
nfa = Machines.Machine()
|
|
116
|
+
default_initial_state = nfa.new_initial_state('')
|
|
117
|
+
token_number = 1
|
|
118
|
+
|
|
119
|
+
for spec in specifications:
|
|
120
|
+
if isinstance(spec, State):
|
|
121
|
+
user_initial_state = nfa.new_initial_state(spec.name)
|
|
122
|
+
for token in spec.tokens:
|
|
123
|
+
self.add_token_to_machine(
|
|
124
|
+
nfa, user_initial_state, token, token_number)
|
|
125
|
+
token_number += 1
|
|
126
|
+
elif isinstance(spec, tuple):
|
|
127
|
+
self.add_token_to_machine(
|
|
128
|
+
nfa, default_initial_state, spec, token_number)
|
|
129
|
+
token_number += 1
|
|
130
|
+
else:
|
|
131
|
+
raise Errors.InvalidToken(
|
|
132
|
+
token_number,
|
|
133
|
+
"Expected a token definition (tuple) or State instance")
|
|
134
|
+
|
|
135
|
+
if debug and (debug_flags & 1):
|
|
136
|
+
debug.write("\n============= NFA ===========\n")
|
|
137
|
+
nfa.dump(debug)
|
|
138
|
+
|
|
139
|
+
dfa = DFA.nfa_to_dfa(nfa, debug=(debug_flags & 3) == 3 and debug)
|
|
140
|
+
|
|
141
|
+
if debug and (debug_flags & 2):
|
|
142
|
+
debug.write("\n============= DFA ===========\n")
|
|
143
|
+
dfa.dump(debug)
|
|
144
|
+
|
|
145
|
+
self.machine = dfa
|
|
146
|
+
|
|
147
|
+
def add_token_to_machine(self, machine, initial_state, token_spec, token_number):
|
|
148
|
+
try:
|
|
149
|
+
(re, action_spec) = self.parse_token_definition(token_spec)
|
|
150
|
+
if isinstance(action_spec, Actions.Action):
|
|
151
|
+
action = action_spec
|
|
152
|
+
else:
|
|
153
|
+
try:
|
|
154
|
+
action_spec.__call__
|
|
155
|
+
except AttributeError:
|
|
156
|
+
action = Actions.Return(action_spec)
|
|
157
|
+
else:
|
|
158
|
+
action = Actions.Call(action_spec)
|
|
159
|
+
final_state = machine.new_state()
|
|
160
|
+
re.build_machine(machine, initial_state, final_state,
|
|
161
|
+
match_bol=1, nocase=0)
|
|
162
|
+
final_state.set_action(action, priority=-token_number)
|
|
163
|
+
except Errors.PlexError as e:
|
|
164
|
+
raise e.__class__("Token number %d: %s" % (token_number, e))
|
|
165
|
+
|
|
166
|
+
def parse_token_definition(self, token_spec):
|
|
167
|
+
if not isinstance(token_spec, tuple):
|
|
168
|
+
raise Errors.InvalidToken("Token definition is not a tuple")
|
|
169
|
+
if len(token_spec) != 2:
|
|
170
|
+
raise Errors.InvalidToken("Wrong number of items in token definition")
|
|
171
|
+
|
|
172
|
+
pattern, action = token_spec
|
|
173
|
+
if not isinstance(pattern, Regexps.RE):
|
|
174
|
+
raise Errors.InvalidToken("Pattern is not an RE instance")
|
|
175
|
+
return (pattern, action)
|
|
176
|
+
|
|
177
|
+
def get_initial_state(self, name):
|
|
178
|
+
return self.machine.get_initial_state(name)
|
Cython/Plex/Machines.pxd
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
cimport cython
|
|
2
|
+
|
|
3
|
+
from .Actions cimport Action
|
|
4
|
+
from .Transitions cimport TransitionMap
|
|
5
|
+
|
|
6
|
+
cdef int maxint
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@cython.final
|
|
10
|
+
cdef class Machine:
|
|
11
|
+
cdef readonly list states
|
|
12
|
+
cdef readonly dict initial_states
|
|
13
|
+
cdef readonly Py_ssize_t next_state_number
|
|
14
|
+
|
|
15
|
+
cpdef new_state(self)
|
|
16
|
+
cpdef new_initial_state(self, name)
|
|
17
|
+
cpdef make_initial_state(self, name, state)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@cython.final
|
|
21
|
+
cdef class Node:
|
|
22
|
+
cdef readonly TransitionMap transitions
|
|
23
|
+
cdef readonly Action action
|
|
24
|
+
cdef public set epsilon_closure
|
|
25
|
+
cdef readonly Py_ssize_t number
|
|
26
|
+
cdef readonly int action_priority
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@cython.final
|
|
30
|
+
cdef class FastMachine:
|
|
31
|
+
cdef readonly dict initial_states
|
|
32
|
+
cdef readonly dict new_state_template
|
|
33
|
+
cdef readonly list states
|
|
34
|
+
cdef readonly Py_ssize_t next_number
|
|
35
|
+
|
|
36
|
+
cpdef make_initial_state(self, name, state)
|
Cython/Plex/Machines.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python Lexical Analyser
|
|
3
|
+
|
|
4
|
+
Classes for building NFAs and DFAs
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import cython
|
|
8
|
+
from .Transitions import TransitionMap
|
|
9
|
+
|
|
10
|
+
maxint = 2**31-1 # sentinel value
|
|
11
|
+
|
|
12
|
+
LOWEST_PRIORITY = -maxint
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Machine:
|
|
16
|
+
"""A collection of Nodes representing an NFA or DFA."""
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self.states = [] # [Node]
|
|
19
|
+
self.initial_states = {} # {(name, bol): Node}
|
|
20
|
+
self.next_state_number = 1
|
|
21
|
+
|
|
22
|
+
def __del__(self):
|
|
23
|
+
for state in self.states:
|
|
24
|
+
state.destroy()
|
|
25
|
+
|
|
26
|
+
def new_state(self):
|
|
27
|
+
"""Add a new state to the machine and return it."""
|
|
28
|
+
s = Node()
|
|
29
|
+
n: cython.Py_ssize_t = self.next_state_number
|
|
30
|
+
self.next_state_number = n + 1
|
|
31
|
+
s.number = n
|
|
32
|
+
self.states.append(s)
|
|
33
|
+
return s
|
|
34
|
+
|
|
35
|
+
def new_initial_state(self, name):
|
|
36
|
+
state = self.new_state()
|
|
37
|
+
self.make_initial_state(name, state)
|
|
38
|
+
return state
|
|
39
|
+
|
|
40
|
+
def make_initial_state(self, name, state):
|
|
41
|
+
self.initial_states[name] = state
|
|
42
|
+
|
|
43
|
+
def get_initial_state(self, name):
|
|
44
|
+
return self.initial_states[name]
|
|
45
|
+
|
|
46
|
+
def dump(self, file):
|
|
47
|
+
file.write("Plex.Machine:\n")
|
|
48
|
+
if self.initial_states is not None:
|
|
49
|
+
file.write(" Initial states:\n")
|
|
50
|
+
for (name, state) in sorted(self.initial_states.items()):
|
|
51
|
+
file.write(" '%s': %d\n" % (name, state.number))
|
|
52
|
+
for s in self.states:
|
|
53
|
+
s.dump(file)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class Node:
|
|
57
|
+
"""A state of an NFA or DFA."""
|
|
58
|
+
|
|
59
|
+
def __init__(self):
|
|
60
|
+
# Preinitialise the list of empty transitions, because
|
|
61
|
+
# the nfa-to-dfa algorithm needs it
|
|
62
|
+
self.transitions = TransitionMap() # TransitionMap
|
|
63
|
+
self.action_priority = LOWEST_PRIORITY # integer
|
|
64
|
+
self.action = None # Action
|
|
65
|
+
self.number = 0 # for debug output
|
|
66
|
+
self.epsilon_closure = None # used by nfa_to_dfa()
|
|
67
|
+
|
|
68
|
+
def destroy(self):
|
|
69
|
+
self.transitions = None
|
|
70
|
+
self.action = None
|
|
71
|
+
self.epsilon_closure = None
|
|
72
|
+
|
|
73
|
+
def add_transition(self, event, new_state):
|
|
74
|
+
self.transitions.add(event, new_state)
|
|
75
|
+
|
|
76
|
+
def link_to(self, state):
|
|
77
|
+
"""Add an epsilon-move from this state to another state."""
|
|
78
|
+
self.add_transition('', state)
|
|
79
|
+
|
|
80
|
+
def set_action(self, action, priority):
|
|
81
|
+
"""Make this an accepting state with the given action. If
|
|
82
|
+
there is already an action, choose the action with highest
|
|
83
|
+
priority."""
|
|
84
|
+
if priority > self.action_priority:
|
|
85
|
+
self.action = action
|
|
86
|
+
self.action_priority = priority
|
|
87
|
+
|
|
88
|
+
def get_action(self):
|
|
89
|
+
return self.action
|
|
90
|
+
|
|
91
|
+
def get_action_priority(self):
|
|
92
|
+
return self.action_priority
|
|
93
|
+
|
|
94
|
+
def is_accepting(self):
|
|
95
|
+
return self.action is not None
|
|
96
|
+
|
|
97
|
+
def __str__(self):
|
|
98
|
+
return "State %d" % self.number
|
|
99
|
+
|
|
100
|
+
def dump(self, file):
|
|
101
|
+
# Header
|
|
102
|
+
file.write(" State %d:\n" % self.number)
|
|
103
|
+
# Transitions
|
|
104
|
+
# self.dump_transitions(file)
|
|
105
|
+
self.transitions.dump(file)
|
|
106
|
+
# Action
|
|
107
|
+
action = self.action
|
|
108
|
+
priority = self.action_priority
|
|
109
|
+
if action is not None:
|
|
110
|
+
file.write(" %s [priority %d]\n" % (action, priority))
|
|
111
|
+
|
|
112
|
+
def __lt__(self, other):
|
|
113
|
+
return self.number < other.number
|
|
114
|
+
|
|
115
|
+
def __hash__(self):
|
|
116
|
+
# Prevent overflowing hash values due to arbitrarily large unsigned addresses.
|
|
117
|
+
return id(self) & maxint
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class FastMachine:
|
|
121
|
+
"""
|
|
122
|
+
FastMachine is a deterministic machine represented in a way that
|
|
123
|
+
allows fast scanning.
|
|
124
|
+
"""
|
|
125
|
+
def __init__(self):
|
|
126
|
+
self.initial_states = {} # {state_name:state}
|
|
127
|
+
self.states = [] # [state] where state = {event:state, 'else':state, 'action':Action}
|
|
128
|
+
self.next_number = 1 # for debugging
|
|
129
|
+
self.new_state_template = {
|
|
130
|
+
'': None, 'bol': None, 'eol': None, 'eof': None, 'else': None
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
def __del__(self):
|
|
134
|
+
for state in self.states:
|
|
135
|
+
state.clear()
|
|
136
|
+
|
|
137
|
+
def new_state(self, action=None):
|
|
138
|
+
number: cython.Py_ssize_t = self.next_number
|
|
139
|
+
self.next_number = number + 1
|
|
140
|
+
result = self.new_state_template.copy()
|
|
141
|
+
result['number'] = number
|
|
142
|
+
result['action'] = action
|
|
143
|
+
self.states.append(result)
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
def make_initial_state(self, name, state):
|
|
147
|
+
self.initial_states[name] = state
|
|
148
|
+
|
|
149
|
+
def add_transitions(self, state: dict, event, new_state, maxint: cython.int = maxint):
|
|
150
|
+
code: cython.int
|
|
151
|
+
code0: cython.int
|
|
152
|
+
code1: cython.int
|
|
153
|
+
|
|
154
|
+
if type(event) is tuple:
|
|
155
|
+
code0, code1 = event
|
|
156
|
+
if code0 == -maxint:
|
|
157
|
+
state['else'] = new_state
|
|
158
|
+
elif code1 != maxint:
|
|
159
|
+
for code in range(code0, code1):
|
|
160
|
+
state[chr(code)] = new_state
|
|
161
|
+
else:
|
|
162
|
+
state[event] = new_state
|
|
163
|
+
|
|
164
|
+
def get_initial_state(self, name):
|
|
165
|
+
return self.initial_states[name]
|
|
166
|
+
|
|
167
|
+
def dump(self, file):
|
|
168
|
+
file.write("Plex.FastMachine:\n")
|
|
169
|
+
file.write(" Initial states:\n")
|
|
170
|
+
for name, state in sorted(self.initial_states.items()):
|
|
171
|
+
file.write(" %s: %s\n" % (repr(name), state['number']))
|
|
172
|
+
for state in self.states:
|
|
173
|
+
self.dump_state(state, file)
|
|
174
|
+
|
|
175
|
+
def dump_state(self, state, file):
|
|
176
|
+
# Header
|
|
177
|
+
file.write(" State %d:\n" % state['number'])
|
|
178
|
+
# Transitions
|
|
179
|
+
self.dump_transitions(state, file)
|
|
180
|
+
# Action
|
|
181
|
+
action = state['action']
|
|
182
|
+
if action is not None:
|
|
183
|
+
file.write(" %s\n" % action)
|
|
184
|
+
|
|
185
|
+
def dump_transitions(self, state, file):
|
|
186
|
+
chars_leading_to_state = {}
|
|
187
|
+
special_to_state = {}
|
|
188
|
+
for (c, s) in state.items():
|
|
189
|
+
if len(c) == 1:
|
|
190
|
+
chars = chars_leading_to_state.get(id(s))
|
|
191
|
+
if chars is None:
|
|
192
|
+
chars = []
|
|
193
|
+
chars_leading_to_state[id(s)] = chars
|
|
194
|
+
chars.append(c)
|
|
195
|
+
elif len(c) <= 4:
|
|
196
|
+
special_to_state[c] = s
|
|
197
|
+
ranges_to_state = {}
|
|
198
|
+
for state in self.states:
|
|
199
|
+
char_list = chars_leading_to_state.get(id(state))
|
|
200
|
+
if char_list:
|
|
201
|
+
ranges = self.chars_to_ranges(char_list)
|
|
202
|
+
ranges_to_state[ranges] = state
|
|
203
|
+
for ranges in sorted(ranges_to_state):
|
|
204
|
+
key = self.ranges_to_string(ranges)
|
|
205
|
+
state = ranges_to_state[ranges]
|
|
206
|
+
file.write(" %s --> State %d\n" % (key, state['number']))
|
|
207
|
+
for key in ('bol', 'eol', 'eof', 'else'):
|
|
208
|
+
state = special_to_state.get(key)
|
|
209
|
+
if state:
|
|
210
|
+
file.write(" %s --> State %d\n" % (key, state['number']))
|
|
211
|
+
|
|
212
|
+
def chars_to_ranges(self, char_list: list) -> tuple:
|
|
213
|
+
char_list.sort()
|
|
214
|
+
|
|
215
|
+
c1: cython.Py_UCS4
|
|
216
|
+
c2: cython.Py_UCS4
|
|
217
|
+
i: cython.Py_ssize_t = 0
|
|
218
|
+
n: cython.Py_ssize_t = len(char_list)
|
|
219
|
+
result = []
|
|
220
|
+
while i < n:
|
|
221
|
+
c1 = ord(char_list[i])
|
|
222
|
+
c2 = c1
|
|
223
|
+
i += 1
|
|
224
|
+
while i < n and ord(char_list[i]) == c2 + 1:
|
|
225
|
+
i += 1
|
|
226
|
+
c2 += 1
|
|
227
|
+
result.append((chr(c1), chr(c2)))
|
|
228
|
+
return tuple(result)
|
|
229
|
+
|
|
230
|
+
def ranges_to_string(self, range_list) -> str:
|
|
231
|
+
return ','.join(map(self.range_to_string, range_list))
|
|
232
|
+
|
|
233
|
+
def range_to_string(self, range_tuple: tuple):
|
|
234
|
+
(c1, c2) = range_tuple
|
|
235
|
+
if c1 == c2:
|
|
236
|
+
return repr(c1)
|
|
237
|
+
else:
|
|
238
|
+
return f"{c1!r}..{c2!r}"
|
Cython/Plex/Machines.pyd
ADDED
|
Binary file
|