llparse 0.1.2__tar.gz → 0.1.3__tar.gz
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-0.1.2 → llparse-0.1.3}/PKG-INFO +7 -4
- {llparse-0.1.2 → llparse-0.1.3}/README.md +6 -3
- {llparse-0.1.2 → llparse-0.1.3}/llparse/compilator.py +1 -1
- {llparse-0.1.2 → llparse-0.1.3}/llparse/debug.py +0 -3
- {llparse-0.1.2 → llparse-0.1.3}/llparse/frontend.py +45 -49
- {llparse-0.1.2 → llparse-0.1.3}/llparse/llparse.py +12 -2
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pyfront/nodes.py +13 -18
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pyfront/peephole.py +1 -1
- {llparse-0.1.2 → llparse-0.1.3}/llparse/trie.py +10 -8
- {llparse-0.1.2 → llparse-0.1.3}/llparse.egg-info/PKG-INFO +7 -4
- {llparse-0.1.2 → llparse-0.1.3}/llparse.egg-info/SOURCES.txt +1 -0
- {llparse-0.1.2 → llparse-0.1.3}/pyproject.toml +1 -1
- llparse-0.1.3/tests/test_frontend.py +25 -0
- {llparse-0.1.2 → llparse-0.1.3}/LICENSE +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/C_compiler.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/__init__.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/constants.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/cython_builder.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/dot.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/enumerator.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/errors.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/header.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pybuilder/__init__.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pybuilder/builder.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pybuilder/loopchecker.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pybuilder/main_code.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pybuilder/parsemap.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pyfront/containers.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pyfront/front.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pyfront/implementation.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pyfront/namespace.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/pyfront/transform.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/settings.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/spanalloc.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse/test.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse.egg-info/dependency_links.txt +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/llparse.egg-info/top_level.txt +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/setup.cfg +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/tests/test_loop_checker.py +0 -0
- {llparse-0.1.2 → llparse-0.1.3}/tests/test_span_allocator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: llparse
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: A Parody of llparse written for writing C Parsers with Python
|
|
5
5
|
Author-email: Vizonex <VizonexBusiness@gmail.com>
|
|
6
6
|
Requires-Python: >=3.9
|
|
@@ -15,7 +15,7 @@ Dynamic: license-file
|
|
|
15
15
|
|
|
16
16
|
A python parody of the typescript library llparse.
|
|
17
17
|
|
|
18
|
-
I take no credit for the orginal work done by indutny and I was originally very nervous about making
|
|
18
|
+
I take no credit for the orginal work done by indutny and the other node-js contributors involved and I was originally very nervous about making
|
|
19
19
|
this python library that I made public...
|
|
20
20
|
|
|
21
21
|
Links to the original library
|
|
@@ -49,7 +49,7 @@ do it at your own risk. They maybe incompleted or not throughly stress-tested.
|
|
|
49
49
|
|
|
50
50
|
## New Features
|
|
51
51
|
- Throw me an issue if typescript llparse introduces something new that you want for me or another contributor to try and implement
|
|
52
|
-
just seeing llparse add new features is
|
|
52
|
+
just seeing llparse add new features is exciting to me.
|
|
53
53
|
|
|
54
54
|
- If you want a feature that typescript llparse doesn't have, be sure to try making a pull request over there as well and not just here,
|
|
55
55
|
there's a good chance they will appericate you for helping over there too and your helping make llhttp better by doing so. :)
|
|
@@ -62,7 +62,7 @@ there's a good chance they will appericate you for helping over there too and yo
|
|
|
62
62
|
- Make it easy for me or someone else to find a problem and solve it in typescript after testing it in python
|
|
63
63
|
- Typescript takes 2 commands to run a script with node-js it while python only takes one cutting the time required tremendously...
|
|
64
64
|
- The orginal project was MIT licensed.
|
|
65
|
-
- I wanted to write my own C
|
|
65
|
+
- I wanted to write my own C Parser tool with llhttp styled callbacks of my own using a language I was the most comfortable with using.
|
|
66
66
|
- I didn't like __Lemon Parser__ or __Yacc__ all that much and a good ide for handling them in Visual Studio Code with error checking to my knowlegde does not exist.
|
|
67
67
|
- The closest thing I got to what I wanted was a project named __NMFU__ shorthand for no memory for you and even I had problems with writing things using that library...
|
|
68
68
|
|
|
@@ -131,3 +131,6 @@ print(c.c)
|
|
|
131
131
|
open("http_parser.c", "w").write(c.c)
|
|
132
132
|
open("http_parser.h", "w").write(c.header)
|
|
133
133
|
```
|
|
134
|
+
|
|
135
|
+
## Video Showcasing this library
|
|
136
|
+
- https://youtu.be/YQOzJ2BghQw
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
A python parody of the typescript library llparse.
|
|
7
7
|
|
|
8
|
-
I take no credit for the orginal work done by indutny and I was originally very nervous about making
|
|
8
|
+
I take no credit for the orginal work done by indutny and the other node-js contributors involved and I was originally very nervous about making
|
|
9
9
|
this python library that I made public...
|
|
10
10
|
|
|
11
11
|
Links to the original library
|
|
@@ -39,7 +39,7 @@ do it at your own risk. They maybe incompleted or not throughly stress-tested.
|
|
|
39
39
|
|
|
40
40
|
## New Features
|
|
41
41
|
- Throw me an issue if typescript llparse introduces something new that you want for me or another contributor to try and implement
|
|
42
|
-
just seeing llparse add new features is
|
|
42
|
+
just seeing llparse add new features is exciting to me.
|
|
43
43
|
|
|
44
44
|
- If you want a feature that typescript llparse doesn't have, be sure to try making a pull request over there as well and not just here,
|
|
45
45
|
there's a good chance they will appericate you for helping over there too and your helping make llhttp better by doing so. :)
|
|
@@ -52,7 +52,7 @@ there's a good chance they will appericate you for helping over there too and yo
|
|
|
52
52
|
- Make it easy for me or someone else to find a problem and solve it in typescript after testing it in python
|
|
53
53
|
- Typescript takes 2 commands to run a script with node-js it while python only takes one cutting the time required tremendously...
|
|
54
54
|
- The orginal project was MIT licensed.
|
|
55
|
-
- I wanted to write my own C
|
|
55
|
+
- I wanted to write my own C Parser tool with llhttp styled callbacks of my own using a language I was the most comfortable with using.
|
|
56
56
|
- I didn't like __Lemon Parser__ or __Yacc__ all that much and a good ide for handling them in Visual Studio Code with error checking to my knowlegde does not exist.
|
|
57
57
|
- The closest thing I got to what I wanted was a project named __NMFU__ shorthand for no memory for you and even I had problems with writing things using that library...
|
|
58
58
|
|
|
@@ -121,3 +121,6 @@ print(c.c)
|
|
|
121
121
|
open("http_parser.c", "w").write(c.c)
|
|
122
122
|
open("http_parser.h", "w").write(c.header)
|
|
123
123
|
```
|
|
124
|
+
|
|
125
|
+
## Video Showcasing this library
|
|
126
|
+
- https://youtu.be/YQOzJ2BghQw
|
|
@@ -12,11 +12,15 @@ from .pyfront.implementation import IImplementation
|
|
|
12
12
|
from .pyfront.nodes import ITableEdge
|
|
13
13
|
from .pyfront.peephole import Peephole
|
|
14
14
|
from .spanalloc import SpanAllocator
|
|
15
|
-
from .trie import Trie, TrieEmpty, TrieNode, TrieSequence, TrieSingle
|
|
15
|
+
from .trie import Trie, TrieEmpty, TrieNode, TrieSequence, TrieSingle, ITrieSingleChild
|
|
16
16
|
|
|
17
17
|
DEFAULT_MIN_TABLE_SIZE = 32
|
|
18
18
|
DEFAULT_MAX_TABLE_WIDTH = 4
|
|
19
19
|
|
|
20
|
+
from logging import getLogger
|
|
21
|
+
|
|
22
|
+
log = getLogger("llparse.frontend")
|
|
23
|
+
|
|
20
24
|
|
|
21
25
|
WrappedNode = IWrap[_frontend.node.Node]
|
|
22
26
|
WrappedCode = IWrap[_frontend.code.Code]
|
|
@@ -166,7 +170,7 @@ class Frontend:
|
|
|
166
170
|
trieNode = trie.build(list(node))
|
|
167
171
|
|
|
168
172
|
if not trieNode:
|
|
169
|
-
|
|
173
|
+
log.debug("TrieNode was nonexistant")
|
|
170
174
|
return self.implementation.node.Empty(
|
|
171
175
|
_frontend.node.Empty(self.Id.id(node.name))
|
|
172
176
|
)
|
|
@@ -178,7 +182,7 @@ class Frontend:
|
|
|
178
182
|
|
|
179
183
|
return children
|
|
180
184
|
|
|
181
|
-
def registerNode(self, node: WrappedNode):
|
|
185
|
+
def registerNode(self, node: WrappedNode) -> None:
|
|
182
186
|
# NOTE NO Implementations required here since this is python!
|
|
183
187
|
if isinstance(
|
|
184
188
|
node.ref,
|
|
@@ -287,7 +291,6 @@ class Frontend:
|
|
|
287
291
|
|
|
288
292
|
if isinstance(single.ref, _frontend.node.Invoke):
|
|
289
293
|
for edge in node:
|
|
290
|
-
# print(edge.key)
|
|
291
294
|
single.ref.addEdge(
|
|
292
295
|
ord(edge.key) if isinstance(edge.key, str) else edge.key,
|
|
293
296
|
self.translate(edge.node),
|
|
@@ -304,52 +307,48 @@ class Frontend:
|
|
|
304
307
|
return None
|
|
305
308
|
|
|
306
309
|
targets: dict[source.code.Node, ITableLookupTarget] = {}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
empty
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
bailout = False
|
|
323
|
-
continue
|
|
310
|
+
|
|
311
|
+
def check_child(child: ITrieSingleChild):
|
|
312
|
+
nonlocal targets
|
|
313
|
+
if not isinstance(child.node, TrieEmpty):
|
|
314
|
+
log.debug(
|
|
315
|
+
'non-leaf trie child of "%s" prevents table allocation' % node.name
|
|
316
|
+
)
|
|
317
|
+
return False
|
|
318
|
+
empty = child.node
|
|
319
|
+
if empty.value is not None:
|
|
320
|
+
log.debug(
|
|
321
|
+
'value passing trie leaf of "%s" prevents table allocation'
|
|
322
|
+
% node.name
|
|
323
|
+
)
|
|
324
|
+
return False
|
|
324
325
|
|
|
325
326
|
target = empty.node
|
|
326
|
-
if not targets
|
|
327
|
+
if target not in targets:
|
|
327
328
|
targets[target] = ITableLookupTarget(
|
|
328
329
|
keys=[child.key], noAdvance=child.noAdvance, trie=empty
|
|
329
330
|
)
|
|
330
|
-
|
|
331
|
-
break
|
|
331
|
+
return True
|
|
332
332
|
|
|
333
333
|
existing = targets[target]
|
|
334
|
-
|
|
335
334
|
if existing.noAdvance != child.noAdvance:
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
335
|
+
log.debug(
|
|
336
|
+
f'noAdvance mismatch in a trie leaf of "{node.name}" prevents '
|
|
337
|
+
"table allocation"
|
|
338
|
+
)
|
|
339
|
+
return False
|
|
340
340
|
existing.keys.append(child.key)
|
|
341
|
+
return True
|
|
341
342
|
|
|
342
|
-
|
|
343
|
-
bailout = True
|
|
344
|
-
break
|
|
345
|
-
|
|
346
|
-
# assert len(trie.children) == len(targets), "Something went wrong"
|
|
347
|
-
if bailout:
|
|
343
|
+
if not all([check_child(child) for child in trie.children]):
|
|
348
344
|
return
|
|
349
345
|
|
|
350
346
|
# Weave width limit for optimization...
|
|
351
|
-
if len(targets
|
|
352
|
-
|
|
347
|
+
if len(targets) >= (1 << self.options["maxTableElemWidth"]):
|
|
348
|
+
log.debug(
|
|
349
|
+
'too many different trie targets of "%s" for a table allocation'
|
|
350
|
+
% node.name
|
|
351
|
+
)
|
|
353
352
|
return
|
|
354
353
|
|
|
355
354
|
table = self.implementation.node.TableLookup(
|
|
@@ -358,11 +357,11 @@ class Frontend:
|
|
|
358
357
|
children.append(table)
|
|
359
358
|
|
|
360
359
|
# Break Loop
|
|
361
|
-
if self.Map.get(node):
|
|
360
|
+
if not self.Map.get(node):
|
|
362
361
|
self.Map[node] = table
|
|
363
362
|
|
|
364
363
|
for target in targets.values():
|
|
365
|
-
_next = self.translateTrie(node, target, children)
|
|
364
|
+
_next = self.translateTrie(node, target.trie, children)
|
|
366
365
|
table.ref.addEdge(
|
|
367
366
|
ITableEdge(keys=target.keys, noAdvance=target.noAdvance, node=_next)
|
|
368
367
|
)
|
|
@@ -408,9 +407,7 @@ class Frontend:
|
|
|
408
407
|
self, node: source.code.Match, trie: TrieSingle, children: MatchChildren
|
|
409
408
|
):
|
|
410
409
|
# Check if Tablelookup could be a valid option to Optimze our code up...
|
|
411
|
-
maybeTable
|
|
412
|
-
|
|
413
|
-
if maybeTable:
|
|
410
|
+
if maybeTable := self.maybeTableLookup(node, trie, children):
|
|
414
411
|
return maybeTable
|
|
415
412
|
|
|
416
413
|
single = self.implementation.node.Single(
|
|
@@ -432,8 +429,7 @@ class Frontend:
|
|
|
432
429
|
value=child.node.value if isinstance(child.node, TrieEmpty) else None,
|
|
433
430
|
)
|
|
434
431
|
|
|
435
|
-
otherwise
|
|
436
|
-
if otherwise:
|
|
432
|
+
if otherwise := trie.otherwise:
|
|
437
433
|
single.ref.setOtherwise(
|
|
438
434
|
self.translateTrie(node, otherwise, children), True, otherwise.value
|
|
439
435
|
)
|
|
@@ -442,8 +438,9 @@ class Frontend:
|
|
|
442
438
|
def translateSpanCode(self, code: source.code._Span):
|
|
443
439
|
return self.translateCode(code)
|
|
444
440
|
|
|
445
|
-
|
|
446
|
-
|
|
441
|
+
def translateCode(
|
|
442
|
+
self, code: source.code.Code
|
|
443
|
+
):
|
|
447
444
|
"""Translates Builder Classes to Frontend Classes..."""
|
|
448
445
|
|
|
449
446
|
prefixed = self.codeId.id(code.name).name
|
|
@@ -499,9 +496,8 @@ class Frontend:
|
|
|
499
496
|
else:
|
|
500
497
|
raise Exception(f'UnSupported code:"{code.name}" type: "{type(code)}"')
|
|
501
498
|
|
|
502
|
-
if self.codeCache.get(res.ref.cacheKey):
|
|
503
|
-
return
|
|
504
|
-
|
|
499
|
+
if _res := self.codeCache.get(res.ref.cacheKey):
|
|
500
|
+
return _res
|
|
505
501
|
self.codeCache[res.ref.cacheKey] = res
|
|
506
502
|
return res
|
|
507
503
|
|
|
@@ -67,12 +67,20 @@ class Compiler:
|
|
|
67
67
|
properties: list[source.Property],
|
|
68
68
|
header_name: Optional[str] = None,
|
|
69
69
|
Impl: Optional[IImplementation] = IImplementation(),
|
|
70
|
+
override_llparse_name: bool = False
|
|
70
71
|
):
|
|
71
72
|
"""Creates the C and header file..."""
|
|
72
73
|
info = self.to_frontend(root, properties, Impl)
|
|
73
74
|
hb = HeaderBuilder(self.prefix, self.headerGuard, properties, info.spans)
|
|
75
|
+
cdata = CCompiler(header_name, self.debug).compile(info)
|
|
76
|
+
if override_llparse_name:
|
|
77
|
+
# sometimes users want to combine parsers together when compiling with C
|
|
78
|
+
# to make up for conflicts with other parsers example: llhttp
|
|
79
|
+
# there should be a fair way of compiling everything.
|
|
80
|
+
cdata = cdata.replace('llparse', self.prefix)
|
|
81
|
+
|
|
74
82
|
return CompilerResult(
|
|
75
|
-
|
|
83
|
+
cdata , hb.build()
|
|
76
84
|
)
|
|
77
85
|
|
|
78
86
|
|
|
@@ -122,6 +130,7 @@ class LLParse(source.Builder):
|
|
|
122
130
|
maxTableElemWidth: Optional[int] = None,
|
|
123
131
|
minTableSize: Optional[int] = None,
|
|
124
132
|
header_name: Optional[str] = None,
|
|
133
|
+
override_llparse_name:bool = False
|
|
125
134
|
):
|
|
126
135
|
"""Builds Graph and then compiles the data into C code , returns with the header and C file inside of a Dataclass"""
|
|
127
136
|
|
|
@@ -133,7 +142,8 @@ class LLParse(source.Builder):
|
|
|
133
142
|
minTableSize if minTableSize else DEFAULT_MIN_TABLE_SIZE,
|
|
134
143
|
)
|
|
135
144
|
|
|
136
|
-
return compiler.compile(root, self.properties(), header_name=header_name)
|
|
145
|
+
return compiler.compile(root, self.properties(), header_name=header_name, override_llparse_name=override_llparse_name)
|
|
146
|
+
|
|
137
147
|
|
|
138
148
|
def to_frontend(
|
|
139
149
|
self,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
|
-
from typing import Any, Optional
|
|
2
|
+
from typing import Any, Optional, Callable
|
|
3
3
|
|
|
4
4
|
from ..pyfront.front import Code, IWrap, Span, SpanField
|
|
5
5
|
from ..pyfront.transform import Transform
|
|
@@ -8,7 +8,9 @@ from ..pyfront.transform import Transform
|
|
|
8
8
|
class Slot:
|
|
9
9
|
# ONLY NODE SHOULD BE ALLOWED TO BE SEEN
|
|
10
10
|
|
|
11
|
-
def __init__(
|
|
11
|
+
def __init__(
|
|
12
|
+
self, node: IWrap["Node"], value: Callable[[IWrap["Node"]], None]
|
|
13
|
+
) -> None:
|
|
12
14
|
self.privNode = node
|
|
13
15
|
"""Same as calling it from get and setting the value etc..."""
|
|
14
16
|
self.privUpdate = value
|
|
@@ -19,12 +21,17 @@ class Slot:
|
|
|
19
21
|
# I spent 4 hours trying to figure this how this could be implemented
|
|
20
22
|
# so this is my only ideal sloution
|
|
21
23
|
def __hash__(self) -> int:
|
|
22
|
-
return hash(self.
|
|
24
|
+
return hash(self.privNode.ref.id.name)
|
|
23
25
|
|
|
24
26
|
@property
|
|
25
27
|
def node(self):
|
|
26
28
|
return self.privNode
|
|
27
29
|
|
|
30
|
+
@node.setter
|
|
31
|
+
def node(self, value: IWrap["Node"]):
|
|
32
|
+
self.privNode = value
|
|
33
|
+
self.privUpdate(value)
|
|
34
|
+
|
|
28
35
|
|
|
29
36
|
@dataclass(unsafe_hash=True)
|
|
30
37
|
class IUniqueName:
|
|
@@ -121,9 +128,6 @@ class Invoke(Node):
|
|
|
121
128
|
|
|
122
129
|
|
|
123
130
|
class Empty(Node):
|
|
124
|
-
# def __init__(self, id: IUniqueName) -> None:
|
|
125
|
-
# super().__init__(id)
|
|
126
|
-
|
|
127
131
|
def __hash__(self):
|
|
128
132
|
return hash(self.id)
|
|
129
133
|
|
|
@@ -237,16 +241,7 @@ class TableLookup(Match):
|
|
|
237
241
|
self.privEdges.append(edge)
|
|
238
242
|
|
|
239
243
|
def buildSlots(self):
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
for e in super().buildSlots():
|
|
244
|
-
yield e
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
# Ident = Identifier("llComment")
|
|
248
|
-
|
|
249
|
-
# node = Node(Ident.id("__On_Pagesum"))
|
|
244
|
+
for e in self.privEdges:
|
|
245
|
+
yield Slot(e.node, lambda value: setattr(e, "node", value))
|
|
246
|
+
yield from super().buildSlots()
|
|
250
247
|
|
|
251
|
-
# node2 = Invoke(Ident.id("Check_Flag"),IsEqual("Flag","Check_Flag",0))
|
|
252
|
-
# node2.setOtherwise(IWrap(node),True,0)
|
|
@@ -58,7 +58,7 @@ class Trie:
|
|
|
58
58
|
internalEdges: list[IEdge] = []
|
|
59
59
|
|
|
60
60
|
for edge in edges:
|
|
61
|
-
key =
|
|
61
|
+
key = chr(edge.key) if isinstance(edge.key, int) else edge.key
|
|
62
62
|
internalEdges.append(
|
|
63
63
|
IEdge(
|
|
64
64
|
key=key.encode("utf-8") if isinstance(key, str) else key,
|
|
@@ -73,8 +73,8 @@ class Trie:
|
|
|
73
73
|
def level(self, edges: list[IEdge], path: list[bytes] = []):
|
|
74
74
|
first = edges[0].key
|
|
75
75
|
last = edges[-1].key
|
|
76
|
-
# print("level",edges, first)
|
|
77
|
-
if len(edges) == 1 and len(edges[0].key) == 0:
|
|
76
|
+
# print("level", edges, first)
|
|
77
|
+
if len(edges) == 1 and (len(edges[0].key) == 0):
|
|
78
78
|
return TrieEmpty(edges[0].node, edges[0].value)
|
|
79
79
|
|
|
80
80
|
i = 0
|
|
@@ -112,17 +112,17 @@ class Trie:
|
|
|
112
112
|
+ (b", ".join(path).decode("utf-8"))
|
|
113
113
|
+ "]"
|
|
114
114
|
)
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
keys: dict[int, list[IEdge]] = {}
|
|
117
117
|
otherwise = None
|
|
118
118
|
for edge in edges:
|
|
119
|
-
if not
|
|
119
|
+
if not edge.key:
|
|
120
120
|
otherwise = TrieEmpty(edge.node, edge.value)
|
|
121
121
|
continue
|
|
122
122
|
|
|
123
123
|
key = edge.key[0]
|
|
124
124
|
|
|
125
|
-
if keys
|
|
125
|
+
if key in keys:
|
|
126
126
|
keys[key].append(edge)
|
|
127
127
|
else:
|
|
128
128
|
keys[key] = [edge]
|
|
@@ -146,7 +146,9 @@ class Trie:
|
|
|
146
146
|
+ "]"
|
|
147
147
|
)
|
|
148
148
|
raise TypeError(err)
|
|
149
|
-
|
|
150
|
-
children.append(
|
|
149
|
+
|
|
150
|
+
children.append(
|
|
151
|
+
ITrieSingleChild(key, noAdvance, self.level(sliced, subPath))
|
|
152
|
+
)
|
|
151
153
|
|
|
152
154
|
return TrieSingle(children, otherwise)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: llparse
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: A Parody of llparse written for writing C Parsers with Python
|
|
5
5
|
Author-email: Vizonex <VizonexBusiness@gmail.com>
|
|
6
6
|
Requires-Python: >=3.9
|
|
@@ -15,7 +15,7 @@ Dynamic: license-file
|
|
|
15
15
|
|
|
16
16
|
A python parody of the typescript library llparse.
|
|
17
17
|
|
|
18
|
-
I take no credit for the orginal work done by indutny and I was originally very nervous about making
|
|
18
|
+
I take no credit for the orginal work done by indutny and the other node-js contributors involved and I was originally very nervous about making
|
|
19
19
|
this python library that I made public...
|
|
20
20
|
|
|
21
21
|
Links to the original library
|
|
@@ -49,7 +49,7 @@ do it at your own risk. They maybe incompleted or not throughly stress-tested.
|
|
|
49
49
|
|
|
50
50
|
## New Features
|
|
51
51
|
- Throw me an issue if typescript llparse introduces something new that you want for me or another contributor to try and implement
|
|
52
|
-
just seeing llparse add new features is
|
|
52
|
+
just seeing llparse add new features is exciting to me.
|
|
53
53
|
|
|
54
54
|
- If you want a feature that typescript llparse doesn't have, be sure to try making a pull request over there as well and not just here,
|
|
55
55
|
there's a good chance they will appericate you for helping over there too and your helping make llhttp better by doing so. :)
|
|
@@ -62,7 +62,7 @@ there's a good chance they will appericate you for helping over there too and yo
|
|
|
62
62
|
- Make it easy for me or someone else to find a problem and solve it in typescript after testing it in python
|
|
63
63
|
- Typescript takes 2 commands to run a script with node-js it while python only takes one cutting the time required tremendously...
|
|
64
64
|
- The orginal project was MIT licensed.
|
|
65
|
-
- I wanted to write my own C
|
|
65
|
+
- I wanted to write my own C Parser tool with llhttp styled callbacks of my own using a language I was the most comfortable with using.
|
|
66
66
|
- I didn't like __Lemon Parser__ or __Yacc__ all that much and a good ide for handling them in Visual Studio Code with error checking to my knowlegde does not exist.
|
|
67
67
|
- The closest thing I got to what I wanted was a project named __NMFU__ shorthand for no memory for you and even I had problems with writing things using that library...
|
|
68
68
|
|
|
@@ -131,3 +131,6 @@ print(c.c)
|
|
|
131
131
|
open("http_parser.c", "w").write(c.c)
|
|
132
132
|
open("http_parser.h", "w").write(c.header)
|
|
133
133
|
```
|
|
134
|
+
|
|
135
|
+
## Video Showcasing this library
|
|
136
|
+
- https://youtu.be/YQOzJ2BghQw
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
|
|
2
|
+
from llparse import LLParse
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_build_tables():
|
|
7
|
+
# There was a bug with 1.2 of our version that doesn't affect the node-js one where
|
|
8
|
+
# it wouldn't building tables, this attempts to simulate the problem Currenlty this
|
|
9
|
+
# bug is patched now :)
|
|
10
|
+
p = LLParse("lltable")
|
|
11
|
+
start = p.node('start')
|
|
12
|
+
loop = p.node('loop')
|
|
13
|
+
loop.skipTo(start)
|
|
14
|
+
start.match(
|
|
15
|
+
[48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
|
|
16
|
+
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 58,
|
|
17
|
+
59, 60, 61, 62, 63, 64, 91, 92, 93, 94, 95, 96, 123, 124, 125, 126, 32, 9, 10, 13, 11, 12],
|
|
18
|
+
loop
|
|
19
|
+
).otherwise(p.error(0, 'im a little teapot'))
|
|
20
|
+
|
|
21
|
+
# If there is not a lookup_table this then it has failed me ;-;
|
|
22
|
+
assert "lookup_table" in p.build(start).c
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|