llparse 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- llparse/C_compiler.py +204 -0
- llparse/__init__.py +2 -0
- llparse/compilator.py +1190 -0
- llparse/constants.py +48 -0
- llparse/cython_builder.py +311 -0
- llparse/debug.py +23 -0
- llparse/dot.py +213 -0
- llparse/enumerator.py +20 -0
- llparse/frontend.py +527 -0
- llparse/header.py +89 -0
- llparse/llparse.py +150 -0
- llparse/pybuilder/__init__.py +2 -0
- llparse/pybuilder/builder.py +318 -0
- llparse/pybuilder/loopchecker.py +246 -0
- llparse/pybuilder/main_code.py +548 -0
- llparse/pybuilder/parsemap.py +37 -0
- llparse/pyfront/containers.py +33 -0
- llparse/pyfront/front.py +189 -0
- llparse/pyfront/implementation.py +98 -0
- llparse/pyfront/namespace.py +1 -0
- llparse/pyfront/nodes.py +243 -0
- llparse/pyfront/peephole.py +45 -0
- llparse/pyfront/transform.py +21 -0
- llparse/settings.py +285 -0
- llparse/spanalloc.py +176 -0
- llparse/test.py +232 -0
- llparse/tire.py +158 -0
- llparse/trie.py +165 -0
- llparse-0.1.0.dist-info/METADATA +129 -0
- llparse-0.1.0.dist-info/RECORD +33 -0
- llparse-0.1.0.dist-info/WHEEL +5 -0
- llparse-0.1.0.dist-info/licenses/LICENSE +21 -0
- llparse-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Optional, TypeVar, Union
|
|
4
|
+
|
|
5
|
+
Signature = ["match", "value"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def toBuffer(value: Union[str, int]):
|
|
9
|
+
if isinstance(value, str):
|
|
10
|
+
res = value
|
|
11
|
+
else:
|
|
12
|
+
assert 0 <= value and value <= 0xFF
|
|
13
|
+
res = [value]
|
|
14
|
+
assert len(res) >= 1
|
|
15
|
+
return res
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# TODO Add text validataion...
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def validate_text(init):
|
|
22
|
+
def is_valid(args, kwargs):
|
|
23
|
+
if kwargs.get("field"):
|
|
24
|
+
field = kwargs["field"]
|
|
25
|
+
if re.search(r"[//\s\\]+", field):
|
|
26
|
+
raise TypeError(
|
|
27
|
+
f'Can\'t access internal field because the field: "{field}" conatins invalid characters'
|
|
28
|
+
)
|
|
29
|
+
return init(args, kwargs)
|
|
30
|
+
|
|
31
|
+
return is_valid
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Code:
|
|
35
|
+
def __init__(self, signature: str, name: str) -> None:
|
|
36
|
+
assert signature in Signature
|
|
37
|
+
|
|
38
|
+
self.signature = signature
|
|
39
|
+
self.name = name
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Field(Code):
|
|
43
|
+
def __init__(self, signature: str, name: str, field: str) -> None:
|
|
44
|
+
self.field = field
|
|
45
|
+
# if re.search(r"[//\s\\]+",field):
|
|
46
|
+
# raise TypeError(f"Can\'t access internal field from user code because the field: {name} conatins invalid characters")
|
|
47
|
+
super().__init__(signature, name + "_" + field)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class FieldValue(Field):
|
|
51
|
+
# NOTE I Added for typehinting Here as it refuses to show up on the ide I'm using (Vizonex)
|
|
52
|
+
|
|
53
|
+
def __init__(self, signature: str, name: str, field: str, value: int) -> None:
|
|
54
|
+
self.value = value
|
|
55
|
+
self.field = field
|
|
56
|
+
super().__init__(signature, name, field)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class And(FieldValue):
|
|
60
|
+
def __init__(self, field: str, value: int) -> None:
|
|
61
|
+
super().__init__("match", "and", field, value)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class IsEqual(FieldValue):
|
|
65
|
+
def __init__(self, field: str, value: int) -> None:
|
|
66
|
+
super().__init__("match", "is_equal", field, value)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Load(Field):
|
|
70
|
+
def __init__(self, field: str) -> None:
|
|
71
|
+
super().__init__("match", "load", field)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class _Match(Code):
|
|
75
|
+
"""Refers to the Code's Match Not the Node's Match"""
|
|
76
|
+
|
|
77
|
+
def __init__(self, name: str) -> None:
|
|
78
|
+
super().__init__("match", name)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class IMulAddOptions:
|
|
83
|
+
base: int
|
|
84
|
+
max: int
|
|
85
|
+
signed: bool = False
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class MulAdd(Field):
|
|
89
|
+
def __init__(self, field: str, base: int, max: int, signed: bool = False) -> None:
|
|
90
|
+
self.options = IMulAddOptions(base, max, signed)
|
|
91
|
+
super().__init__("value", "mul_add", field)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Or(FieldValue):
|
|
95
|
+
def __init__(self, field: str, value: int) -> None:
|
|
96
|
+
super().__init__("match", "or", field, value)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# class Span(Match):
|
|
100
|
+
# def __init__(self, name: str) -> None:
|
|
101
|
+
# super().__init__(name)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class Store(Field):
|
|
105
|
+
def __init__(self, field: str) -> None:
|
|
106
|
+
self.field = field
|
|
107
|
+
super().__init__("value", "store", field)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class Test(FieldValue):
|
|
111
|
+
def __init__(self, field: str, value: int) -> None:
|
|
112
|
+
super().__init__("match", "test", field, value)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class Update(FieldValue):
|
|
116
|
+
def __init__(self, field: str, value: int) -> None:
|
|
117
|
+
super().__init__("match", "update", field, value)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class Value(Code):
|
|
121
|
+
def __init__(self, name: str) -> None:
|
|
122
|
+
super().__init__("value", name)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Nodes...
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class Node:
|
|
129
|
+
def __init__(self, name: str) -> None:
|
|
130
|
+
self.name = name
|
|
131
|
+
self.otherwiseEdge: Optional["Edge"] = None
|
|
132
|
+
self.privEdges: list["Edge"] = []
|
|
133
|
+
|
|
134
|
+
def __hash__(self) -> int:
|
|
135
|
+
return hash(self.name)
|
|
136
|
+
|
|
137
|
+
def otherwise(self, node: "Node"):
|
|
138
|
+
if self.otherwiseEdge:
|
|
139
|
+
raise TypeError("Node Already has an 'otherwise' or 'skipto'")
|
|
140
|
+
self.otherwiseEdge = Edge(node, True, None, None)
|
|
141
|
+
return self
|
|
142
|
+
|
|
143
|
+
def skipTo(self, node: "Node"):
|
|
144
|
+
if self.otherwiseEdge:
|
|
145
|
+
raise TypeError("Node Already has an 'otherwise' or 'skipto'")
|
|
146
|
+
self.otherwiseEdge = Edge(node, False, None, None)
|
|
147
|
+
return self
|
|
148
|
+
|
|
149
|
+
def getOtherwiseEdge(self):
|
|
150
|
+
return self.otherwiseEdge
|
|
151
|
+
|
|
152
|
+
def getEdges(self):
|
|
153
|
+
"""Returns non if object is empty"""
|
|
154
|
+
return None if self.privEdges == [] else self.privEdges
|
|
155
|
+
|
|
156
|
+
def getAllEdges(self):
|
|
157
|
+
r"Get list of all edges (including otherwise, if present)"
|
|
158
|
+
res = self.privEdges
|
|
159
|
+
if not self.otherwiseEdge:
|
|
160
|
+
return res
|
|
161
|
+
else:
|
|
162
|
+
# Concate DO NOT ADD TO RES!!!!
|
|
163
|
+
|
|
164
|
+
return res + [self.otherwiseEdge]
|
|
165
|
+
|
|
166
|
+
def __iter__(self):
|
|
167
|
+
if self.privEdges != []:
|
|
168
|
+
for e in self.privEdges:
|
|
169
|
+
yield e
|
|
170
|
+
|
|
171
|
+
def addEdge(self, edge: "Edge"):
|
|
172
|
+
assert isinstance(edge.key, (int, str)) or edge.key
|
|
173
|
+
|
|
174
|
+
if len(self.privEdges) > 0:
|
|
175
|
+
assert edge.key not in [e.key for e in self.privEdges]
|
|
176
|
+
self.privEdges.insert(0, edge)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# TODO Add strict type checking to \"Pause.__init__\"" parameters to prevent the
|
|
180
|
+
# bypassing arbtrary values
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class Pause(Node):
|
|
184
|
+
def __init__(self, code: int, reason: str) -> None:
|
|
185
|
+
self.code = code
|
|
186
|
+
self.reason = reason
|
|
187
|
+
super().__init__("pause")
|
|
188
|
+
|
|
189
|
+
def skipTo(self, node: "Node"):
|
|
190
|
+
"""`WARNING!` `Pause.skipTo()` IS NOT SUPPORTED AND WILL IMMEDIATELY THROW AN `Execption` IF YOU DO IT"""
|
|
191
|
+
raise Exception("Not supported in Pause Class, please use '.otherwise'")
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class Comsume(Node):
|
|
195
|
+
def __init__(self, field: str) -> None:
|
|
196
|
+
self.field = field
|
|
197
|
+
super().__init__("consume_" + field)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class Error(Node):
|
|
201
|
+
def __init__(self, code: int, reason: str) -> None:
|
|
202
|
+
super().__init__("error")
|
|
203
|
+
# print(code)
|
|
204
|
+
assert isinstance(code, int), "code is supposed to be an int not %s" % (
|
|
205
|
+
type(code).__name__
|
|
206
|
+
)
|
|
207
|
+
self.code = code
|
|
208
|
+
self.reason = reason
|
|
209
|
+
|
|
210
|
+
def otherwise(self, node: "Node"):
|
|
211
|
+
raise TypeError("Not Supported")
|
|
212
|
+
|
|
213
|
+
def skipTo(self, node: "Node"):
|
|
214
|
+
raise TypeError("Not Supported")
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class Invoke(Node):
|
|
218
|
+
def __init__(self, code: Code, IInvokeMap: dict[int, Node]) -> None:
|
|
219
|
+
self.code = code
|
|
220
|
+
super().__init__("invoke_" + code.name)
|
|
221
|
+
for numKey, targetNode in IInvokeMap.items():
|
|
222
|
+
if isinstance(numKey, int) and targetNode is None:
|
|
223
|
+
raise TypeError(
|
|
224
|
+
"Invoke's map keys must be integers and values must not be left blank!"
|
|
225
|
+
)
|
|
226
|
+
self.addEdge(Edge(targetNode, True, numKey, None))
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
# -- Transfroms --
|
|
230
|
+
|
|
231
|
+
TransformName = ["to_lower_unsafe", "to_lower"]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class Transform:
|
|
235
|
+
def __init__(self, name: str) -> None:
|
|
236
|
+
assert name in TransformName
|
|
237
|
+
self.name = name
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class ToLower(Transform):
|
|
241
|
+
def __init__(self) -> None:
|
|
242
|
+
super().__init__("to_lower")
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class ToLowerUnsafe(Transform):
|
|
246
|
+
def __init__(self) -> None:
|
|
247
|
+
super().__init__("to_lower_unsafe")
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
class TransfromCreator:
|
|
251
|
+
"""API For Character transformations used in::
|
|
252
|
+
|
|
253
|
+
p.node().transform(...)"""
|
|
254
|
+
|
|
255
|
+
def toLowerUnsafe(self):
|
|
256
|
+
return ToLowerUnsafe()
|
|
257
|
+
|
|
258
|
+
def toLower(self):
|
|
259
|
+
return ToLower()
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# def toBuffer(value:Union[int,str,bytes]) -> bytes:
|
|
263
|
+
# """Returns a bytes to use when making switch cases in C..."""
|
|
264
|
+
# if isinstance(value,bytes):
|
|
265
|
+
# res = value
|
|
266
|
+
# elif isinstance(value,str):
|
|
267
|
+
# res = value.encode("utf-8","surrogateescape")
|
|
268
|
+
# else:
|
|
269
|
+
# if not (0 <= value and value <= 0xff):
|
|
270
|
+
# raise BufferError("Invalid byte value")
|
|
271
|
+
# res = chr(value).encode("utf-8","surrogateescape")
|
|
272
|
+
# if len(res) >= 1:
|
|
273
|
+
# raise AssertionError("Invalid key length")
|
|
274
|
+
# return res
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
MatchSingleValue = TypeVar("MatchSingleValue", str, int, bytes)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class Edge:
|
|
281
|
+
def __init__(
|
|
282
|
+
self,
|
|
283
|
+
node: Node,
|
|
284
|
+
noAdvance: bool,
|
|
285
|
+
key: Optional[Union[int, str]],
|
|
286
|
+
value: Optional[int],
|
|
287
|
+
) -> None:
|
|
288
|
+
self.node = node
|
|
289
|
+
self.noAdvance = noAdvance
|
|
290
|
+
|
|
291
|
+
self.key = key
|
|
292
|
+
self.value = value
|
|
293
|
+
|
|
294
|
+
# Validation...
|
|
295
|
+
if isinstance(node, Invoke):
|
|
296
|
+
# NOTE In python 0 is seen as none so simply checking for it is not an option!
|
|
297
|
+
# in llparse This bould be is it's equvilent of "if (value === undefined) {""
|
|
298
|
+
if (not isinstance(value, int)) and value is None:
|
|
299
|
+
if node.code.signature != "match":
|
|
300
|
+
raise TypeError(
|
|
301
|
+
f"Invalid invoke code signature : {node.code.signature} is not match"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
elif node.code.signature != "value":
|
|
305
|
+
raise TypeError(
|
|
306
|
+
f"Invalid invoke code signature : {node.code.signature} is not value"
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
elif noAdvance:
|
|
310
|
+
if key and not isinstance(key, int) and len(key) != 1:
|
|
311
|
+
raise TypeError("Only 1-char keys are allowed in 'noAdvance' edges")
|
|
312
|
+
|
|
313
|
+
else:
|
|
314
|
+
# print(node)
|
|
315
|
+
if not isinstance(node, Node):
|
|
316
|
+
raise TypeError(
|
|
317
|
+
f"Attempted to pass value to non-Invoke node as :{type(node)}"
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
def __hash__(self) -> int:
|
|
321
|
+
return hash(self.node.name)
|
|
322
|
+
|
|
323
|
+
# Very Big Function but it works....
|
|
324
|
+
@staticmethod
|
|
325
|
+
def compare(a: "Edge", b: "Edge"):
|
|
326
|
+
return a.key == b.key
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
# This is where the fun begins...
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
class Match(Node):
|
|
333
|
+
"""This node matches characters/sequences and forwards the execution according
|
|
334
|
+
to matched character with optional attached value (See `.select()`)"""
|
|
335
|
+
|
|
336
|
+
def __init__(self, name: str) -> None:
|
|
337
|
+
super().__init__(name)
|
|
338
|
+
self.transformFn: Optional[Transform] = None
|
|
339
|
+
|
|
340
|
+
def transform(self, transformFn: Transform):
|
|
341
|
+
self.transformFn = transformFn
|
|
342
|
+
return self
|
|
343
|
+
|
|
344
|
+
def match(self, value: Union[str, int, list[int], list[str]], next: Node):
|
|
345
|
+
"""
|
|
346
|
+
Match sequence/character and forward execution to `next` on success,
|
|
347
|
+
|
|
348
|
+
consuming matched bytes of the input.
|
|
349
|
+
|
|
350
|
+
No value is attached on such execution forwarding, and the target node
|
|
351
|
+
|
|
352
|
+
**must not** be an `Invoke` node with a callback expecting the value.
|
|
353
|
+
|
|
354
|
+
Parameters
|
|
355
|
+
----------
|
|
356
|
+
|
|
357
|
+
- `value` Sequence/character to be matched
|
|
358
|
+
|
|
359
|
+
- `next` Target node to be executed on success.
|
|
360
|
+
"""
|
|
361
|
+
# if isinstance(value,str):
|
|
362
|
+
# value = value.encode("utf-8")
|
|
363
|
+
if isinstance(value, list) and len(value) > 1:
|
|
364
|
+
for i in value:
|
|
365
|
+
self.match(i.encode("utf-8") if isinstance(i, str) else i, next)
|
|
366
|
+
return self
|
|
367
|
+
|
|
368
|
+
edge = Edge(next, False, value, None)
|
|
369
|
+
self.addEdge(edge)
|
|
370
|
+
return self
|
|
371
|
+
|
|
372
|
+
def peek(self, value: Union[str, int, list[Union[str, int]]], next: Node):
|
|
373
|
+
"""Match character and forward execution to `next` on success
|
|
374
|
+
without consuming one byte of the input.
|
|
375
|
+
|
|
376
|
+
No value is attached on such execution forwarding, and the target node
|
|
377
|
+
must not be an `Invoke` with a callback expecting the value.
|
|
378
|
+
|
|
379
|
+
Parameters
|
|
380
|
+
----------
|
|
381
|
+
|
|
382
|
+
- `value` Character to be matched
|
|
383
|
+
- `next` Target node to be executed on success."""
|
|
384
|
+
|
|
385
|
+
if isinstance(value, list):
|
|
386
|
+
for i in value:
|
|
387
|
+
self.peek(i, next)
|
|
388
|
+
return self
|
|
389
|
+
|
|
390
|
+
if (isinstance(value, str)) and (len(value) != 1):
|
|
391
|
+
raise AssertionError(
|
|
392
|
+
".peek() accepts only singular character keys "
|
|
393
|
+
+ f"perhaps you meant to say : {value.split()}"
|
|
394
|
+
if isinstance(str, value)
|
|
395
|
+
else ""
|
|
396
|
+
)
|
|
397
|
+
edge = Edge(next, True, value, None)
|
|
398
|
+
self.addEdge(edge)
|
|
399
|
+
return self
|
|
400
|
+
|
|
401
|
+
# You may be asking why I'm not using Other types of Errors why assertion errors when there is not assert?
|
|
402
|
+
# It's beacuse it wanted to stay close to the orginal llparse library for better troubleshooting and error diagnosis - Vizonex
|
|
403
|
+
def select(
|
|
404
|
+
self,
|
|
405
|
+
keyOrDict: Union[int, str, dict[str, int]],
|
|
406
|
+
valueOrNext: Optional[Union[int, Node]] = None,
|
|
407
|
+
next: Optional[Node] = None,
|
|
408
|
+
):
|
|
409
|
+
"""Match character/sequence and forward execution to `next` on success
|
|
410
|
+
consumed matched bytes of the input.
|
|
411
|
+
|
|
412
|
+
Value is attached on such execution forwarding, and the target node
|
|
413
|
+
must be an `Invoke` with a callback expecting the value.
|
|
414
|
+
|
|
415
|
+
Possible signatures:
|
|
416
|
+
|
|
417
|
+
`.select(key, value [, next ])`
|
|
418
|
+
`.select({ key: value } [, next])`
|
|
419
|
+
|
|
420
|
+
- `keyOrDict` Either a sequence to match, or a dictionary from sequences to values
|
|
421
|
+
- `valueOrNext` Either an integer value to be forwarded to the target node, or an otherwise node
|
|
422
|
+
- `next` Convenience param. Same as calling `.otherwise(...)`"""
|
|
423
|
+
if isinstance(keyOrDict, dict):
|
|
424
|
+
if not isinstance(valueOrNext, Node):
|
|
425
|
+
raise AssertionError("Invalid next argument of '.select()'")
|
|
426
|
+
if next:
|
|
427
|
+
raise AssertionError("Invalid argument count of '.select()'")
|
|
428
|
+
|
|
429
|
+
next = valueOrNext
|
|
430
|
+
for numKey, key in keyOrDict.items():
|
|
431
|
+
# print(f"{key}:{numKey}:{next}")
|
|
432
|
+
self.select(numKey, keyOrDict[numKey], next)
|
|
433
|
+
|
|
434
|
+
return self
|
|
435
|
+
|
|
436
|
+
# select(key,value,next)
|
|
437
|
+
assert isinstance(valueOrNext, int), (
|
|
438
|
+
"value Argument should be an integer not, %s" % (type(valueOrNext).__name__)
|
|
439
|
+
)
|
|
440
|
+
# raise AssertionError("Invalid `value` of argument .select()")
|
|
441
|
+
assert next is not None, "Invalid `next` of argument .select()"
|
|
442
|
+
value = int(valueOrNext)
|
|
443
|
+
key = toBuffer(keyOrDict)
|
|
444
|
+
edge = Edge(next, False, key, value)
|
|
445
|
+
if self.name == "nmethods":
|
|
446
|
+
print(f"{self.name}: {key} -> {edge.node.name}")
|
|
447
|
+
|
|
448
|
+
self.addEdge(edge)
|
|
449
|
+
return self
|
|
450
|
+
|
|
451
|
+
def getTransform(self):
|
|
452
|
+
return self.transformFn
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
class _Span(Match):
|
|
456
|
+
def __init__(self, name: str) -> None:
|
|
457
|
+
self.name = name
|
|
458
|
+
super().__init__(name)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
class SpanStart(Node):
|
|
462
|
+
def __init__(self, span: "Span") -> None:
|
|
463
|
+
self.span = span
|
|
464
|
+
super().__init__(f"span_start_{span.callback.name}")
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
class SpanEnd(Node):
|
|
468
|
+
def __init__(self, span: "Span") -> None:
|
|
469
|
+
self.span = span
|
|
470
|
+
super().__init__(f"span_end_{span.callback.name}")
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
class Span:
|
|
474
|
+
def __init__(self, callback: _Span) -> None:
|
|
475
|
+
self.callback = callback
|
|
476
|
+
# NOTE Both SpanStart and SpanEnd have hash
|
|
477
|
+
# functions inherited from Node so no need to
|
|
478
|
+
# add anything special over there...
|
|
479
|
+
self.startCache: dict[Node, SpanStart] = {}
|
|
480
|
+
self.endCache: dict[Node, SpanEnd] = {}
|
|
481
|
+
|
|
482
|
+
# NOTE The thing that I'm greatful for seen in the orginal llparse typescript library
|
|
483
|
+
# is the ability to fork out and create all sorts of nodes whenever possible, these two
|
|
484
|
+
# functions personally demonstrate just that branching out concept alone - Vizonex
|
|
485
|
+
|
|
486
|
+
def start(self, otherwise: Optional[Node] = None):
|
|
487
|
+
if otherwise and self.startCache.get(otherwise):
|
|
488
|
+
return self.startCache[otherwise]
|
|
489
|
+
|
|
490
|
+
res = SpanStart(self)
|
|
491
|
+
|
|
492
|
+
if otherwise:
|
|
493
|
+
res.otherwise(otherwise)
|
|
494
|
+
self.startCache[otherwise] = res
|
|
495
|
+
|
|
496
|
+
return res
|
|
497
|
+
|
|
498
|
+
def end(self, otherwise: Optional[Node] = None):
|
|
499
|
+
if otherwise and self.endCache.get(otherwise):
|
|
500
|
+
return self.endCache[otherwise]
|
|
501
|
+
|
|
502
|
+
res = SpanEnd(self)
|
|
503
|
+
|
|
504
|
+
if otherwise:
|
|
505
|
+
res.otherwise(otherwise)
|
|
506
|
+
self.endCache[otherwise] = res
|
|
507
|
+
|
|
508
|
+
return res
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
class Reachability:
|
|
512
|
+
@staticmethod
|
|
513
|
+
def build(root: Node) -> list[Node]:
|
|
514
|
+
res: set[Node] = set()
|
|
515
|
+
queue = [root]
|
|
516
|
+
|
|
517
|
+
while queue:
|
|
518
|
+
node = queue.pop()
|
|
519
|
+
if node in res:
|
|
520
|
+
continue
|
|
521
|
+
|
|
522
|
+
res.add(node)
|
|
523
|
+
|
|
524
|
+
for edge in node:
|
|
525
|
+
queue.append(edge.node)
|
|
526
|
+
|
|
527
|
+
otherwise = node.getOtherwiseEdge()
|
|
528
|
+
if otherwise:
|
|
529
|
+
queue.append(otherwise.node)
|
|
530
|
+
|
|
531
|
+
return list(res)
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
# On_User_Key = Match("On_User_Key")
|
|
535
|
+
|
|
536
|
+
# On_User_Value = Match("On_User_Value")
|
|
537
|
+
|
|
538
|
+
# data_extraction = Node("On_Data_Extraction").skipTo(On_User_Key)
|
|
539
|
+
|
|
540
|
+
# node = Match("On_Level_Comment").skipTo(data_extraction)
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
# On_User_Key.match(["0","1","2","3","4","5","6","7","8","9"],On_User_Key)\
|
|
544
|
+
# .peek("~",On_User_Value)\
|
|
545
|
+
# .otherwise(Error(1,"[BAD KEY] Some retard decided to hijack your server! Oh SHIT!"))
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
# print([d.node.name for d in node.getAllEdges()])
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
from main_code import Edge, Node
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class ParserMap:
|
|
6
|
+
def __init__(self, root: Node) -> None:
|
|
7
|
+
self.root = root
|
|
8
|
+
|
|
9
|
+
def Jsonize(self):
|
|
10
|
+
queue = [self.root]
|
|
11
|
+
seen: set[Node] = set()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
while len(queue) != 0:
|
|
15
|
+
node = queue.pop()
|
|
16
|
+
|
|
17
|
+
if node in seen:
|
|
18
|
+
continue
|
|
19
|
+
|
|
20
|
+
seen.add(node)
|
|
21
|
+
|
|
22
|
+
for edge in node:
|
|
23
|
+
queue.append(edge.node)
|
|
24
|
+
|
|
25
|
+
otherwise = node.getOtherwiseEdge()
|
|
26
|
+
if otherwise:
|
|
27
|
+
queue.append(otherwise.node)
|
|
28
|
+
|
|
29
|
+
return [(s.__dict__, list(map(self.get_edges, s))) for s in seen]
|
|
30
|
+
|
|
31
|
+
def get_edges(self, edge: Edge):
|
|
32
|
+
if not edge:
|
|
33
|
+
return {}
|
|
34
|
+
data = edge.__dict__
|
|
35
|
+
data["node"] = edge.node
|
|
36
|
+
# print(data["node"].name)
|
|
37
|
+
return data
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from typing import Generic, TypeVar
|
|
2
|
+
|
|
3
|
+
from implementation import IImplementation
|
|
4
|
+
from pyfront.front import IWrap, T
|
|
5
|
+
|
|
6
|
+
R = TypeVar("R")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ContainerWrap(Generic[T]):
|
|
10
|
+
def __init__(self, ref: T) -> None:
|
|
11
|
+
self.ref = ref
|
|
12
|
+
self.map: dict[str, IWrap[T]] = {}
|
|
13
|
+
|
|
14
|
+
def get(self, R: type[R], key: str) -> IWrap[R]:
|
|
15
|
+
"""Changes and Alters the refrence to the orginal object..."""
|
|
16
|
+
|
|
17
|
+
# UnPack Object to Do Conversion From Since We aren't Using Typescript...
|
|
18
|
+
return IWrap(R(**self.map.get[key].__dict__))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# TODO Vizonex Figure out how containers
|
|
22
|
+
# should be implemented in python Spcae...
|
|
23
|
+
# Since Interfaces and other thinsg in it
|
|
24
|
+
# are tricky to just simply determine
|
|
25
|
+
class Container:
|
|
26
|
+
def __init__(self) -> None:
|
|
27
|
+
self.map: dict[str, IImplementation] = {}
|
|
28
|
+
|
|
29
|
+
def build(self):
|
|
30
|
+
return IImplementation()
|
|
31
|
+
|
|
32
|
+
def buildCode(self):
|
|
33
|
+
return
|