llparse 0.1.4__tar.gz → 0.1.6__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.
Files changed (41) hide show
  1. {llparse-0.1.4 → llparse-0.1.6}/PKG-INFO +1 -1
  2. {llparse-0.1.4 → llparse-0.1.6}/llparse/compilator.py +10 -1
  3. {llparse-0.1.4 → llparse-0.1.6}/llparse/frontend.py +12 -3
  4. {llparse-0.1.4 → llparse-0.1.6}/llparse/pybuilder/builder.py +103 -72
  5. {llparse-0.1.4 → llparse-0.1.6}/llparse/pybuilder/main_code.py +31 -12
  6. {llparse-0.1.4 → llparse-0.1.6}/llparse/pyfront/front.py +8 -0
  7. {llparse-0.1.4 → llparse-0.1.6}/llparse/pyfront/implementation.py +4 -0
  8. {llparse-0.1.4 → llparse-0.1.6}/llparse.egg-info/PKG-INFO +1 -1
  9. {llparse-0.1.4 → llparse-0.1.6}/pyproject.toml +1 -1
  10. llparse-0.1.6/tests/test_frontend.py +164 -0
  11. {llparse-0.1.4 → llparse-0.1.6}/tests/test_span_allocator.py +15 -9
  12. llparse-0.1.4/tests/test_frontend.py +0 -35
  13. {llparse-0.1.4 → llparse-0.1.6}/LICENSE +0 -0
  14. {llparse-0.1.4 → llparse-0.1.6}/README.md +0 -0
  15. {llparse-0.1.4 → llparse-0.1.6}/llparse/C_compiler.py +0 -0
  16. {llparse-0.1.4 → llparse-0.1.6}/llparse/__init__.py +0 -0
  17. {llparse-0.1.4 → llparse-0.1.6}/llparse/constants.py +0 -0
  18. {llparse-0.1.4 → llparse-0.1.6}/llparse/cython_builder.py +0 -0
  19. {llparse-0.1.4 → llparse-0.1.6}/llparse/debug.py +0 -0
  20. {llparse-0.1.4 → llparse-0.1.6}/llparse/dot.py +0 -0
  21. {llparse-0.1.4 → llparse-0.1.6}/llparse/enumerator.py +0 -0
  22. {llparse-0.1.4 → llparse-0.1.6}/llparse/errors.py +0 -0
  23. {llparse-0.1.4 → llparse-0.1.6}/llparse/header.py +0 -0
  24. {llparse-0.1.4 → llparse-0.1.6}/llparse/llparse.py +0 -0
  25. {llparse-0.1.4 → llparse-0.1.6}/llparse/pybuilder/__init__.py +0 -0
  26. {llparse-0.1.4 → llparse-0.1.6}/llparse/pybuilder/loopchecker.py +0 -0
  27. {llparse-0.1.4 → llparse-0.1.6}/llparse/pybuilder/parsemap.py +0 -0
  28. {llparse-0.1.4 → llparse-0.1.6}/llparse/pyfront/containers.py +0 -0
  29. {llparse-0.1.4 → llparse-0.1.6}/llparse/pyfront/namespace.py +0 -0
  30. {llparse-0.1.4 → llparse-0.1.6}/llparse/pyfront/nodes.py +0 -0
  31. {llparse-0.1.4 → llparse-0.1.6}/llparse/pyfront/peephole.py +0 -0
  32. {llparse-0.1.4 → llparse-0.1.6}/llparse/pyfront/transform.py +0 -0
  33. {llparse-0.1.4 → llparse-0.1.6}/llparse/settings.py +0 -0
  34. {llparse-0.1.4 → llparse-0.1.6}/llparse/spanalloc.py +0 -0
  35. {llparse-0.1.4 → llparse-0.1.6}/llparse/test.py +0 -0
  36. {llparse-0.1.4 → llparse-0.1.6}/llparse/trie.py +0 -0
  37. {llparse-0.1.4 → llparse-0.1.6}/llparse.egg-info/SOURCES.txt +0 -0
  38. {llparse-0.1.4 → llparse-0.1.6}/llparse.egg-info/dependency_links.txt +0 -0
  39. {llparse-0.1.4 → llparse-0.1.6}/llparse.egg-info/top_level.txt +0 -0
  40. {llparse-0.1.4 → llparse-0.1.6}/setup.cfg +0 -0
  41. {llparse-0.1.4 → llparse-0.1.6}/tests/test_loop_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llparse
3
- Version: 0.1.4
3
+ Version: 0.1.6
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
@@ -273,6 +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
+ class Operator(Field):
277
+ def __init__(self, ref: _frontend.code.Operator):
278
+ self.ref = ref
279
+
280
+ def doBuild(self, ctx: "Compilation", out: list[str]):
281
+ out.append(f'return {self.field(ctx)} {self.ref.op} {self.ref.value};')
282
+
276
283
 
277
284
  @dataclass
278
285
  class INodeEdge:
@@ -501,7 +508,7 @@ class Pause(Error):
501
508
 
502
509
  assert self.ref.otherwise
503
510
  otherwise = ctx.unwrapNode(self.ref.otherwise.node)
504
- out.append(f"{ctx.currentField()} = (void*) (intptr_t) {otherwise.cachedDecel};")
511
+ out.append(f"{ctx.currentField()} = (void*) (intptr_t) {otherwise.cachedDecel or ('s_n_' + otherwise.ref.id.name)};")
505
512
  out.append(f"return {STATE_ERROR};")
506
513
 
507
514
 
@@ -1218,6 +1225,8 @@ class Compilation:
1218
1225
  r = Test(ref)
1219
1226
  elif isinstance(ref, _frontend.code.Update):
1220
1227
  r = Update(ref)
1228
+ elif isinstance(ref, _frontend.code.Operator):
1229
+ r = Operator(ref)
1221
1230
  else:
1222
1231
  raise Exception(
1223
1232
  f'refrence "{ref.name}" is an Invalid Code Type , TypeName:"{ref.__class__.__name__}"'
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass, field
2
- from typing import Literal, Optional, Union
2
+ from typing import Literal, Optional, Union, TypeVar
3
3
 
4
4
  from .enumerator import Enumerator
5
5
  from .pybuilder import LoopChecker
@@ -22,6 +22,9 @@ from logging import getLogger
22
22
  log = getLogger("llparse.frontend")
23
23
 
24
24
 
25
+ CodeT = TypeVar('CodeT', bound=source.code.Code)
26
+ NodeT = TypeVar('NodeT', bound=source.node.Node)
27
+
25
28
  WrappedNode = IWrap[_frontend.node.Node]
26
29
  WrappedCode = IWrap[_frontend.code.Code]
27
30
 
@@ -462,7 +465,7 @@ class Frontend:
462
465
  return self.translateCode(code)
463
466
 
464
467
  def translateCode(
465
- self, code: source.code.Code
468
+ self, code: CodeT
466
469
  ):
467
470
  """Translates Builder Classes to Frontend Classes..."""
468
471
 
@@ -474,7 +477,13 @@ class Frontend:
474
477
  res = codeImpl.IsEqual(
475
478
  _frontend.code.IsEqual(prefixed, code.field, code.value)
476
479
  )
477
-
480
+ # custom thing I added in 0.1.6 I encourage the typescript
481
+ # maintainers and developers of llparse to look into this :)
482
+ elif isinstance(code, source.code.Operator):
483
+ res = codeImpl.Operator(_frontend.code.Operator(
484
+ prefixed, code.field, code.value, code.op
485
+ ))
486
+
478
487
  elif isinstance(code, source.code.Load):
479
488
  res = codeImpl.Load(_frontend.code.Load(prefixed, code.field))
480
489
 
@@ -36,10 +36,13 @@ class Creator:
36
36
  def __init__(self) -> None:
37
37
  return
38
38
 
39
- # TODO Make Sure python llparse match api is compatable with 3.10 and above...
39
+ # TODO (Vizonex): I think we could add a node for property copying from a to b
40
+ # and addition and subtraction nodes like a counter unlike consume and I think the typescript
41
+ # Library could have the same features as us. I seem to come up with new nodes often
42
+ # which is a rare thing to see. :)
40
43
 
41
44
  # Thank goodness I can do C example documentation in here :) - Vizonex
42
- def match(self, name: str):
45
+ def match(self, name: str) -> code.Match:
43
46
  """Create an external callback that **has no** `value` argument.
44
47
 
45
48
  This callback can be used in all `Invoke` nodes except those that are
@@ -53,14 +56,11 @@ class Creator:
53
56
 
54
57
  Where `llparse_t` is parser state's type name.
55
58
 
56
- Parameters
57
- ----------
58
- ----------
59
- - `name` External function name.
59
+ :param name: External function name.
60
60
  """
61
61
  return code._Match(name)
62
62
 
63
- def value(self, name: str):
63
+ def value(self, name: str) -> code.Value:
64
64
  """
65
65
 
66
66
  Create an external callback that **has** `value` argument.
@@ -76,15 +76,12 @@ class Creator:
76
76
 
77
77
  Where `llparse_t` is parser state's type name.
78
78
 
79
- Parameters
80
- ----------
81
- ----------
82
- - `name` External function name.
79
+ :param name: External function name.
83
80
 
84
81
  """
85
82
  return code.Value(name)
86
83
 
87
- def span(self, name: str):
84
+ def span(self, name: str) -> code._Span:
88
85
  """Create an external span callback.
89
86
 
90
87
  This callback can be used only in `Span` constructor.
@@ -100,30 +97,25 @@ class Creator:
100
97
 
101
98
  NOTE: non-zero return value is treated as resumable error.
102
99
 
103
- Parameters
104
- ----------
105
- - `name` External function name.
100
+ :param name: External function name.
106
101
  """
107
102
  return code._Span(name)
108
103
 
109
- def store(self, field: str):
104
+ def store(self, field: str) -> code.Store:
110
105
  """
111
106
  Intrinsic operation. Stores `value` from `.select()` node into the state's
112
107
  property with the name specified by `field`, returns zero.
113
108
 
114
109
  ```c
115
- state[field] = value;
116
- return 0;
110
+ state[field] = value;
111
+ return 0;
117
112
  ```
118
113
 
119
- Parameters
120
- ----------
121
-
122
- - `field` Property name
114
+ :param field: Property name
123
115
  """
124
116
  return code.Store(field)
125
117
 
126
- def load(self, field: str):
118
+ def load(self, field: str) -> code.Load:
127
119
  """Intrinsic operation. Loads and returns state's property with the name
128
120
  specified by `field`.
129
121
 
@@ -132,15 +124,14 @@ class Creator:
132
124
  ```c
133
125
  return state[field];
134
126
  ```
135
- Parameters
136
- ----------
137
- `field` Property name.
127
+
128
+ :param field: Property name.
138
129
  """
139
130
  return code.Load(field)
140
131
 
141
132
  def mulAdd(
142
133
  self, field: str, base: int, max: Optional[int] = None, signed: bool = False
143
- ):
134
+ ) -> code.MulAdd:
144
135
  """Intrinsic operation. Takes `value` from `.select()`, state's property
145
136
  with the name `field` and does:
146
137
  ```c
@@ -155,24 +146,21 @@ class Creator:
155
146
  - 0 - success
156
147
  - 1 - overflow
157
148
 
158
- Parameters
159
- ----------
160
- ----------
161
149
  Unlike in Typescript, The values of `IMulAddOptions` have been added here
162
150
  since it's Python , not Typescript
163
151
 
164
- - `field` Property name
152
+ :param field: Property name
165
153
 
166
- - `base` Value to multiply the property with in the first step
154
+ :param base: Value to multiply the property with in the first step
167
155
 
168
- - `max` Maximum value of the property. If at any point of computation the
156
+ :param max: Maximum value of the property. If at any point of computation the
169
157
  intermediate result exceeds it - `mulAdd` returns 1 (overflow).
170
158
 
171
- - `signed` If `true` - all arithmetics perfomed by `mulAdd` will be signed.
159
+ :param signed: If `true` - all arithmetics perfomed by `mulAdd` will be signed.
172
160
  Default value: `false`"""
173
161
  return code.MulAdd(field, base, max, signed)
174
162
 
175
- def update(self, field: str, value: int):
163
+ def update(self, field: str, value: int) -> code.Update:
176
164
  """
177
165
 
178
166
  Intrinsic operation. Puts `value` integer into the state's property with
@@ -181,75 +169,119 @@ class Creator:
181
169
  state[field] = value;
182
170
  return 0;
183
171
 
184
- Parameters
185
- ----------
186
- ----------
187
- - `field` Property name
188
- - `value` Integer value to be stored into the property.
172
+ :param field: Property name
173
+ :param value: Integer value to be stored into the property.
189
174
  """
190
175
  return code.Update(field, value)
191
176
 
192
- def isEqual(self, field: str, value: str):
177
+ def isEqual(self, field: str, value: str) -> code.IsEqual:
193
178
  """Intrinsic operation.
194
179
 
195
- state[field] &= value
196
- return 0;
180
+ ```c
181
+ state[field] &= value
182
+ return 0;
183
+ ```
197
184
 
198
- Parameters
199
- ----------
200
- ----------
201
- - `field` Property name
202
- - `value` Integer value
185
+ :param field: Property name
186
+ :param value: Integer value
203
187
  """
204
188
  return code.IsEqual(field, value)
205
189
 
206
190
  # NOTE : Unlike in typescript lowercase "and" & "or"
207
191
  # cannot be used this might have to be
208
192
  # throughly addressed - Vizonex
209
- def And(self, field: str, value: int):
193
+ def And(self, field: str, value: int) -> code.And:
210
194
  """Intrinsic operation.
211
195
 
212
- state[field] &= value
213
- return 0;
196
+ ```c
197
+ state[field] &= value
198
+ return 0;
199
+ ```
214
200
 
215
- Parameters
216
- ----------
217
- ----------
218
- - `field` Property name
219
- - `value` Integer value"""
201
+ :param field: Property name
202
+ :param value: Integer value
203
+ """
220
204
 
221
205
  return code.And(field, value)
222
206
 
223
- def Or(self, field: str, value: int):
207
+ def Or(self, field: str, value: int) -> code.Or:
224
208
  """
225
209
  Intrinsic operation.
226
210
 
227
211
  state[field] |= value
228
212
  return 0;
229
213
 
230
- Parameters
231
- ----------
232
- ----------
233
- - `field` Property name
234
- - `value` Integer value
214
+ :param field: Property name
215
+ :param value: Integer value
235
216
 
236
217
  This will allow us to set our own flags at will
237
218
  """
238
219
  return code.Or(field, value)
239
220
 
240
- def test(self, field: str, value: str):
221
+ def test(self, field: str, value: int) -> code.Test:
241
222
  """Intrinsic operation.
242
223
 
224
+ ```c
243
225
  return (state[field] & value) == value ? 1 : 0;
226
+ ```
244
227
 
245
- Parameters
246
- ----------
247
- ----------
248
- - `field` Property name
249
- - `value` Integer value
228
+ :param field: Property name
229
+ :param value: Integer value
250
230
  """
251
231
  return code.Test(field, value)
252
232
 
233
+ def is_gt(self, field: str, value: int) -> code.Operator:
234
+ """Intrinsic operation.
235
+
236
+ ```c
237
+ return (state[field] > value);
238
+ ```
239
+
240
+ :param field: Property name
241
+ :param value: Integer value
242
+ """
243
+
244
+ return code.Operator(">", field, value)
245
+
246
+ def is_lt(self, field: str, value: int) -> code.Operator:
247
+ """Intrinsic operation.
248
+
249
+ ```c
250
+ return (state[field] < value);
251
+ ```
252
+
253
+ :param field: Property name
254
+ :param value: Integer value
255
+ """
256
+
257
+ return code.Operator("<", field, value)
258
+
259
+ def is_le(self, field: str, value: int) -> code.Operator:
260
+ """Intrinsic operation.
261
+
262
+ ```c
263
+ return (state[field] <= value);
264
+ ```
265
+
266
+ :param field: Property name
267
+ :param value: Integer value
268
+ """
269
+
270
+ return code.Operator("<=", field, value)
271
+
272
+ def is_ge(self, field: str, value: int) -> code.Operator:
273
+ """Intrinsic operation.
274
+
275
+ ```c
276
+ return (state[field] >= value);
277
+ ```
278
+
279
+ :param field: Property name
280
+ :param value: Integer value
281
+ """
282
+
283
+ return code.Operator(">=", field, value)
284
+
253
285
 
254
286
  # NOTE: I have Nodes and Codes in the same file called `main_code`
255
287
  # as a tiny convienience for the sake a protability of not wanting
@@ -318,7 +350,7 @@ class Builder:
318
350
  """Return list of all allocated properties in parser's state."""
319
351
  return list(self.privProperties.values())
320
352
 
321
- def intBE(self, field: str, bits:int):
353
+ def intBE(self, field: str, bits: int):
322
354
  """
323
355
  :param field: State's property name
324
356
  :param bits: Number of bits to use
@@ -337,7 +369,7 @@ class Builder:
337
369
  def uintBE(self, field: str, bits: int):
338
370
  """
339
371
  return a node for unpacking arrays to integers
340
-
372
+
341
373
  :param field: State's property name
342
374
  :param bits: Number of bits to use
343
375
  """
@@ -346,9 +378,8 @@ class Builder:
346
378
  def uintLE(self, field: str, bits: int):
347
379
  """
348
380
  return a node for unpacking arrays to integers
349
-
381
+
350
382
  :param field: State's property name
351
383
  :param bits: Number of bits to use
352
384
  """
353
385
  return code.Int(field, bits, False, True)
354
-
@@ -80,6 +80,24 @@ class IsEqual(FieldValue):
80
80
  super().__init__("match", "is_equal", field, value)
81
81
 
82
82
 
83
+ OperatorsMap = {"<": "lt", ">": "gt", ">=": "ge", "<=": "le"}
84
+
85
+
86
+ class Operator(FieldValue):
87
+ """An Operator such as `>, <, >=, <=` made for dealing with
88
+ properties with infinate sizes"""
89
+
90
+ def __init__(self, op: str, field: str, value: int) -> None:
91
+ if name := OperatorsMap.get(op):
92
+ super().__init__("match", name, field, value)
93
+ # Make sure our operator can be remebered for later...
94
+ self.op = op
95
+ else:
96
+ raise NotImplementedError(
97
+ f"operator {op} not implemented or doesnt exist yet"
98
+ )
99
+
100
+
83
101
  class Load(Field):
84
102
  def __init__(self, field: str) -> None:
85
103
  super().__init__("match", "load", field)
@@ -92,8 +110,6 @@ class _Match(Code):
92
110
  super().__init__("match", name)
93
111
 
94
112
 
95
-
96
-
97
113
  @dataclass
98
114
  class IMulAddOptions:
99
115
  base: int
@@ -246,38 +262,41 @@ class Invoke(Node):
246
262
  self.addEdge(Edge(targetNode, True, numKey, None))
247
263
 
248
264
 
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
265
+ # Not in llparse node-js (yet) But I wanted to implement
266
+ # this into my version since I am making a very important
252
267
  # http2 frame parser
253
268
 
254
269
  # SEE: https://github.com/nodejs/llparse-frontend/pull/1
255
270
 
256
- def build_name(field:str, bits: int, signed:bool, little_endian:bool) -> str:
271
+
272
+ def build_name(field: str, bits: int, signed: bool, little_endian: bool) -> str:
257
273
  result = f"{field}_{'int' if signed else 'uint'}_{bits * 8}"
258
274
  if bits > 1:
259
- return result + ('_le' if little_endian else 'be')
275
+ return result + ("_le" if little_endian else "be")
260
276
  else:
261
277
  return result
262
278
 
263
279
 
264
280
  class Int(Node):
265
281
  """Used for parsing bytes via unpacking"""
266
- def __init__(self, field: str, bits: int, signed: bool, little_endian: bool) -> None:
282
+
283
+ def __init__(
284
+ self, field: str, bits: int, signed: bool, little_endian: bool
285
+ ) -> None:
267
286
  """
268
287
  :param field: State's property name
269
288
  :param bits: Number of bits to use
270
- :param signed: Number is signed
289
+ :param signed: Number is signed
271
290
  :param little_endian: true if le, false if be
272
291
  """
273
292
  if bits < 0:
274
293
  raise ValueError("bits should be a positive integer")
275
- self.field = field
294
+ self.field = field
276
295
  self.bits = bits
277
296
  self.signed = signed
278
- self.little_endian = little_endian
297
+ self.little_endian = little_endian
279
298
  super().__init__(build_name(field, bits, signed, little_endian))
280
-
299
+
281
300
 
282
301
  # -- Transfroms --
283
302
 
@@ -86,6 +86,14 @@ class IsEqual(FieldValue):
86
86
  )
87
87
 
88
88
 
89
+ class Operator(FieldValue):
90
+ def __init__(self, name: str, field: str, value: int, op: str):
91
+ super().__init__(
92
+ "match", f"is_{field}_{name}_{toCacheKey(value)}", f'{name}_{toCacheKey(value)}', field, value
93
+ )
94
+ self.op = op
95
+
96
+
89
97
  class Load(Field):
90
98
  """Subclass of Field"""
91
99
 
@@ -60,6 +60,7 @@ class ICodeImplementation:
60
60
  def __init__(self) -> None:
61
61
  return
62
62
 
63
+ # TODO: (Vizonex) Transform these functions to lamdas instead to conserve space...
63
64
  def And(self, c: code.And):
64
65
  return IWrap(c)
65
66
 
@@ -92,6 +93,9 @@ class ICodeImplementation:
92
93
 
93
94
  def Value(self, c: code.Value):
94
95
  return IWrap(c)
96
+
97
+ def Operator(self, c: code.Operator):
98
+ return IWrap(c)
95
99
 
96
100
 
97
101
  class IImplementation:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: llparse
3
- Version: 0.1.4
3
+ Version: 0.1.6
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "llparse"
3
- version = "0.1.4"
3
+ version = "0.1.6"
4
4
  description = "A Parody of llparse written for writing C Parsers with Python"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -0,0 +1,164 @@
1
+ from llparse import LLParse
2
+ from llparse.pybuilder.main_code import Operator
3
+
4
+ import pytest
5
+
6
+
7
+ @pytest.fixture(params=[">", "<", ">=", "<="])
8
+ def op(request: pytest.FixtureRequest) -> str:
9
+ return request.param
10
+
11
+
12
+ def test_build_tables():
13
+ # There was a bug with 1.2 of our version that doesn't affect the node-js one where
14
+ # it wouldn't building tables, this attempts to simulate the problem Currenlty this
15
+ # bug is patched now :)
16
+ p = LLParse("lltable")
17
+ start = p.node("start")
18
+ loop = p.node("loop")
19
+ loop.skipTo(start)
20
+ start.match(
21
+ [
22
+ 48,
23
+ 49,
24
+ 50,
25
+ 51,
26
+ 52,
27
+ 53,
28
+ 54,
29
+ 55,
30
+ 56,
31
+ 57,
32
+ 97,
33
+ 98,
34
+ 99,
35
+ 100,
36
+ 101,
37
+ 102,
38
+ 103,
39
+ 104,
40
+ 105,
41
+ 106,
42
+ 107,
43
+ 108,
44
+ 109,
45
+ 110,
46
+ 111,
47
+ 112,
48
+ 113,
49
+ 114,
50
+ 115,
51
+ 116,
52
+ 117,
53
+ 118,
54
+ 119,
55
+ 120,
56
+ 121,
57
+ 122,
58
+ 65,
59
+ 66,
60
+ 67,
61
+ 68,
62
+ 69,
63
+ 70,
64
+ 71,
65
+ 72,
66
+ 73,
67
+ 74,
68
+ 75,
69
+ 76,
70
+ 77,
71
+ 78,
72
+ 79,
73
+ 80,
74
+ 81,
75
+ 82,
76
+ 83,
77
+ 84,
78
+ 85,
79
+ 86,
80
+ 87,
81
+ 88,
82
+ 89,
83
+ 90,
84
+ 33,
85
+ 34,
86
+ 35,
87
+ 36,
88
+ 37,
89
+ 38,
90
+ 39,
91
+ 40,
92
+ 41,
93
+ 42,
94
+ 43,
95
+ 44,
96
+ 45,
97
+ 46,
98
+ 47,
99
+ 58,
100
+ 59,
101
+ 60,
102
+ 61,
103
+ 62,
104
+ 63,
105
+ 64,
106
+ 91,
107
+ 92,
108
+ 93,
109
+ 94,
110
+ 95,
111
+ 96,
112
+ 123,
113
+ 124,
114
+ 125,
115
+ 126,
116
+ 32,
117
+ 9,
118
+ 10,
119
+ 13,
120
+ 11,
121
+ 12,
122
+ ],
123
+ loop,
124
+ ).otherwise(p.error(0, "im a little teapot"))
125
+
126
+ # If there is not a lookup_table this then it has failed me ;-;
127
+ assert "lookup_table" in p.build(start).c
128
+
129
+
130
+ def test_pausing():
131
+ # Ensure frotentend LoopChecker does not mark off against Pausing
132
+ p = LLParse("lltest")
133
+ s = p.node("start")
134
+ s2 = p.node("start2")
135
+ s.match("p", p.pause(1, "parser was asked to pause").otherwise(s2)).skipTo(s)
136
+ s2.match("p", p.pause(2, "parser was asked to pause again").otherwise(s)).skipTo(s2)
137
+ p.build(s)
138
+
139
+
140
+ def test_operators(op: str):
141
+ test = LLParse("test")
142
+
143
+ test.property("i16", "a")
144
+
145
+ node = test.node("node_1")
146
+ # WARNING: Don't try and do this normally need operator exposed for making fixtures a bit easier.
147
+ node.match(
148
+ "1",
149
+ test.invoke(
150
+ Operator(op, "a", 10), {1: node}, test.error(1, "a is not greater than 10")
151
+ ),
152
+ ).otherwise(test.error(2, "lol"))
153
+
154
+ t = test.build(node)
155
+ code = t.c.splitlines(keepends=False)
156
+ assert f" return state->a {op} 10;" in code
157
+ if op == ">":
158
+ assert "int test__c_gt_a_10 (" in code
159
+ elif op == "<":
160
+ assert "int test__c_lt_a_10 (" in code
161
+ elif op == ">=":
162
+ assert "int test__c_ge_a_10 (" in code
163
+ elif op == "<=":
164
+ assert "int test__c_le_a_10 (" in code
@@ -54,7 +54,7 @@ def test_allocate_overlapping_spans(span_alloc: tuple[SpanAllocator, Builder]) -
54
54
  assert res.max == 1
55
55
 
56
56
  assert len(res.concurrency) == 2
57
-
57
+
58
58
  # python loves to shuffle things on me :/ but both exist nevertheless
59
59
  assert span2 in res.concurrency[0] or span1 in res.concurrency[0]
60
60
  assert span1 in res.concurrency[1] or span2 in res.concurrency[1]
@@ -106,16 +106,22 @@ def test_should_throw_on_loops(span_alloc: tuple[SpanAllocator, Builder]) -> Non
106
106
  with pytest.raises(Error, match=r"unmatched.*on_data"):
107
107
  sa.allocate(start)
108
108
 
109
- def test_propagate_through_invoke_map(span_alloc:tuple[SpanAllocator, Builder]):
109
+
110
+ def test_propagate_through_invoke_map(span_alloc: tuple[SpanAllocator, Builder]):
110
111
  sa, b = span_alloc
111
- start = b.node('start')
112
- span = b.span(b.code.span('llparse__on_data'))
112
+ start = b.node("start")
113
+ span = b.span(b.code.span("llparse__on_data"))
113
114
 
114
- b.property('i8', 'custom')
115
+ b.property("i8", "custom")
115
116
 
116
- start.otherwise(b.invoke(b.code.load('custom'), {
117
- 0: span.end().skipTo(start),
118
- }, span.end().skipTo(start)))
117
+ start.otherwise(
118
+ b.invoke(
119
+ b.code.load("custom"),
120
+ {
121
+ 0: span.end().skipTo(start),
122
+ },
123
+ span.end().skipTo(start),
124
+ )
125
+ )
119
126
 
120
127
  sa.allocate(span.start(start))
121
-
@@ -1,35 +0,0 @@
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
- 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