llparse 0.1.8__tar.gz → 0.2.0__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.8 → llparse-0.2.0}/PKG-INFO +11 -4
- {llparse-0.1.8 → llparse-0.2.0}/README.md +10 -3
- {llparse-0.1.8 → llparse-0.2.0}/llparse/C_compiler.py +2 -2
- {llparse-0.1.8 → llparse-0.2.0}/llparse/__init__.py +2 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/compilator.py +35 -33
- {llparse-0.1.8 → llparse-0.2.0}/llparse/cython_builder.py +1 -1
- {llparse-0.1.8 → llparse-0.2.0}/llparse/enumerator.py +3 -2
- {llparse-0.1.8 → llparse-0.2.0}/llparse/frontend.py +35 -23
- {llparse-0.1.8 → llparse-0.2.0}/llparse/llparse.py +14 -12
- llparse-0.2.0/llparse/pybuilder/__init__.py +7 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/pybuilder/builder.py +1 -2
- {llparse-0.1.8 → llparse-0.2.0}/llparse/pybuilder/loopchecker.py +2 -3
- {llparse-0.1.8 → llparse-0.2.0}/llparse/pybuilder/main_code.py +0 -18
- llparse-0.2.0/llparse/pyfront/__init__.py +3 -0
- llparse-0.1.8/llparse/pyfront/front.py → llparse-0.2.0/llparse/pyfront/code.py +5 -1
- {llparse-0.1.8 → llparse-0.2.0}/llparse/pyfront/implementation.py +4 -4
- llparse-0.2.0/llparse/pyfront/namespace.py +9 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/pyfront/nodes.py +5 -10
- llparse-0.2.0/llparse/pyfront/peephole.py +47 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/spanalloc.py +17 -12
- {llparse-0.1.8 → llparse-0.2.0}/llparse/trie.py +10 -9
- {llparse-0.1.8 → llparse-0.2.0}/llparse.egg-info/PKG-INFO +11 -4
- {llparse-0.1.8 → llparse-0.2.0}/llparse.egg-info/SOURCES.txt +3 -3
- {llparse-0.1.8 → llparse-0.2.0}/pyproject.toml +1 -1
- llparse-0.2.0/tests/test_compilator.py +54 -0
- llparse-0.1.8/llparse/pybuilder/__init__.py +0 -8
- llparse-0.1.8/llparse/pyfront/containers.py +0 -33
- llparse-0.1.8/llparse/pyfront/namespace.py +0 -3
- llparse-0.1.8/llparse/pyfront/peephole.py +0 -45
- llparse-0.1.8/llparse/test.py +0 -233
- {llparse-0.1.8 → llparse-0.2.0}/LICENSE +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/constants.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/debug.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/dot.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/errors.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/header.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/pybuilder/parsemap.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/pyfront/transform.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse/settings.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse.egg-info/dependency_links.txt +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/llparse.egg-info/top_level.txt +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/setup.cfg +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/tests/test_frontend.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/tests/test_loop_checker.py +0 -0
- {llparse-0.1.8 → llparse-0.2.0}/tests/test_span_allocator.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: llparse
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
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,15 +15,16 @@ 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 the other node-js contributors involved and
|
|
19
|
-
|
|
18
|
+
I take no credit for the orginal work done by indutny and the other node-js contributors involved and my additional
|
|
19
|
+
features were meant to inspire activity with the original library again.
|
|
20
20
|
|
|
21
21
|
Links to the original library
|
|
22
22
|
- https://llparse.org
|
|
23
23
|
- https://github.com/nodejs/llparse
|
|
24
24
|
|
|
25
25
|
Unlike the typescript library all 3 of llparse's libraries were combined in this version of the code for the sake of portability...
|
|
26
|
-
I ended up mentioning how I did this a while back and I also had a concept for a C parser as well but I just didn't like it and I ended up using this instead but I also learned typescript as a bonus and It was alot of fun for me. I don't plan to make this into a real pypi library yet but I also didn't want to take away from the magic of the original source code that I borrowed from
|
|
26
|
+
I ended up mentioning how I did this a while back and I also had a concept for a C parser as well but I just didn't like it and I ended up using this instead but I also learned typescript as a bonus and It was alot of fun for me. I don't plan to make this into a real pypi library yet but I also didn't want to take away from the magic of the original source code that I borrowed from.
|
|
27
|
+
|
|
27
28
|
|
|
28
29
|
# Looking back on my dead work 2 years later
|
|
29
30
|
I had this idea lay somewhat dormant for 2 years and now seeing that I wanted to write a new socks5 server parser writing it in python
|
|
@@ -134,3 +135,9 @@ open("http_parser.h", "w").write(c.header)
|
|
|
134
135
|
|
|
135
136
|
## Video Showcasing this library
|
|
136
137
|
- https://youtu.be/YQOzJ2BghQw
|
|
138
|
+
|
|
139
|
+
## Examples of this library being in use
|
|
140
|
+
- [llh2](https://github.com/Vizonex/llh2) I would like to move to the typescript version once my ideas and
|
|
141
|
+
features I've added in get fully implemented but we shall wait and see...
|
|
142
|
+
|
|
143
|
+
|
|
@@ -5,15 +5,16 @@
|
|
|
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 the other node-js contributors involved and
|
|
9
|
-
|
|
8
|
+
I take no credit for the orginal work done by indutny and the other node-js contributors involved and my additional
|
|
9
|
+
features were meant to inspire activity with the original library again.
|
|
10
10
|
|
|
11
11
|
Links to the original library
|
|
12
12
|
- https://llparse.org
|
|
13
13
|
- https://github.com/nodejs/llparse
|
|
14
14
|
|
|
15
15
|
Unlike the typescript library all 3 of llparse's libraries were combined in this version of the code for the sake of portability...
|
|
16
|
-
I ended up mentioning how I did this a while back and I also had a concept for a C parser as well but I just didn't like it and I ended up using this instead but I also learned typescript as a bonus and It was alot of fun for me. I don't plan to make this into a real pypi library yet but I also didn't want to take away from the magic of the original source code that I borrowed from
|
|
16
|
+
I ended up mentioning how I did this a while back and I also had a concept for a C parser as well but I just didn't like it and I ended up using this instead but I also learned typescript as a bonus and It was alot of fun for me. I don't plan to make this into a real pypi library yet but I also didn't want to take away from the magic of the original source code that I borrowed from.
|
|
17
|
+
|
|
17
18
|
|
|
18
19
|
# Looking back on my dead work 2 years later
|
|
19
20
|
I had this idea lay somewhat dormant for 2 years and now seeing that I wanted to write a new socks5 server parser writing it in python
|
|
@@ -124,3 +125,9 @@ open("http_parser.h", "w").write(c.header)
|
|
|
124
125
|
|
|
125
126
|
## Video Showcasing this library
|
|
126
127
|
- https://youtu.be/YQOzJ2BghQw
|
|
128
|
+
|
|
129
|
+
## Examples of this library being in use
|
|
130
|
+
- [llh2](https://github.com/Vizonex/llh2) I would like to move to the typescript version once my ideas and
|
|
131
|
+
features I've added in get fully implemented but we shall wait and see...
|
|
132
|
+
|
|
133
|
+
|
|
@@ -176,13 +176,13 @@ class CCompiler:
|
|
|
176
176
|
posField = ctx.spanPosField(span.index)
|
|
177
177
|
|
|
178
178
|
if len(span.callbacks) == 1:
|
|
179
|
-
cb = ctx.unwrapCode(span.callbacks[0]
|
|
179
|
+
cb = ctx.unwrapCode(span.callbacks[0])
|
|
180
180
|
callback = ctx.buildCode(cb)
|
|
181
181
|
|
|
182
182
|
else:
|
|
183
183
|
# TODO (Vizonex) Merge lines 139 & 140 together in a future update
|
|
184
184
|
callback = (
|
|
185
|
-
f"(({info.prefix}__span_cb)" + ctx.spanCbField(span.index) +
|
|
185
|
+
f"(({info.prefix}__span_cb)" + ctx.spanCbField(span.index) + ")"
|
|
186
186
|
)
|
|
187
187
|
|
|
188
188
|
args = [ctx.stateArg(), posField, f"(const char*) {ctx.endPosArg()}"]
|
|
@@ -273,12 +273,13 @@ class Update(Field):
|
|
|
273
273
|
out.append(f"{self.field(ctx)} = {self.ref.value};")
|
|
274
274
|
out.append("return 0;")
|
|
275
275
|
|
|
276
|
+
|
|
276
277
|
class Operator(Field):
|
|
277
278
|
def __init__(self, ref: _frontend.code.Operator):
|
|
278
279
|
self.ref = ref
|
|
279
|
-
|
|
280
|
+
|
|
280
281
|
def doBuild(self, ctx: "Compilation", out: list[str]):
|
|
281
|
-
out.append(f
|
|
282
|
+
out.append(f"return {self.field(ctx)} {self.ref.op} {self.ref.value};")
|
|
282
283
|
|
|
283
284
|
|
|
284
285
|
@dataclass
|
|
@@ -508,7 +509,9 @@ class Pause(Error):
|
|
|
508
509
|
|
|
509
510
|
assert self.ref.otherwise
|
|
510
511
|
otherwise = ctx.unwrapNode(self.ref.otherwise.node)
|
|
511
|
-
out.append(
|
|
512
|
+
out.append(
|
|
513
|
+
f"{ctx.currentField()} = (void*) (intptr_t) {otherwise.cachedDecel or ('s_n_' + otherwise.ref.id.name)};"
|
|
514
|
+
)
|
|
512
515
|
out.append(f"return {STATE_ERROR};")
|
|
513
516
|
|
|
514
517
|
|
|
@@ -519,7 +522,7 @@ class Sequence(Node):
|
|
|
519
522
|
|
|
520
523
|
def doBuild(self, out: list[str]):
|
|
521
524
|
ctx = self.compilation
|
|
522
|
-
# TODO: llparse_match_t could be easily changed around to
|
|
525
|
+
# TODO: llparse_match_t could be easily changed around to
|
|
523
526
|
# Something that can't be overlapped with when compiled with other parsers...
|
|
524
527
|
out.append("llparse_match_t match_seq;")
|
|
525
528
|
out.append("")
|
|
@@ -617,7 +620,7 @@ class SpanStart(Node):
|
|
|
617
620
|
|
|
618
621
|
if len(field.callbacks) > 1:
|
|
619
622
|
cbField = ctx.spanCbField(field.index)
|
|
620
|
-
callback = ctx.unwrapCode(self.ref.callback
|
|
623
|
+
callback = ctx.unwrapCode(self.ref.callback)
|
|
621
624
|
out.append(f"{cbField} = {ctx.buildCode(callback)};")
|
|
622
625
|
|
|
623
626
|
otherwise = self.ref.otherwise
|
|
@@ -645,7 +648,7 @@ class SpanEnd(Node):
|
|
|
645
648
|
out.append(f"{posField} = NULL;")
|
|
646
649
|
|
|
647
650
|
# Invoke callback
|
|
648
|
-
callback = ctx.buildCode(ctx.unwrapCode(self.ref.callback
|
|
651
|
+
callback = ctx.buildCode(ctx.unwrapCode(self.ref.callback))
|
|
649
652
|
|
|
650
653
|
out.append(f"err = {callback}({ctx.stateArg()}, start, {ctx.posArg()});")
|
|
651
654
|
|
|
@@ -691,11 +694,13 @@ class SpanEnd(Node):
|
|
|
691
694
|
# 0x800000 I24
|
|
692
695
|
# 0x1000000 U24
|
|
693
696
|
|
|
697
|
+
|
|
694
698
|
class Int(Node):
|
|
695
699
|
def __init__(self, ref: _frontend.node.Int):
|
|
696
700
|
super().__init__(ref)
|
|
697
701
|
self.ref = ref
|
|
698
702
|
self.offset = ref.byteOffset
|
|
703
|
+
|
|
699
704
|
# I'm going to deviate from arthurschreiber's work a bit with indutny's suggestions.
|
|
700
705
|
# we should really be using bitwise operators like rshift and lshift
|
|
701
706
|
@property
|
|
@@ -705,11 +710,11 @@ class Int(Node):
|
|
|
705
710
|
def readInt8(self, out: list[str]) -> None:
|
|
706
711
|
ctx, index = self.pair
|
|
707
712
|
out.append(f"{index} = ((*{ctx.posArg()}) & 0x80);")
|
|
708
|
-
|
|
713
|
+
|
|
709
714
|
def readUInt8(self, out: list[str]) -> None:
|
|
710
715
|
ctx, index = self.pair
|
|
711
716
|
out.append(f"{index} = (*{ctx.posArg()});")
|
|
712
|
-
|
|
717
|
+
|
|
713
718
|
# LITTLE ENDIAN
|
|
714
719
|
|
|
715
720
|
def readInt16LE(self, out: list[str]) -> None:
|
|
@@ -717,7 +722,7 @@ class Int(Node):
|
|
|
717
722
|
if self.offset == 0:
|
|
718
723
|
out.append(f"{index} = (*{ctx.posArg()});")
|
|
719
724
|
else:
|
|
720
|
-
# Since BE Belongs to performing << aka left shifts we do >> right shifts
|
|
725
|
+
# Since BE Belongs to performing << aka left shifts we do >> right shifts
|
|
721
726
|
out.append(f"{index} = ({index} >> 8) | ((*{ctx.posArg()}) & 0x80);")
|
|
722
727
|
|
|
723
728
|
def readUInt16LE(self, out: list[str]) -> None:
|
|
@@ -742,7 +747,7 @@ class Int(Node):
|
|
|
742
747
|
out.append(f"{index} = (*{ctx.posArg()});")
|
|
743
748
|
else:
|
|
744
749
|
out.append(f"{index} = ({index} >> 8) | (*{ctx.posArg()});")
|
|
745
|
-
|
|
750
|
+
|
|
746
751
|
def readInt32LE(self, out: list[str]) -> None:
|
|
747
752
|
ctx, index = self.pair
|
|
748
753
|
if self.offset == 0:
|
|
@@ -758,17 +763,17 @@ class Int(Node):
|
|
|
758
763
|
out.append(f"{index} = (*{ctx.posArg()});")
|
|
759
764
|
else:
|
|
760
765
|
out.append(f"{index} = ({index} >> 8) | (*{ctx.posArg()});")
|
|
761
|
-
|
|
762
|
-
# BIG ENDIAN
|
|
763
|
-
|
|
766
|
+
|
|
767
|
+
# BIG ENDIAN
|
|
768
|
+
|
|
764
769
|
def readInt16BE(self, out: list[str]) -> None:
|
|
765
770
|
ctx, index = self.pair
|
|
766
771
|
if self.offset == 0:
|
|
767
772
|
out.append(f"{index} = (*{ctx.posArg()});")
|
|
768
773
|
else:
|
|
769
|
-
# Since LE Belongs to >> we do "<<" instead
|
|
774
|
+
# Since LE Belongs to >> we do "<<" instead
|
|
770
775
|
out.append(f"{index} = ({index} << 8) | ((*{ctx.posArg()}) & 0x80);")
|
|
771
|
-
|
|
776
|
+
|
|
772
777
|
def readUInt16BE(self, out: list[str]) -> None:
|
|
773
778
|
ctx, index = self.pair
|
|
774
779
|
if self.offset == 0:
|
|
@@ -791,7 +796,7 @@ class Int(Node):
|
|
|
791
796
|
out.append(f"{index} = (*{ctx.posArg()});")
|
|
792
797
|
else:
|
|
793
798
|
out.append(f"{index} = ({index} << 8) | (*{ctx.posArg()});")
|
|
794
|
-
|
|
799
|
+
|
|
795
800
|
def readInt32BE(self, out: list[str]) -> None:
|
|
796
801
|
ctx, index = self.pair
|
|
797
802
|
if self.offset == 0:
|
|
@@ -807,15 +812,16 @@ class Int(Node):
|
|
|
807
812
|
out.append(f"{index} = (*{ctx.posArg()});")
|
|
808
813
|
else:
|
|
809
814
|
out.append(f"{index} = ({index} << 8) | (*{ctx.posArg()});")
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
def doBuild(self, out:list[str]):
|
|
815
|
+
|
|
816
|
+
def doBuild(self, out: list[str]):
|
|
813
817
|
self.prologue(out)
|
|
814
818
|
# I'm still supporting 3.9 but I plan to drop it's support in favor of match case soon...
|
|
815
819
|
bits = self.ref.bits
|
|
816
|
-
|
|
817
|
-
if self.compilation.getFieldType(self.ref.field) ==
|
|
818
|
-
raise ValueError(
|
|
820
|
+
|
|
821
|
+
if self.compilation.getFieldType(self.ref.field) == "ptr":
|
|
822
|
+
raise ValueError(
|
|
823
|
+
f'property {self.ref.field} should not use pointers but it was given "ptr"'
|
|
824
|
+
)
|
|
819
825
|
|
|
820
826
|
if bits == 1:
|
|
821
827
|
self.readInt8(out) if self.ref.signed else self.readUInt8(out)
|
|
@@ -835,10 +841,8 @@ class Int(Node):
|
|
|
835
841
|
else:
|
|
836
842
|
self.readInt32BE(out) if self.ref.signed else self.readUInt32BE(out)
|
|
837
843
|
# TODO: uint64 & int64
|
|
838
|
-
|
|
839
|
-
self.tailTo(out, self.ref.otherwise.node, self.ref.otherwise.noAdvance, None)
|
|
840
|
-
|
|
841
844
|
|
|
845
|
+
self.tailTo(out, self.ref.otherwise.node, self.ref.otherwise.noAdvance, None)
|
|
842
846
|
|
|
843
847
|
|
|
844
848
|
MAX_CHAR = 0xFF
|
|
@@ -1117,8 +1121,7 @@ class Compilation:
|
|
|
1117
1121
|
def reserveSpans(self, spans: list[_frontend.node.SpanField]):
|
|
1118
1122
|
for span in spans:
|
|
1119
1123
|
for callback in span.callbacks:
|
|
1120
|
-
cb
|
|
1121
|
-
if cb:
|
|
1124
|
+
if cb := self.unwrapCode(callback):
|
|
1122
1125
|
self.buildCode(cb)
|
|
1123
1126
|
|
|
1124
1127
|
def debug(self, out: list[str], message: str):
|
|
@@ -1193,12 +1196,11 @@ class Compilation:
|
|
|
1193
1196
|
raise LookupError(f'Field "{field}" not found')
|
|
1194
1197
|
|
|
1195
1198
|
# Helpers are different since in python we have duck typing - Vizonex
|
|
1196
|
-
def unwrapCode(
|
|
1197
|
-
|
|
1198
|
-
):
|
|
1199
|
-
if self.CodeContainer.get(code):
|
|
1199
|
+
def unwrapCode(self, code: IWrap[_frontend.code.Code]):
|
|
1200
|
+
if __code := self.CodeContainer.get(code):
|
|
1200
1201
|
# Give some indication that the element has already been built...
|
|
1201
|
-
return self.CodeContainer[code]
|
|
1202
|
+
# return self.CodeContainer[code]
|
|
1203
|
+
return __code
|
|
1202
1204
|
|
|
1203
1205
|
ref = code.ref
|
|
1204
1206
|
|
|
@@ -1251,7 +1253,7 @@ class Compilation:
|
|
|
1251
1253
|
r = Error(ref)
|
|
1252
1254
|
elif isinstance(ref, _frontend.node.Invoke):
|
|
1253
1255
|
r = Invoke(ref)
|
|
1254
|
-
|
|
1256
|
+
|
|
1255
1257
|
elif isinstance(ref, _frontend.node.SpanStart):
|
|
1256
1258
|
r = SpanStart(ref)
|
|
1257
1259
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
from .pyfront.
|
|
1
|
+
from .pyfront.code import IWrap
|
|
2
2
|
from .pyfront.nodes import Node
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class Enumerator:
|
|
6
|
+
# TODO: Remove from staticmethod and make one seperate function
|
|
6
7
|
@staticmethod
|
|
7
|
-
def getAllNodes(root: IWrap[Node]):
|
|
8
|
+
def getAllNodes(root: IWrap[Node]) -> list[IWrap[Node]]:
|
|
8
9
|
nodes: set[IWrap[Node]] = set()
|
|
9
10
|
queue: list[IWrap[Node]] = [root]
|
|
10
11
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
|
-
from typing import Literal, Optional,
|
|
2
|
+
from typing import Literal, Optional, TypeVar, Union
|
|
3
3
|
|
|
4
4
|
from .enumerator import Enumerator
|
|
5
5
|
from .pybuilder import LoopChecker
|
|
@@ -7,12 +7,12 @@ from .pybuilder import builder as source
|
|
|
7
7
|
|
|
8
8
|
# from pyfront.namespace import code, node , transform
|
|
9
9
|
from .pyfront import namespace as _frontend
|
|
10
|
-
from .pyfront.
|
|
10
|
+
from .pyfront.code import Identifier, IWrap, SpanField
|
|
11
11
|
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 ITrieSingleChild, Trie, TrieEmpty, TrieNode, TrieSequence, TrieSingle
|
|
16
16
|
|
|
17
17
|
DEFAULT_MIN_TABLE_SIZE = 32
|
|
18
18
|
DEFAULT_MAX_TABLE_WIDTH = 4
|
|
@@ -22,8 +22,8 @@ from logging import getLogger
|
|
|
22
22
|
log = getLogger("llparse.frontend")
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
CodeT = TypeVar(
|
|
26
|
-
NodeT = TypeVar(
|
|
25
|
+
CodeT = TypeVar("CodeT", bound=source.code.Code)
|
|
26
|
+
NodeT = TypeVar("NodeT", bound=source.node.Node)
|
|
27
27
|
|
|
28
28
|
WrappedNode = IWrap[_frontend.node.Node]
|
|
29
29
|
WrappedCode = IWrap[_frontend.code.Code]
|
|
@@ -196,7 +196,7 @@ class Frontend:
|
|
|
196
196
|
_frontend.node.Sequence,
|
|
197
197
|
_frontend.node.Single,
|
|
198
198
|
_frontend.node.TableLookup,
|
|
199
|
-
_frontend.node.SpanStart
|
|
199
|
+
_frontend.node.SpanStart,
|
|
200
200
|
),
|
|
201
201
|
):
|
|
202
202
|
self.resumptionTargets.add(node)
|
|
@@ -263,8 +263,8 @@ class Frontend:
|
|
|
263
263
|
|
|
264
264
|
assert isinstance(node, (source.code.Match, source.node.Int))
|
|
265
265
|
_match = node
|
|
266
|
-
|
|
267
|
-
assert otherwise,
|
|
266
|
+
|
|
267
|
+
assert otherwise, f'Node "{node.name}" has no ".otherwise()"'
|
|
268
268
|
|
|
269
269
|
if isinstance(node, source.node.Match):
|
|
270
270
|
for child in result:
|
|
@@ -277,9 +277,10 @@ class Frontend:
|
|
|
277
277
|
# TODO Vizonex : This might break , be sure to make a workaround function here...
|
|
278
278
|
child.ref.setTransform(transform)
|
|
279
279
|
|
|
280
|
-
|
|
281
280
|
else:
|
|
282
|
-
result[-1].ref.setOtherwise(
|
|
281
|
+
result[-1].ref.setOtherwise(
|
|
282
|
+
self.translate(otherwise.node), otherwise.noAdvance
|
|
283
|
+
)
|
|
283
284
|
assert len(result) >= 1
|
|
284
285
|
return result[0]
|
|
285
286
|
|
|
@@ -310,16 +311,30 @@ class Frontend:
|
|
|
310
311
|
assert len(list(node)) == 0
|
|
311
312
|
|
|
312
313
|
return single
|
|
313
|
-
|
|
314
|
+
|
|
314
315
|
def translateInt(self, node: source.node.Int) -> list[IWrap[_frontend.node.Int]]:
|
|
315
|
-
inner = _frontend.node.Int(
|
|
316
|
+
inner = _frontend.node.Int(
|
|
317
|
+
self.Id.id(node.name),
|
|
318
|
+
node.field,
|
|
319
|
+
node.bits,
|
|
320
|
+
node.signed,
|
|
321
|
+
node.little_endian,
|
|
322
|
+
0,
|
|
323
|
+
)
|
|
316
324
|
result = [self.implementation.node.Int(inner)]
|
|
317
325
|
# front is to avoid overlapping with python's functions (aka next)
|
|
318
326
|
front = self.Map[node] = result[0]
|
|
319
|
-
|
|
327
|
+
|
|
320
328
|
for offset in range(1, node.bits):
|
|
321
329
|
unique_name = self.Id.id(f"{node.name}_byte{offset + 1}")
|
|
322
|
-
inner = _frontend.node.Int(
|
|
330
|
+
inner = _frontend.node.Int(
|
|
331
|
+
unique_name,
|
|
332
|
+
node.field,
|
|
333
|
+
node.bits,
|
|
334
|
+
node.signed,
|
|
335
|
+
node.little_endian,
|
|
336
|
+
offset,
|
|
337
|
+
)
|
|
323
338
|
outer = self.implementation.node.Int(inner)
|
|
324
339
|
result.append(outer)
|
|
325
340
|
# Integers will advance since they are unpacking values...
|
|
@@ -327,7 +342,6 @@ class Frontend:
|
|
|
327
342
|
front = result[-1]
|
|
328
343
|
return result
|
|
329
344
|
|
|
330
|
-
|
|
331
345
|
def maybeTableLookup(
|
|
332
346
|
self, node: source.code.Match, trie: TrieSingle, children: MatchChildren
|
|
333
347
|
):
|
|
@@ -466,9 +480,7 @@ class Frontend:
|
|
|
466
480
|
def translateSpanCode(self, code: source.code._Span):
|
|
467
481
|
return self.translateCode(code)
|
|
468
482
|
|
|
469
|
-
def translateCode(
|
|
470
|
-
self, code: CodeT
|
|
471
|
-
):
|
|
483
|
+
def translateCode(self, code: CodeT):
|
|
472
484
|
"""Translates Builder Classes to Frontend Classes..."""
|
|
473
485
|
|
|
474
486
|
prefixed = self.codeId.id(code.name).name
|
|
@@ -479,13 +491,13 @@ class Frontend:
|
|
|
479
491
|
res = codeImpl.IsEqual(
|
|
480
492
|
_frontend.code.IsEqual(prefixed, code.field, code.value)
|
|
481
493
|
)
|
|
482
|
-
# custom thing I added in 0.1.6 I encourage the typescript
|
|
494
|
+
# custom thing I added in 0.1.6 I encourage the typescript
|
|
483
495
|
# maintainers and developers of llparse to look into this :)
|
|
484
496
|
elif isinstance(code, source.code.Operator):
|
|
485
|
-
res = codeImpl.Operator(
|
|
486
|
-
prefixed, code.field, code.value, code.op
|
|
487
|
-
)
|
|
488
|
-
|
|
497
|
+
res = codeImpl.Operator(
|
|
498
|
+
_frontend.code.Operator(prefixed, code.field, code.value, code.op)
|
|
499
|
+
)
|
|
500
|
+
|
|
489
501
|
elif isinstance(code, source.code.Load):
|
|
490
502
|
res = codeImpl.Load(_frontend.code.Load(prefixed, code.field))
|
|
491
503
|
|
|
@@ -67,21 +67,19 @@ 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
|
+
override_llparse_name: bool = False,
|
|
71
71
|
):
|
|
72
72
|
"""Creates the C and header file..."""
|
|
73
73
|
info = self.to_frontend(root, properties, Impl)
|
|
74
74
|
hb = HeaderBuilder(self.prefix, self.headerGuard, properties, info.spans)
|
|
75
|
-
cdata =
|
|
75
|
+
cdata = CCompiler(header_name, self.debug).compile(info)
|
|
76
76
|
if override_llparse_name:
|
|
77
77
|
# sometimes users want to combine parsers together when compiling with C
|
|
78
78
|
# to make up for conflicts with other parsers example: llhttp
|
|
79
79
|
# there should be a fair way of compiling everything.
|
|
80
|
-
cdata = cdata.replace(
|
|
80
|
+
cdata = cdata.replace("llparse", self.prefix)
|
|
81
81
|
|
|
82
|
-
return CompilerResult(
|
|
83
|
-
cdata , hb.build()
|
|
84
|
-
)
|
|
82
|
+
return CompilerResult(cdata, hb.build())
|
|
85
83
|
|
|
86
84
|
|
|
87
85
|
class LLParse(source.Builder):
|
|
@@ -113,7 +111,7 @@ class LLParse(source.Builder):
|
|
|
113
111
|
debug: Optional[str] = None,
|
|
114
112
|
maxTableElemWidth: Optional[int] = None,
|
|
115
113
|
minTableSize: Optional[int] = None,
|
|
116
|
-
):
|
|
114
|
+
) -> Compiler:
|
|
117
115
|
return Compiler(
|
|
118
116
|
self.prefix,
|
|
119
117
|
headerGuard,
|
|
@@ -130,8 +128,8 @@ class LLParse(source.Builder):
|
|
|
130
128
|
maxTableElemWidth: Optional[int] = None,
|
|
131
129
|
minTableSize: Optional[int] = None,
|
|
132
130
|
header_name: Optional[str] = None,
|
|
133
|
-
override_llparse_name:bool = False
|
|
134
|
-
):
|
|
131
|
+
override_llparse_name: bool = False,
|
|
132
|
+
) -> CompilerResult:
|
|
135
133
|
"""Builds Graph and then compiles the data into C code , returns with the header and C file inside of a Dataclass"""
|
|
136
134
|
|
|
137
135
|
compiler = Compiler(
|
|
@@ -142,8 +140,12 @@ class LLParse(source.Builder):
|
|
|
142
140
|
minTableSize if minTableSize else DEFAULT_MIN_TABLE_SIZE,
|
|
143
141
|
)
|
|
144
142
|
|
|
145
|
-
return compiler.compile(
|
|
146
|
-
|
|
143
|
+
return compiler.compile(
|
|
144
|
+
root,
|
|
145
|
+
self.properties(),
|
|
146
|
+
header_name=header_name,
|
|
147
|
+
override_llparse_name=override_llparse_name,
|
|
148
|
+
)
|
|
147
149
|
|
|
148
150
|
def to_frontend(
|
|
149
151
|
self,
|
|
@@ -152,7 +154,7 @@ class LLParse(source.Builder):
|
|
|
152
154
|
debug: Optional[str] = None,
|
|
153
155
|
maxTableElemWidth: Optional[int] = None,
|
|
154
156
|
minTableSize: Optional[int] = None,
|
|
155
|
-
):
|
|
157
|
+
) -> Compiler:
|
|
156
158
|
"""Used as an external hack to get access to the frontend of llparse and extract
|
|
157
159
|
it's contents to compile the libraries you make other things like cython, This is not in llparse
|
|
158
160
|
specifically (Yet...)"""
|
|
@@ -118,15 +118,14 @@ class Reachability:
|
|
|
118
118
|
def build(self, root: Node) -> list[Node]:
|
|
119
119
|
res: set[Node] = set()
|
|
120
120
|
queue = [root]
|
|
121
|
-
while
|
|
121
|
+
while queue:
|
|
122
122
|
node = queue.pop()
|
|
123
123
|
if node in res:
|
|
124
124
|
continue
|
|
125
125
|
res.add(node)
|
|
126
126
|
for edge in node:
|
|
127
127
|
queue.append(edge.node)
|
|
128
|
-
otherwise
|
|
129
|
-
if otherwise:
|
|
128
|
+
if otherwise := node.getOtherwiseEdge():
|
|
130
129
|
queue.append(otherwise.node)
|
|
131
130
|
|
|
132
131
|
# Reverse the order so that we always
|
|
@@ -196,7 +196,6 @@ class Node:
|
|
|
196
196
|
return res
|
|
197
197
|
else:
|
|
198
198
|
# Concate DO NOT ADD TO RES!!!!
|
|
199
|
-
|
|
200
199
|
return res + [self.otherwiseEdge]
|
|
201
200
|
|
|
202
201
|
def __iter__(self):
|
|
@@ -601,20 +600,3 @@ class Reachability:
|
|
|
601
600
|
queue.append(otherwise.node)
|
|
602
601
|
|
|
603
602
|
return list(res)
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
# On_User_Key = Match("On_User_Key")
|
|
607
|
-
|
|
608
|
-
# On_User_Value = Match("On_User_Value")
|
|
609
|
-
|
|
610
|
-
# data_extraction = Node("On_Data_Extraction").skipTo(On_User_Key)
|
|
611
|
-
|
|
612
|
-
# node = Match("On_Level_Comment").skipTo(data_extraction)
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
# On_User_Key.match(["0","1","2","3","4","5","6","7","8","9"],On_User_Key)\
|
|
616
|
-
# .peek("~",On_User_Value)\
|
|
617
|
-
# .otherwise(Error(1,"[BAD KEY] Some retard decided to hijack your server! Oh SHIT!"))
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
# print([d.node.name for d in node.getAllEdges()])
|
|
@@ -89,7 +89,11 @@ class IsEqual(FieldValue):
|
|
|
89
89
|
class Operator(FieldValue):
|
|
90
90
|
def __init__(self, name: str, field: str, value: int, op: str):
|
|
91
91
|
super().__init__(
|
|
92
|
-
"match",
|
|
92
|
+
"match",
|
|
93
|
+
f"is_{field}_{name}_{toCacheKey(value)}",
|
|
94
|
+
f"{name}_{toCacheKey(value)}",
|
|
95
|
+
field,
|
|
96
|
+
value,
|
|
93
97
|
)
|
|
94
98
|
self.op = op
|
|
95
99
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from
|
|
1
|
+
from . import code as code
|
|
2
2
|
from ..pyfront import nodes as node
|
|
3
3
|
from ..pyfront import transform
|
|
4
|
-
from
|
|
4
|
+
from .code import IWrap
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class INodeImplementation:
|
|
@@ -37,7 +37,7 @@ class INodeImplementation:
|
|
|
37
37
|
|
|
38
38
|
def TableLookup(self, n: node.TableLookup):
|
|
39
39
|
return IWrap(n)
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
def Int(self, n: node.Int):
|
|
42
42
|
return IWrap(n)
|
|
43
43
|
|
|
@@ -93,7 +93,7 @@ class ICodeImplementation:
|
|
|
93
93
|
|
|
94
94
|
def Value(self, c: code.Value):
|
|
95
95
|
return IWrap(c)
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
def Operator(self, c: code.Operator):
|
|
98
98
|
return IWrap(c)
|
|
99
99
|
|