tnfr 4.5.0__py3-none-any.whl → 4.5.2__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.
Potentially problematic release.
This version of tnfr might be problematic. Click here for more details.
- tnfr/__init__.py +91 -89
- tnfr/alias.py +546 -0
- tnfr/cache.py +578 -0
- tnfr/callback_utils.py +388 -0
- tnfr/cli/__init__.py +75 -0
- tnfr/cli/arguments.py +177 -0
- tnfr/cli/execution.py +288 -0
- tnfr/cli/utils.py +36 -0
- tnfr/collections_utils.py +300 -0
- tnfr/config.py +19 -28
- tnfr/constants/__init__.py +174 -0
- tnfr/constants/core.py +159 -0
- tnfr/constants/init.py +31 -0
- tnfr/constants/metric.py +110 -0
- tnfr/constants_glyphs.py +98 -0
- tnfr/dynamics/__init__.py +658 -0
- tnfr/dynamics/dnfr.py +733 -0
- tnfr/dynamics/integrators.py +267 -0
- tnfr/dynamics/sampling.py +31 -0
- tnfr/execution.py +201 -0
- tnfr/flatten.py +283 -0
- tnfr/gamma.py +302 -88
- tnfr/glyph_history.py +290 -0
- tnfr/grammar.py +285 -96
- tnfr/graph_utils.py +84 -0
- tnfr/helpers/__init__.py +71 -0
- tnfr/helpers/numeric.py +87 -0
- tnfr/immutable.py +178 -0
- tnfr/import_utils.py +228 -0
- tnfr/initialization.py +197 -0
- tnfr/io.py +246 -0
- tnfr/json_utils.py +162 -0
- tnfr/locking.py +37 -0
- tnfr/logging_utils.py +116 -0
- tnfr/metrics/__init__.py +41 -0
- tnfr/metrics/coherence.py +829 -0
- tnfr/metrics/common.py +151 -0
- tnfr/metrics/core.py +101 -0
- tnfr/metrics/diagnosis.py +234 -0
- tnfr/metrics/export.py +137 -0
- tnfr/metrics/glyph_timing.py +189 -0
- tnfr/metrics/reporting.py +148 -0
- tnfr/metrics/sense_index.py +120 -0
- tnfr/metrics/trig.py +181 -0
- tnfr/metrics/trig_cache.py +109 -0
- tnfr/node.py +214 -159
- tnfr/observers.py +126 -128
- tnfr/ontosim.py +134 -134
- tnfr/operators/__init__.py +420 -0
- tnfr/operators/jitter.py +203 -0
- tnfr/operators/remesh.py +485 -0
- tnfr/presets.py +46 -14
- tnfr/rng.py +254 -0
- tnfr/selector.py +210 -0
- tnfr/sense.py +284 -131
- tnfr/structural.py +207 -79
- tnfr/tokens.py +60 -0
- tnfr/trace.py +329 -94
- tnfr/types.py +43 -17
- tnfr/validators.py +70 -24
- tnfr/value_utils.py +59 -0
- tnfr-4.5.2.dist-info/METADATA +379 -0
- tnfr-4.5.2.dist-info/RECORD +67 -0
- tnfr/cli.py +0 -322
- tnfr/constants.py +0 -277
- tnfr/dynamics.py +0 -814
- tnfr/helpers.py +0 -264
- tnfr/main.py +0 -47
- tnfr/metrics.py +0 -597
- tnfr/operators.py +0 -525
- tnfr/program.py +0 -176
- tnfr/scenarios.py +0 -34
- tnfr-4.5.0.dist-info/METADATA +0 -109
- tnfr-4.5.0.dist-info/RECORD +0 -28
- {tnfr-4.5.0.dist-info → tnfr-4.5.2.dist-info}/WHEEL +0 -0
- {tnfr-4.5.0.dist-info → tnfr-4.5.2.dist-info}/entry_points.txt +0 -0
- {tnfr-4.5.0.dist-info → tnfr-4.5.2.dist-info}/licenses/LICENSE.md +0 -0
- {tnfr-4.5.0.dist-info → tnfr-4.5.2.dist-info}/top_level.txt +0 -0
tnfr/structural.py
CHANGED
|
@@ -1,29 +1,23 @@
|
|
|
1
|
+
"""Structural analysis."""
|
|
2
|
+
|
|
1
3
|
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Este módulo ofrece:
|
|
5
|
-
- Factoría `create_nfr` para inicializar redes/nodos TNFR.
|
|
6
|
-
- Clases de operador (`Operador` y derivados) con interfaz común.
|
|
7
|
-
- Registro de operadores `OPERADORES`.
|
|
8
|
-
- Utilidades `validate_sequence` y `run_sequence` para ejecutar
|
|
9
|
-
secuencias canónicas de operadores.
|
|
10
|
-
"""
|
|
11
|
-
from typing import Iterable, Tuple, List
|
|
12
|
-
import networkx as nx
|
|
4
|
+
from typing import Iterable
|
|
5
|
+
import networkx as nx # type: ignore[import-untyped]
|
|
13
6
|
|
|
14
7
|
from .dynamics import (
|
|
15
8
|
set_delta_nfr_hook,
|
|
16
|
-
update_epi_via_nodal_equation,
|
|
17
9
|
dnfr_epi_vf_mixed,
|
|
18
10
|
)
|
|
19
|
-
from .
|
|
20
|
-
from .
|
|
11
|
+
from .grammar import apply_glyph_with_grammar
|
|
12
|
+
from .types import Glyph
|
|
13
|
+
from .constants import EPI_PRIMARY, VF_PRIMARY, THETA_PRIMARY
|
|
21
14
|
|
|
22
15
|
|
|
23
16
|
# ---------------------------------------------------------------------------
|
|
24
17
|
# 1) Factoría NFR
|
|
25
18
|
# ---------------------------------------------------------------------------
|
|
26
19
|
|
|
20
|
+
|
|
27
21
|
def create_nfr(
|
|
28
22
|
name: str,
|
|
29
23
|
*,
|
|
@@ -32,19 +26,19 @@ def create_nfr(
|
|
|
32
26
|
theta: float = 0.0,
|
|
33
27
|
graph: nx.Graph | None = None,
|
|
34
28
|
dnfr_hook=dnfr_epi_vf_mixed,
|
|
35
|
-
) ->
|
|
36
|
-
"""
|
|
29
|
+
) -> tuple[nx.Graph, str]:
|
|
30
|
+
"""Create a graph with an initialised NFR node.
|
|
37
31
|
|
|
38
|
-
|
|
32
|
+
Returns the tuple ``(G, name)`` for convenience.
|
|
39
33
|
"""
|
|
40
|
-
G = graph
|
|
34
|
+
G = graph if graph is not None else nx.Graph()
|
|
41
35
|
G.add_node(
|
|
42
36
|
name,
|
|
43
37
|
**{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
38
|
+
EPI_PRIMARY: float(epi),
|
|
39
|
+
VF_PRIMARY: float(vf),
|
|
40
|
+
THETA_PRIMARY: float(theta),
|
|
41
|
+
},
|
|
48
42
|
)
|
|
49
43
|
set_delta_nfr_hook(G, dnfr_hook)
|
|
50
44
|
return G, name
|
|
@@ -56,10 +50,11 @@ def create_nfr(
|
|
|
56
50
|
|
|
57
51
|
|
|
58
52
|
class Operador:
|
|
59
|
-
"""Base
|
|
53
|
+
"""Base class for TNFR operators.
|
|
60
54
|
|
|
61
|
-
|
|
62
|
-
canónico).
|
|
55
|
+
Each operator defines ``name`` (ASCII identifier) and ``glyph``
|
|
56
|
+
(símbolo TNFR canónico). Calling an instance applies the corresponding
|
|
57
|
+
symbol to the node.
|
|
63
58
|
"""
|
|
64
59
|
|
|
65
60
|
name = "operador"
|
|
@@ -67,96 +62,151 @@ class Operador:
|
|
|
67
62
|
|
|
68
63
|
def __call__(self, G: nx.Graph, node, **kw) -> None:
|
|
69
64
|
if self.glyph is None:
|
|
70
|
-
raise NotImplementedError("Operador sin
|
|
71
|
-
|
|
65
|
+
raise NotImplementedError("Operador sin glyph asignado")
|
|
66
|
+
apply_glyph_with_grammar(G, [node], self.glyph, kw.get("window"))
|
|
72
67
|
|
|
73
68
|
|
|
74
|
-
# Derivados concretos -------------------------------------------------------
|
|
75
69
|
class Emision(Operador):
|
|
70
|
+
"""Aplicación del operador de emisión (símbolo ``AL``)."""
|
|
71
|
+
|
|
72
|
+
__slots__ = ()
|
|
76
73
|
name = "emision"
|
|
77
|
-
glyph =
|
|
74
|
+
glyph = Glyph.AL.value
|
|
78
75
|
|
|
79
76
|
|
|
80
77
|
class Recepcion(Operador):
|
|
78
|
+
"""Operador de recepción (símbolo ``EN``)."""
|
|
79
|
+
|
|
80
|
+
__slots__ = ()
|
|
81
81
|
name = "recepcion"
|
|
82
|
-
glyph =
|
|
82
|
+
glyph = Glyph.EN.value
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
class Coherencia(Operador):
|
|
86
|
+
"""Operador de coherencia (símbolo ``IL``)."""
|
|
87
|
+
|
|
88
|
+
__slots__ = ()
|
|
86
89
|
name = "coherencia"
|
|
87
|
-
glyph =
|
|
90
|
+
glyph = Glyph.IL.value
|
|
88
91
|
|
|
89
92
|
|
|
90
93
|
class Disonancia(Operador):
|
|
94
|
+
"""Operador de disonancia (símbolo ``OZ``)."""
|
|
95
|
+
|
|
96
|
+
__slots__ = ()
|
|
91
97
|
name = "disonancia"
|
|
92
|
-
glyph =
|
|
98
|
+
glyph = Glyph.OZ.value
|
|
93
99
|
|
|
94
100
|
|
|
95
101
|
class Acoplamiento(Operador):
|
|
102
|
+
"""Operador de acoplamiento (símbolo ``UM``)."""
|
|
103
|
+
|
|
104
|
+
__slots__ = ()
|
|
96
105
|
name = "acoplamiento"
|
|
97
|
-
glyph =
|
|
106
|
+
glyph = Glyph.UM.value
|
|
98
107
|
|
|
99
108
|
|
|
100
109
|
class Resonancia(Operador):
|
|
110
|
+
"""Operador de resonancia (símbolo ``RA``)."""
|
|
111
|
+
|
|
112
|
+
__slots__ = ()
|
|
101
113
|
name = "resonancia"
|
|
102
|
-
glyph =
|
|
114
|
+
glyph = Glyph.RA.value
|
|
103
115
|
|
|
104
116
|
|
|
105
117
|
class Silencio(Operador):
|
|
118
|
+
"""Operador de silencio (símbolo ``SHA``)."""
|
|
119
|
+
|
|
120
|
+
__slots__ = ()
|
|
106
121
|
name = "silencio"
|
|
107
|
-
glyph =
|
|
122
|
+
glyph = Glyph.SHA.value
|
|
108
123
|
|
|
109
124
|
|
|
110
125
|
class Expansion(Operador):
|
|
126
|
+
"""Operador de expansión (símbolo ``VAL``)."""
|
|
127
|
+
|
|
128
|
+
__slots__ = ()
|
|
111
129
|
name = "expansion"
|
|
112
|
-
glyph =
|
|
130
|
+
glyph = Glyph.VAL.value
|
|
113
131
|
|
|
114
132
|
|
|
115
133
|
class Contraccion(Operador):
|
|
134
|
+
"""Operador de contracción (símbolo ``NUL``)."""
|
|
135
|
+
|
|
136
|
+
__slots__ = ()
|
|
116
137
|
name = "contraccion"
|
|
117
|
-
glyph =
|
|
138
|
+
glyph = Glyph.NUL.value
|
|
118
139
|
|
|
119
140
|
|
|
120
141
|
class Autoorganizacion(Operador):
|
|
142
|
+
"""Operador de autoorganización (símbolo ``THOL``)."""
|
|
143
|
+
|
|
144
|
+
__slots__ = ()
|
|
121
145
|
name = "autoorganizacion"
|
|
122
|
-
glyph =
|
|
146
|
+
glyph = Glyph.THOL.value
|
|
123
147
|
|
|
124
148
|
|
|
125
149
|
class Mutacion(Operador):
|
|
150
|
+
"""Operador de mutación (símbolo ``ZHIR``)."""
|
|
151
|
+
|
|
152
|
+
__slots__ = ()
|
|
126
153
|
name = "mutacion"
|
|
127
|
-
glyph =
|
|
154
|
+
glyph = Glyph.ZHIR.value
|
|
128
155
|
|
|
129
156
|
|
|
130
157
|
class Transicion(Operador):
|
|
158
|
+
"""Operador de transición (símbolo ``NAV``)."""
|
|
159
|
+
|
|
160
|
+
__slots__ = ()
|
|
131
161
|
name = "transicion"
|
|
132
|
-
glyph =
|
|
162
|
+
glyph = Glyph.NAV.value
|
|
133
163
|
|
|
134
164
|
|
|
135
165
|
class Recursividad(Operador):
|
|
166
|
+
"""Operador de recursividad (símbolo ``REMESH``)."""
|
|
167
|
+
|
|
168
|
+
__slots__ = ()
|
|
136
169
|
name = "recursividad"
|
|
137
|
-
glyph =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
OPERADORES = {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
Transicion,
|
|
155
|
-
Recursividad,
|
|
156
|
-
]
|
|
170
|
+
glyph = Glyph.REMESH.value
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
OPERADORES: dict[str, type[Operador]] = {
|
|
174
|
+
Emision.name: Emision,
|
|
175
|
+
Recepcion.name: Recepcion,
|
|
176
|
+
Coherencia.name: Coherencia,
|
|
177
|
+
Disonancia.name: Disonancia,
|
|
178
|
+
Acoplamiento.name: Acoplamiento,
|
|
179
|
+
Resonancia.name: Resonancia,
|
|
180
|
+
Silencio.name: Silencio,
|
|
181
|
+
Expansion.name: Expansion,
|
|
182
|
+
Contraccion.name: Contraccion,
|
|
183
|
+
Autoorganizacion.name: Autoorganizacion,
|
|
184
|
+
Mutacion.name: Mutacion,
|
|
185
|
+
Transicion.name: Transicion,
|
|
186
|
+
Recursividad.name: Recursividad,
|
|
157
187
|
}
|
|
158
188
|
|
|
159
189
|
|
|
190
|
+
__all__ = (
|
|
191
|
+
"create_nfr",
|
|
192
|
+
"Operador",
|
|
193
|
+
"Emision",
|
|
194
|
+
"Recepcion",
|
|
195
|
+
"Coherencia",
|
|
196
|
+
"Disonancia",
|
|
197
|
+
"Acoplamiento",
|
|
198
|
+
"Resonancia",
|
|
199
|
+
"Silencio",
|
|
200
|
+
"Expansion",
|
|
201
|
+
"Contraccion",
|
|
202
|
+
"Autoorganizacion",
|
|
203
|
+
"Mutacion",
|
|
204
|
+
"Transicion",
|
|
205
|
+
"Recursividad",
|
|
206
|
+
"OPERADORES",
|
|
207
|
+
"validate_sequence",
|
|
208
|
+
"run_sequence",
|
|
209
|
+
)
|
|
160
210
|
# ---------------------------------------------------------------------------
|
|
161
211
|
# 3) Motor de secuencias + validador sintáctico
|
|
162
212
|
# ---------------------------------------------------------------------------
|
|
@@ -167,35 +217,113 @@ _TRAMO_INTERMEDIO = {"disonancia", "acoplamiento", "resonancia"}
|
|
|
167
217
|
_CIERRE_VALIDO = {"silencio", "transicion", "recursividad"}
|
|
168
218
|
|
|
169
219
|
|
|
170
|
-
def
|
|
171
|
-
"""
|
|
220
|
+
def _validate_start(token: str) -> tuple[bool, str]:
|
|
221
|
+
"""Ensure the sequence begins with a valid structural operator."""
|
|
222
|
+
|
|
223
|
+
if not isinstance(token, str):
|
|
224
|
+
return False, "tokens must be str"
|
|
225
|
+
if token not in _INICIO_VALIDOS:
|
|
226
|
+
return False, "must start with emission or recursion"
|
|
227
|
+
return True, ""
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _validate_intermediate(
|
|
231
|
+
found_recepcion: bool, found_coherencia: bool, seen_intermedio: bool
|
|
232
|
+
) -> tuple[bool, str]:
|
|
233
|
+
"""Check that the central TNFR segment is present."""
|
|
234
|
+
|
|
235
|
+
if not (found_recepcion and found_coherencia):
|
|
236
|
+
return False, "missing input→coherence segment"
|
|
237
|
+
if not seen_intermedio:
|
|
238
|
+
return False, "missing tension/coupling/resonance segment"
|
|
239
|
+
return True, ""
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _validate_end(last_token: str, open_thol: bool) -> tuple[bool, str]:
|
|
243
|
+
"""Validate closing operator and any pending THOL blocks."""
|
|
244
|
+
|
|
245
|
+
if last_token not in _CIERRE_VALIDO:
|
|
246
|
+
return False, "sequence must end with silence/transition/recursion"
|
|
247
|
+
if open_thol:
|
|
248
|
+
return False, "THOL block without closure"
|
|
249
|
+
return True, ""
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _validate_known_tokens(nombres_set: set[str]) -> tuple[bool, str]:
|
|
253
|
+
"""Ensure all tokens map to canonical operators."""
|
|
254
|
+
|
|
255
|
+
desconocidos = nombres_set - OPERADORES.keys()
|
|
256
|
+
if desconocidos:
|
|
257
|
+
return False, f"unknown tokens: {', '.join(desconocidos)}"
|
|
258
|
+
return True, ""
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _validate_token_sequence(nombres: list[str]) -> tuple[bool, str]:
|
|
262
|
+
"""Validate token format and logical coherence in one pass."""
|
|
263
|
+
|
|
172
264
|
if not nombres:
|
|
173
|
-
return False, "
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
265
|
+
return False, "empty sequence"
|
|
266
|
+
|
|
267
|
+
ok, msg = _validate_start(nombres[0])
|
|
268
|
+
if not ok:
|
|
269
|
+
return False, msg
|
|
270
|
+
|
|
271
|
+
nombres_set: set[str] = set()
|
|
272
|
+
found_recepcion = False
|
|
273
|
+
found_coherencia = False
|
|
274
|
+
seen_intermedio = False
|
|
275
|
+
open_thol = False
|
|
276
|
+
|
|
277
|
+
for n in nombres:
|
|
278
|
+
if not isinstance(n, str):
|
|
279
|
+
return False, "tokens must be str"
|
|
280
|
+
nombres_set.add(n)
|
|
281
|
+
|
|
282
|
+
if n == "recepcion" and not found_recepcion:
|
|
283
|
+
found_recepcion = True
|
|
284
|
+
elif found_recepcion and n == "coherencia" and not found_coherencia:
|
|
285
|
+
found_coherencia = True
|
|
286
|
+
elif found_coherencia and not seen_intermedio and n in _TRAMO_INTERMEDIO:
|
|
287
|
+
seen_intermedio = True
|
|
288
|
+
|
|
289
|
+
if n == "autoorganizacion":
|
|
290
|
+
open_thol = True
|
|
291
|
+
elif open_thol and n in {"silencio", "contraccion"}:
|
|
292
|
+
open_thol = False
|
|
293
|
+
|
|
294
|
+
ok, msg = _validate_known_tokens(nombres_set)
|
|
295
|
+
if not ok:
|
|
296
|
+
return False, msg
|
|
297
|
+
ok, msg = _validate_intermediate(found_recepcion, found_coherencia, seen_intermedio)
|
|
298
|
+
if not ok:
|
|
299
|
+
return False, msg
|
|
300
|
+
ok, msg = _validate_end(nombres[-1], open_thol)
|
|
301
|
+
if not ok:
|
|
302
|
+
return False, msg
|
|
185
303
|
return True, "ok"
|
|
186
304
|
|
|
187
305
|
|
|
306
|
+
def validate_sequence(nombres: list[str]) -> tuple[bool, str]:
|
|
307
|
+
"""Validate minimal TNFR syntax rules."""
|
|
308
|
+
return _validate_token_sequence(nombres)
|
|
309
|
+
|
|
310
|
+
|
|
188
311
|
def run_sequence(G: nx.Graph, node, ops: Iterable[Operador]) -> None:
|
|
189
|
-
"""
|
|
312
|
+
"""Execute a sequence of operators on ``node`` after validation."""
|
|
313
|
+
|
|
314
|
+
compute = G.graph.get("compute_delta_nfr")
|
|
190
315
|
ops_list = list(ops)
|
|
191
316
|
nombres = [op.name for op in ops_list]
|
|
317
|
+
|
|
192
318
|
ok, msg = validate_sequence(nombres)
|
|
193
319
|
if not ok:
|
|
194
|
-
raise ValueError(f"
|
|
320
|
+
raise ValueError(f"Invalid sequence: {msg}")
|
|
321
|
+
|
|
195
322
|
for op in ops_list:
|
|
196
323
|
op(G, node)
|
|
197
|
-
compute = G.graph.get("compute_delta_nfr")
|
|
198
324
|
if callable(compute):
|
|
199
325
|
compute(G)
|
|
200
|
-
update_epi_via_nodal_equation
|
|
201
|
-
|
|
326
|
+
# ``update_epi_via_nodal_equation`` was previously invoked here to
|
|
327
|
+
# recalculate the EPI value after each operator. The responsibility for
|
|
328
|
+
# updating EPI now lies with the dynamics hook configured in
|
|
329
|
+
# ``compute_delta_nfr`` or with external callers.
|
tnfr/tokens.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Token primitives for the TNFR DSL."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from enum import Enum, auto
|
|
7
|
+
from typing import Any, Iterable, Optional, Sequence, Union
|
|
8
|
+
|
|
9
|
+
from .types import Glyph
|
|
10
|
+
|
|
11
|
+
Node = Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(slots=True)
|
|
15
|
+
class WAIT:
|
|
16
|
+
"""Wait a number of steps without applying glyphs."""
|
|
17
|
+
|
|
18
|
+
steps: int = 1
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(slots=True)
|
|
22
|
+
class TARGET:
|
|
23
|
+
"""Select the subset of nodes for subsequent glyphs."""
|
|
24
|
+
|
|
25
|
+
nodes: Optional[Iterable[Node]] = None # ``None`` targets all nodes
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(slots=True)
|
|
29
|
+
class THOL:
|
|
30
|
+
"""THOL block that opens self-organisation."""
|
|
31
|
+
|
|
32
|
+
body: Sequence[Any]
|
|
33
|
+
repeat: int = 1
|
|
34
|
+
force_close: Optional[Glyph] = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
Token = Union[Glyph, WAIT, TARGET, THOL, str]
|
|
38
|
+
|
|
39
|
+
# Sentinel used internally to mark the boundaries of a THOL block during flattening
|
|
40
|
+
THOL_SENTINEL = object()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class OpTag(Enum):
|
|
44
|
+
"""Operation tags emitted by the flattening step."""
|
|
45
|
+
|
|
46
|
+
TARGET = auto()
|
|
47
|
+
WAIT = auto()
|
|
48
|
+
GLYPH = auto()
|
|
49
|
+
THOL = auto()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
"Node",
|
|
54
|
+
"WAIT",
|
|
55
|
+
"TARGET",
|
|
56
|
+
"THOL",
|
|
57
|
+
"Token",
|
|
58
|
+
"THOL_SENTINEL",
|
|
59
|
+
"OpTag",
|
|
60
|
+
]
|