llparse 0.1.3__tar.gz → 0.1.5__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.3 → llparse-0.1.5}/PKG-INFO +1 -1
- {llparse-0.1.3 → llparse-0.1.5}/llparse/compilator.py +168 -7
- {llparse-0.1.3 → llparse-0.1.5}/llparse/frontend.py +34 -11
- llparse-0.1.5/llparse/pybuilder/__init__.py +8 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pybuilder/builder.py +37 -1
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pybuilder/main_code.py +35 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pyfront/front.py +0 -3
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pyfront/implementation.py +3 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pyfront/nodes.py +20 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse.egg-info/PKG-INFO +1 -1
- {llparse-0.1.3 → llparse-0.1.5}/pyproject.toml +1 -1
- {llparse-0.1.3 → llparse-0.1.5}/tests/test_frontend.py +11 -1
- llparse-0.1.3/llparse/pybuilder/__init__.py +0 -2
- {llparse-0.1.3 → llparse-0.1.5}/LICENSE +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/README.md +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/C_compiler.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/__init__.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/constants.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/cython_builder.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/debug.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/dot.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/enumerator.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/errors.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/header.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/llparse.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pybuilder/loopchecker.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pybuilder/parsemap.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pyfront/containers.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pyfront/namespace.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pyfront/peephole.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/pyfront/transform.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/settings.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/spanalloc.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/test.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse/trie.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse.egg-info/SOURCES.txt +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse.egg-info/dependency_links.txt +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/llparse.egg-info/top_level.txt +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/setup.cfg +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/tests/test_loop_checker.py +0 -0
- {llparse-0.1.3 → llparse-0.1.5}/tests/test_span_allocator.py +0 -0
|
@@ -337,7 +337,7 @@ class Node:
|
|
|
337
337
|
out: list[str],
|
|
338
338
|
node: IWrap[_frontend.node.Node],
|
|
339
339
|
noAdvance: bool,
|
|
340
|
-
value: Optional[int],
|
|
340
|
+
value: Optional[int] = None,
|
|
341
341
|
):
|
|
342
342
|
ctx = self.compilation
|
|
343
343
|
target = ctx.unwrapNode(node).build(ctx)
|
|
@@ -501,7 +501,7 @@ class Pause(Error):
|
|
|
501
501
|
|
|
502
502
|
assert self.ref.otherwise
|
|
503
503
|
otherwise = ctx.unwrapNode(self.ref.otherwise.node)
|
|
504
|
-
out.append(f"{ctx.currentField()} = (void*) (intptr_t) {otherwise};")
|
|
504
|
+
out.append(f"{ctx.currentField()} = (void*) (intptr_t) {otherwise.cachedDecel or ('s_n_' + otherwise.ref.id.name)};")
|
|
505
505
|
out.append(f"return {STATE_ERROR};")
|
|
506
506
|
|
|
507
507
|
|
|
@@ -512,7 +512,8 @@ class Sequence(Node):
|
|
|
512
512
|
|
|
513
513
|
def doBuild(self, out: list[str]):
|
|
514
514
|
ctx = self.compilation
|
|
515
|
-
|
|
515
|
+
# TODO: llparse_match_t could be easily changed around to
|
|
516
|
+
# Something that can't be overlapped with when compiled with other parsers...
|
|
516
517
|
out.append("llparse_match_t match_seq;")
|
|
517
518
|
out.append("")
|
|
518
519
|
|
|
@@ -639,7 +640,7 @@ class SpanEnd(Node):
|
|
|
639
640
|
# Invoke callback
|
|
640
641
|
callback = ctx.buildCode(ctx.unwrapCode(self.ref.callback, True))
|
|
641
642
|
|
|
642
|
-
out.append(f"err = {callback}({ctx.stateArg()}, start,{ctx.posArg()});")
|
|
643
|
+
out.append(f"err = {callback}({ctx.stateArg()}, start, {ctx.posArg()});")
|
|
643
644
|
|
|
644
645
|
out.append("if (err != 0) {")
|
|
645
646
|
tmp = []
|
|
@@ -676,6 +677,163 @@ class SpanEnd(Node):
|
|
|
676
677
|
out.append(f"return {STATE_ERROR};")
|
|
677
678
|
|
|
678
679
|
|
|
680
|
+
# Based off arthurschreiber's work with Indutny's Tips and requests added to the mix.
|
|
681
|
+
|
|
682
|
+
# 0x80 I8
|
|
683
|
+
# 0x8000 I16
|
|
684
|
+
# 0x800000 I24
|
|
685
|
+
# 0x1000000 U24
|
|
686
|
+
|
|
687
|
+
class Int(Node):
|
|
688
|
+
def __init__(self, ref: _frontend.node.Int):
|
|
689
|
+
super().__init__(ref)
|
|
690
|
+
self.ref = ref
|
|
691
|
+
self.offset = ref.byteOffset
|
|
692
|
+
# I'm going to deviate from arthurschreiber's work a bit with indutny's suggestions.
|
|
693
|
+
# we should really be using bitwise operators like rshift and lshift
|
|
694
|
+
@property
|
|
695
|
+
def pair(self):
|
|
696
|
+
return self.compilation, self.compilation.stateField(self.ref.field)
|
|
697
|
+
|
|
698
|
+
def readInt8(self, out: list[str]) -> None:
|
|
699
|
+
ctx, index = self.pair
|
|
700
|
+
out.append(f"{index} = ((*{ctx.posArg()}) & 0x80);")
|
|
701
|
+
|
|
702
|
+
def readUInt8(self, out: list[str]) -> None:
|
|
703
|
+
ctx, index = self.pair
|
|
704
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
705
|
+
|
|
706
|
+
# LITTLE ENDIAN
|
|
707
|
+
|
|
708
|
+
def readInt16LE(self, out: list[str]) -> None:
|
|
709
|
+
ctx, index = self.pair
|
|
710
|
+
if self.offset == 0:
|
|
711
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
712
|
+
else:
|
|
713
|
+
# Since BE Belongs to performing << aka left shifts we do >> right shifts
|
|
714
|
+
out.append(f"{index} = ({index} >> 8) | ((*{ctx.posArg()}) & 0x80);")
|
|
715
|
+
|
|
716
|
+
def readUInt16LE(self, out: list[str]) -> None:
|
|
717
|
+
ctx, index = self.pair
|
|
718
|
+
if self.offset == 0:
|
|
719
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
720
|
+
else:
|
|
721
|
+
out.append(f"{index} = ({index} >> 8) | (*{ctx.posArg()});")
|
|
722
|
+
|
|
723
|
+
def readInt24LE(self, out: list[str]) -> None:
|
|
724
|
+
ctx, index = self.pair
|
|
725
|
+
if self.offset == 0:
|
|
726
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
727
|
+
elif self.offset == 1:
|
|
728
|
+
out.append(f"{index} = ({index} >> 8) | (*{ctx.posArg()});")
|
|
729
|
+
else:
|
|
730
|
+
out.append(f"{index} = ({index} >> 8) | ((*{ctx.posArg()}) & 0x80);")
|
|
731
|
+
|
|
732
|
+
def readUInt24LE(self, out: list[str]) -> None:
|
|
733
|
+
ctx, index = self.pair
|
|
734
|
+
if self.offset == 0:
|
|
735
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
736
|
+
else:
|
|
737
|
+
out.append(f"{index} = ({index} >> 8) | (*{ctx.posArg()});")
|
|
738
|
+
|
|
739
|
+
def readInt32LE(self, out: list[str]) -> None:
|
|
740
|
+
ctx, index = self.pair
|
|
741
|
+
if self.offset == 0:
|
|
742
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
743
|
+
elif self.offset in (1, 2):
|
|
744
|
+
out.append(f"{index} = ({index} >> 8) | (*{ctx.posArg()});")
|
|
745
|
+
else:
|
|
746
|
+
out.append(f"{index} = ({index} >> 8) | ((*{ctx.posArg()}) & 0x80);")
|
|
747
|
+
|
|
748
|
+
def readUInt32LE(self, out: list[str]) -> None:
|
|
749
|
+
ctx, index = self.pair
|
|
750
|
+
if self.offset == 0:
|
|
751
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
752
|
+
else:
|
|
753
|
+
out.append(f"{index} = ({index} >> 8) | (*{ctx.posArg()});")
|
|
754
|
+
|
|
755
|
+
# BIG ENDIAN
|
|
756
|
+
|
|
757
|
+
def readInt16BE(self, out: list[str]) -> None:
|
|
758
|
+
ctx, index = self.pair
|
|
759
|
+
if self.offset == 0:
|
|
760
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
761
|
+
else:
|
|
762
|
+
# Since LE Belongs to >> we do "<<" instead
|
|
763
|
+
out.append(f"{index} = ({index} << 8) | ((*{ctx.posArg()}) & 0x80);")
|
|
764
|
+
|
|
765
|
+
def readUInt16BE(self, out: list[str]) -> None:
|
|
766
|
+
ctx, index = self.pair
|
|
767
|
+
if self.offset == 0:
|
|
768
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
769
|
+
else:
|
|
770
|
+
out.append(f"{index} = ({index} << 8) | (*{ctx.posArg()});")
|
|
771
|
+
|
|
772
|
+
def readInt24BE(self, out: list[str]) -> None:
|
|
773
|
+
ctx, index = self.pair
|
|
774
|
+
if self.offset == 0:
|
|
775
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
776
|
+
elif self.offset == 1:
|
|
777
|
+
out.append(f"{index} = ({index} << 8) | (*{ctx.posArg()});")
|
|
778
|
+
else:
|
|
779
|
+
out.append(f"{index} = ({index} << 8) | ((*{ctx.posArg()}) & 0x80);")
|
|
780
|
+
|
|
781
|
+
def readUInt24BE(self, out: list[str]) -> None:
|
|
782
|
+
ctx, index = self.pair
|
|
783
|
+
if self.offset == 0:
|
|
784
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
785
|
+
else:
|
|
786
|
+
out.append(f"{index} = ({index} << 8) | (*{ctx.posArg()});")
|
|
787
|
+
|
|
788
|
+
def readInt32BE(self, out: list[str]) -> None:
|
|
789
|
+
ctx, index = self.pair
|
|
790
|
+
if self.offset == 0:
|
|
791
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
792
|
+
elif self.offset in (1, 2):
|
|
793
|
+
out.append(f"{index} = ({index} << 8) | (*{ctx.posArg()});")
|
|
794
|
+
else:
|
|
795
|
+
out.append(f"{index} = ({index} << 8) | ((*{ctx.posArg()}) & 0x80);")
|
|
796
|
+
|
|
797
|
+
def readUInt32BE(self, out: list[str]) -> None:
|
|
798
|
+
ctx, index = self.pair
|
|
799
|
+
if self.offset == 0:
|
|
800
|
+
out.append(f"{index} = (*{ctx.posArg()});")
|
|
801
|
+
else:
|
|
802
|
+
out.append(f"{index} = ({index} << 8) | (*{ctx.posArg()});")
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
def doBuild(self, out:list[str]):
|
|
806
|
+
self.prologue(out)
|
|
807
|
+
# I'm still supporting 3.9 but I plan to drop it's support in favor of match case soon...
|
|
808
|
+
bits = self.ref.bits
|
|
809
|
+
|
|
810
|
+
if self.compilation.getFieldType(self.ref.field) == 'ptr':
|
|
811
|
+
raise ValueError(f'property {self.ref.field} should not use pointers but it was given \"ptr\"')
|
|
812
|
+
|
|
813
|
+
if bits == 1:
|
|
814
|
+
self.readInt8(out) if self.ref.signed else self.readUInt8(out)
|
|
815
|
+
elif bits == 2:
|
|
816
|
+
if self.ref.littleEndian:
|
|
817
|
+
self.readInt16LE(out) if self.ref.signed else self.readUInt16LE(out)
|
|
818
|
+
else:
|
|
819
|
+
self.readInt16BE(out) if self.ref.signed else self.readUInt16BE(out)
|
|
820
|
+
elif bits == 3:
|
|
821
|
+
if self.ref.littleEndian:
|
|
822
|
+
self.readInt24LE(out) if self.ref.signed else self.readUInt24LE(out)
|
|
823
|
+
else:
|
|
824
|
+
self.readInt24BE(out) if self.ref.signed else self.readUInt24BE(out)
|
|
825
|
+
else:
|
|
826
|
+
if self.ref.littleEndian:
|
|
827
|
+
self.readInt32LE(out) if self.ref.signed else self.readUInt32LE(out)
|
|
828
|
+
else:
|
|
829
|
+
self.readInt32BE(out) if self.ref.signed else self.readUInt32BE(out)
|
|
830
|
+
# TODO: uint64 & int64
|
|
831
|
+
|
|
832
|
+
self.tailTo(out, self.ref.otherwise.node, self.ref.otherwise.noAdvance, None)
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
|
|
679
837
|
MAX_CHAR = 0xFF
|
|
680
838
|
TABLE_GROUP = 16
|
|
681
839
|
|
|
@@ -1077,13 +1235,14 @@ class Compilation:
|
|
|
1077
1235
|
r = Consume(ref)
|
|
1078
1236
|
elif isinstance(ref, _frontend.node.Empty):
|
|
1079
1237
|
r = Empty(ref)
|
|
1238
|
+
elif isinstance(ref, _frontend.node.Pause):
|
|
1239
|
+
r = Pause(ref)
|
|
1240
|
+
|
|
1080
1241
|
elif isinstance(ref, _frontend.node.Error):
|
|
1081
1242
|
r = Error(ref)
|
|
1082
1243
|
elif isinstance(ref, _frontend.node.Invoke):
|
|
1083
1244
|
r = Invoke(ref)
|
|
1084
|
-
|
|
1085
|
-
r = Pause(ref)
|
|
1086
|
-
|
|
1245
|
+
|
|
1087
1246
|
elif isinstance(ref, _frontend.node.SpanStart):
|
|
1088
1247
|
r = SpanStart(ref)
|
|
1089
1248
|
|
|
@@ -1096,6 +1255,8 @@ class Compilation:
|
|
|
1096
1255
|
r = Sequence(ref)
|
|
1097
1256
|
elif isinstance(ref, _frontend.node.TableLookup):
|
|
1098
1257
|
r = TableLookup(ref)
|
|
1258
|
+
elif isinstance(ref, _frontend.node.Int):
|
|
1259
|
+
r = Int(ref)
|
|
1099
1260
|
else:
|
|
1100
1261
|
raise TypeError(
|
|
1101
1262
|
f'refrence "{ref}" is an Invalid Code Type , TypeName:"{ref.__class__.__name__}"'
|
|
@@ -211,7 +211,7 @@ class Frontend:
|
|
|
211
211
|
result = nodeImpl.Error(_frontend.node.Error(ID(), node.code, node.reason))
|
|
212
212
|
|
|
213
213
|
elif isinstance(node, source.code.Pause):
|
|
214
|
-
result = nodeImpl.Pause(_frontend.node.
|
|
214
|
+
result = nodeImpl.Pause(_frontend.node.Pause(ID(), node.code, node.reason))
|
|
215
215
|
|
|
216
216
|
elif isinstance(node, source.code.Comsume):
|
|
217
217
|
result = nodeImpl.Consume(_frontend.node.Consume(ID(), node.field))
|
|
@@ -244,6 +244,10 @@ class Frontend:
|
|
|
244
244
|
|
|
245
245
|
elif isinstance(node, source.code.Match):
|
|
246
246
|
result = self.translateMatch(node)
|
|
247
|
+
|
|
248
|
+
elif isinstance(node, source.node.Int):
|
|
249
|
+
result = self.translateInt(node)
|
|
250
|
+
|
|
247
251
|
else:
|
|
248
252
|
raise Exception(f'Unknown Node Type for :"{node.name}" {type(node)}')
|
|
249
253
|
|
|
@@ -251,24 +255,26 @@ class Frontend:
|
|
|
251
255
|
|
|
252
256
|
if isinstance(result, list):
|
|
253
257
|
# result:list[WrappedNode]
|
|
254
|
-
assert isinstance(node, source.code.Match)
|
|
255
|
-
_match = node
|
|
256
258
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
+
assert isinstance(node, (source.code.Match, source.node.Int))
|
|
260
|
+
_match = node
|
|
261
|
+
|
|
262
|
+
assert otherwise, (f'Node "{node.name}" has no ".otherwise()"')
|
|
259
263
|
|
|
260
|
-
|
|
264
|
+
if isinstance(node, source.node.Match):
|
|
261
265
|
for child in result:
|
|
262
266
|
if not child.ref.otherwise:
|
|
263
267
|
child.ref.setOtherwise(
|
|
264
268
|
self.translate(otherwise.node), otherwise.noAdvance
|
|
265
269
|
)
|
|
270
|
+
transform = self.translateTransform(_match.getTransform())
|
|
271
|
+
for child in result:
|
|
272
|
+
# TODO Vizonex : This might break , be sure to make a workaround function here...
|
|
273
|
+
child.ref.setTransform(transform)
|
|
266
274
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
child.ref.setTransform(transform)
|
|
271
|
-
|
|
275
|
+
|
|
276
|
+
else:
|
|
277
|
+
result[-1].ref.setOtherwise(self.translate(otherwise.node), otherwise.noAdvance)
|
|
272
278
|
assert len(result) >= 1
|
|
273
279
|
return result[0]
|
|
274
280
|
|
|
@@ -299,6 +305,23 @@ class Frontend:
|
|
|
299
305
|
assert len(list(node)) == 0
|
|
300
306
|
|
|
301
307
|
return single
|
|
308
|
+
|
|
309
|
+
def translateInt(self, node: source.node.Int) -> list[IWrap[_frontend.node.Int]]:
|
|
310
|
+
inner = _frontend.node.Int(self.Id.id(node.name), node.field, node.bits, node.signed, node.little_endian, 0)
|
|
311
|
+
result = [self.implementation.node.Int(inner)]
|
|
312
|
+
# front is to avoid overlapping with python's functions (aka next)
|
|
313
|
+
front = self.Map[node] = result[0]
|
|
314
|
+
|
|
315
|
+
for offset in range(1, node.bits):
|
|
316
|
+
unique_name = self.Id.id(f"{node.name}_byte{offset + 1}")
|
|
317
|
+
inner = _frontend.node.Int(unique_name, node.field, node.bits, node.signed, node.little_endian, offset)
|
|
318
|
+
outer = self.implementation.node.Int(inner)
|
|
319
|
+
result.append(outer)
|
|
320
|
+
# Integers will advance since they are unpacking values...
|
|
321
|
+
front.ref.setOtherwise(outer, False)
|
|
322
|
+
front = result[-1]
|
|
323
|
+
return result
|
|
324
|
+
|
|
302
325
|
|
|
303
326
|
def maybeTableLookup(
|
|
304
327
|
self, node: source.code.Match, trie: TrieSingle, children: MatchChildren
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from typing import Literal, Optional, Union
|
|
2
|
-
|
|
3
2
|
from ..pybuilder import main_code as code
|
|
4
3
|
|
|
4
|
+
# typehinting node and code (TODO: Vizonex) Lets seperate the modules soon...
|
|
5
|
+
node = code
|
|
5
6
|
# from pydot import graph_from_dot_data
|
|
6
7
|
|
|
7
8
|
|
|
@@ -316,3 +317,38 @@ class Builder:
|
|
|
316
317
|
def properties(self) -> list[Property]:
|
|
317
318
|
"""Return list of all allocated properties in parser's state."""
|
|
318
319
|
return list(self.privProperties.values())
|
|
320
|
+
|
|
321
|
+
def intBE(self, field: str, bits:int):
|
|
322
|
+
"""
|
|
323
|
+
:param field: State's property name
|
|
324
|
+
:param bits: Number of bits to use
|
|
325
|
+
"""
|
|
326
|
+
return code.Int(field, bits, True, False)
|
|
327
|
+
|
|
328
|
+
def intLE(self, field: str, bits: int):
|
|
329
|
+
"""
|
|
330
|
+
return a node for unpacking arrays to integers
|
|
331
|
+
|
|
332
|
+
:param field: State's property name
|
|
333
|
+
:param bits: Number of bits to use
|
|
334
|
+
"""
|
|
335
|
+
return code.Int(field, bits, True, True)
|
|
336
|
+
|
|
337
|
+
def uintBE(self, field: str, bits: int):
|
|
338
|
+
"""
|
|
339
|
+
return a node for unpacking arrays to integers
|
|
340
|
+
|
|
341
|
+
:param field: State's property name
|
|
342
|
+
:param bits: Number of bits to use
|
|
343
|
+
"""
|
|
344
|
+
return code.Int(field, bits, False, False)
|
|
345
|
+
|
|
346
|
+
def uintLE(self, field: str, bits: int):
|
|
347
|
+
"""
|
|
348
|
+
return a node for unpacking arrays to integers
|
|
349
|
+
|
|
350
|
+
:param field: State's property name
|
|
351
|
+
:param bits: Number of bits to use
|
|
352
|
+
"""
|
|
353
|
+
return code.Int(field, bits, False, True)
|
|
354
|
+
|
|
@@ -92,6 +92,8 @@ class _Match(Code):
|
|
|
92
92
|
super().__init__("match", name)
|
|
93
93
|
|
|
94
94
|
|
|
95
|
+
|
|
96
|
+
|
|
95
97
|
@dataclass
|
|
96
98
|
class IMulAddOptions:
|
|
97
99
|
base: int
|
|
@@ -244,6 +246,39 @@ class Invoke(Node):
|
|
|
244
246
|
self.addEdge(Edge(targetNode, True, numKey, None))
|
|
245
247
|
|
|
246
248
|
|
|
249
|
+
|
|
250
|
+
# Not in llparse node-js (yet) But I wanted to implement
|
|
251
|
+
# this into my version since I am making a very important
|
|
252
|
+
# http2 frame parser
|
|
253
|
+
|
|
254
|
+
# SEE: https://github.com/nodejs/llparse-frontend/pull/1
|
|
255
|
+
|
|
256
|
+
def build_name(field:str, bits: int, signed:bool, little_endian:bool) -> str:
|
|
257
|
+
result = f"{field}_{'int' if signed else 'uint'}_{bits * 8}"
|
|
258
|
+
if bits > 1:
|
|
259
|
+
return result + ('_le' if little_endian else 'be')
|
|
260
|
+
else:
|
|
261
|
+
return result
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class Int(Node):
|
|
265
|
+
"""Used for parsing bytes via unpacking"""
|
|
266
|
+
def __init__(self, field: str, bits: int, signed: bool, little_endian: bool) -> None:
|
|
267
|
+
"""
|
|
268
|
+
:param field: State's property name
|
|
269
|
+
:param bits: Number of bits to use
|
|
270
|
+
:param signed: Number is signed
|
|
271
|
+
:param little_endian: true if le, false if be
|
|
272
|
+
"""
|
|
273
|
+
if bits < 0:
|
|
274
|
+
raise ValueError("bits should be a positive integer")
|
|
275
|
+
self.field = field
|
|
276
|
+
self.bits = bits
|
|
277
|
+
self.signed = signed
|
|
278
|
+
self.little_endian = little_endian
|
|
279
|
+
super().__init__(build_name(field, bits, signed, little_endian))
|
|
280
|
+
|
|
281
|
+
|
|
247
282
|
# -- Transfroms --
|
|
248
283
|
|
|
249
284
|
TransformName = ["to_lower_unsafe", "to_lower"]
|
|
@@ -153,6 +153,26 @@ class Pause(Error):
|
|
|
153
153
|
super().__init__(id, code, reason)
|
|
154
154
|
|
|
155
155
|
|
|
156
|
+
# Not in llparse node-js (yet) But I wanted to implement
|
|
157
|
+
# this into my version since I am making a very important
|
|
158
|
+
# http2 frame parser
|
|
159
|
+
|
|
160
|
+
# SEE: https://github.com/nodejs/llparse-frontend/pull/1
|
|
161
|
+
|
|
162
|
+
@dataclass
|
|
163
|
+
class Int(Node):
|
|
164
|
+
field: str
|
|
165
|
+
bits: int
|
|
166
|
+
signed: bool
|
|
167
|
+
littleEndian: bool
|
|
168
|
+
byteOffset: int
|
|
169
|
+
|
|
170
|
+
def __hash__(self):
|
|
171
|
+
return hash(self.id)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
156
176
|
@dataclass
|
|
157
177
|
class ISeqEdge:
|
|
158
178
|
node: IWrap[Node]
|
|
@@ -22,4 +22,14 @@ def test_build_tables():
|
|
|
22
22
|
assert "lookup_table" in p.build(start).c
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
def test_pausing():
|
|
26
|
+
# Ensure frotentend LoopChecker does not mark off against Pausing
|
|
27
|
+
p = LLParse("lltest")
|
|
28
|
+
s = p.node('start')
|
|
29
|
+
s2 = p.node('start2')
|
|
30
|
+
s.match('p', p.pause(1, 'parser was asked to pause').otherwise(s2)).skipTo(s)
|
|
31
|
+
s2.match('p', p.pause(2, 'parser was asked to pause again').otherwise(s)).skipTo(s2)
|
|
32
|
+
|
|
33
|
+
p.build(s)
|
|
34
|
+
|
|
35
|
+
|
|
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
|
|
File without changes
|