syncraft 0.1.28__tar.gz → 0.1.29__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.

Potentially problematic release.


This version of syncraft might be problematic. Click here for more details.

Files changed (24) hide show
  1. {syncraft-0.1.28 → syncraft-0.1.29}/PKG-INFO +1 -1
  2. {syncraft-0.1.28 → syncraft-0.1.29}/pyproject.toml +1 -1
  3. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/algebra.py +4 -1
  4. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/ast.py +135 -144
  5. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/finder.py +13 -13
  6. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/generator.py +29 -18
  7. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/parser.py +4 -2
  8. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/syntax.py +2 -2
  9. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/PKG-INFO +1 -1
  10. {syncraft-0.1.28 → syncraft-0.1.29}/LICENSE +0 -0
  11. {syncraft-0.1.28 → syncraft-0.1.29}/README.md +0 -0
  12. {syncraft-0.1.28 → syncraft-0.1.29}/setup.cfg +0 -0
  13. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/__init__.py +0 -0
  14. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/constraint.py +0 -0
  15. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/diagnostic.py +0 -0
  16. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/py.typed +0 -0
  17. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/sqlite3.py +0 -0
  18. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/SOURCES.txt +0 -0
  19. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/dependency_links.txt +0 -0
  20. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/requires.txt +0 -0
  21. {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/top_level.txt +0 -0
  22. {syncraft-0.1.28 → syncraft-0.1.29}/tests/test_bimap.py +0 -0
  23. {syncraft-0.1.28 → syncraft-0.1.29}/tests/test_parse.py +0 -0
  24. {syncraft-0.1.28 → syncraft-0.1.29}/tests/test_until.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syncraft
3
- Version: 0.1.28
3
+ Version: 0.1.29
4
4
  Summary: Parser combinator library
5
5
  Author-email: Michael Afmokt <michael@esacca.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "syncraft"
3
- version = "0.1.28"
3
+ version = "0.1.29"
4
4
  description = "Parser combinator library"
5
5
  license = "MIT"
6
6
  license-files = ["LICENSE"]
@@ -8,7 +8,10 @@ import traceback
8
8
  from dataclasses import dataclass, replace, asdict
9
9
  from weakref import WeakKeyDictionary
10
10
  from abc import ABC
11
- from syncraft.ast import ThenKind, Then, S, Choice, Many, ChoiceKind
11
+ from syncraft.ast import ThenKind, Then, Choice, Many, ChoiceKind
12
+ from syncraft.constraint import Bindable
13
+
14
+ S = TypeVar('S', bound=Bindable)
12
15
 
13
16
  A = TypeVar('A') # Result type
14
17
  B = TypeVar('B') # Mapped result type
@@ -3,14 +3,14 @@
3
3
  from __future__ import annotations
4
4
  import re
5
5
  from typing import (
6
- Optional, Any, TypeVar, Tuple, runtime_checkable, Self,
7
- Dict, Generic, Callable, Union, Protocol, Type
6
+ Optional, Any, TypeVar, Tuple, runtime_checkable, cast,
7
+ Generic, Callable, Union, Protocol, Type, List, ClassVar
8
8
  )
9
9
 
10
10
 
11
- from dataclasses import dataclass
11
+ from dataclasses import dataclass, replace, is_dataclass, asdict, fields
12
12
  from enum import Enum
13
- from syncraft.constraint import Bindable
13
+
14
14
 
15
15
 
16
16
 
@@ -18,7 +18,9 @@ A = TypeVar('A')
18
18
  B = TypeVar('B')
19
19
  C = TypeVar('C')
20
20
  D = TypeVar('D')
21
- S = TypeVar('S', bound=Bindable)
21
+ S = TypeVar('S')
22
+ S1 = TypeVar('S1')
23
+
22
24
 
23
25
  @dataclass(frozen=True)
24
26
  class Biarrow(Generic[A, B]):
@@ -79,20 +81,6 @@ class Lens(Generic[C, A]):
79
81
  return other.__truediv__(self)
80
82
 
81
83
 
82
- @dataclass(frozen=True)
83
- class Reducer(Generic[A, S]):
84
- run_f: Callable[[A, S], S]
85
- def __call__(self, a: A, s: S) -> S:
86
- return self.run_f(a, s)
87
-
88
- def map(self, f: Callable[[B], A]) -> Reducer[B, S]:
89
- def map_run(b: B, s: S) -> S:
90
- return self(f(b), s)
91
- return Reducer(map_run)
92
-
93
- def __rshift__(self, other: Reducer[A, S]) -> Reducer[A, S]:
94
- return Reducer(lambda a, s: other(a, self(a, s)))
95
-
96
84
  @dataclass(frozen=True)
97
85
  class Bimap(Generic[A, B]):
98
86
  run_f: Callable[[A], Tuple[B, Callable[[B], A]]]
@@ -161,14 +149,36 @@ class Bimap(Generic[A, B]):
161
149
  return abc, inv_f
162
150
  return Bimap(when_run)
163
151
 
164
-
165
152
 
153
+ @dataclass(frozen=True)
154
+ class Reducer(Generic[A, S]):
155
+ run_f: Callable[[A, S], S]
156
+ def __call__(self, a: A, s: S) -> S:
157
+ return self.run_f(a, s)
166
158
 
159
+ def map(self, f: Callable[[B], A]) -> Reducer[B, S]:
160
+ def map_run(b: B, s: S) -> S:
161
+ return self(f(b), s)
162
+ return Reducer(map_run)
163
+
164
+ def __rshift__(self, other: Reducer[A, S]) -> Reducer[A, S]:
165
+ return Reducer(lambda a, s: other(a, self(a, s)))
166
+
167
+ def zip(self, other: Reducer[A, S1])-> Reducer[A, Tuple[S, S1]]:
168
+ return Reducer(lambda a, s: (self(a, s[0]), other(a, s[1])))
169
+
170
+ def diff(self, other: Reducer[B, S]) -> Reducer[Tuple[A, B], S]:
171
+ return Reducer(lambda ab, s: other(ab[1], self(ab[0], s)))
172
+
173
+ def filter(self, f: Callable[[A, S], bool]) -> Reducer[A, S]:
174
+ return Reducer(lambda a, s: self(a, s) if f(a, s) else s)
175
+
176
+
167
177
 
168
178
  @dataclass(frozen=True)
169
179
  class AST:
170
- def walk(self, r: Reducer[Any, S], s: S) -> S:
171
- return s
180
+ def bimap(self, r: Bimap[Any, Any]=Bimap.identity()) -> Tuple[Any, Callable[[Any], Any]]:
181
+ return r(self)
172
182
 
173
183
  @dataclass(frozen=True)
174
184
  class Nothing(AST):
@@ -182,19 +192,10 @@ class Nothing(AST):
182
192
  class Marked(Generic[A], AST):
183
193
  name: str
184
194
  value: A
185
- def walk(self, r: Reducer[A, S], s: S) -> S:
186
- return self.value.walk(r, s) if isinstance(self.value, AST) else r(self.value, s)
187
-
188
-
189
- class DataclassProtocol(Protocol):
190
- __dataclass_fields__: dict
191
-
192
- E = TypeVar("E")
193
- @dataclass(frozen=True)
194
- class Collect(Generic[A, E], AST):
195
- collector: Type[E]
196
- value: A
197
-
195
+ def bimap(self, r: Bimap[A, B]=Bimap.identity()) -> Tuple[Marked[B], Callable[[Marked[B]], Marked[A]]]:
196
+ v, inner_f = self.value.bimap(r) if isinstance(self.value, AST) else r(self.value)
197
+ return Marked(name=self.name, value=v), lambda b: Marked(name = b.name, value=inner_f(b.value))
198
+
198
199
  class ChoiceKind(Enum):
199
200
  LEFT = 'left'
200
201
  RIGHT = 'right'
@@ -203,49 +204,122 @@ class ChoiceKind(Enum):
203
204
  class Choice(Generic[A, B], AST):
204
205
  kind: Optional[ChoiceKind]
205
206
  value: Optional[A | B] = None
206
- def walk(self, r: Reducer[A | B, S], s: S) -> S:
207
- if self.value is not None:
208
- if isinstance(self.value, AST):
209
- return self.value.walk(r, s)
210
- else:
211
- return r(self.value, s)
212
- return s
207
+ def bimap(self, r: Bimap[A | B, C]=Bimap.identity()) -> Tuple[Optional[C], Callable[[Optional[C]], Choice[A, B]]]:
208
+ if self.value is None:
209
+ return None, lambda c: replace(self, value=None, kind=None)
210
+ else:
211
+ v, inv = self.value.bimap(r) if isinstance(self.value, AST) else r(self.value)
212
+ return v, lambda c: replace(self, value=inv(c) if c is not None else None, kind=None)
213
213
 
214
214
  @dataclass(frozen=True)
215
215
  class Many(Generic[A], AST):
216
216
  value: Tuple[A, ...]
217
- def walk(self, r: Reducer[A, S], s: S) -> S:
218
- for item in self.value:
219
- if isinstance(item, AST):
220
- s = item.walk(r, s)
217
+ def bimap(self, r: Bimap[A, B]=Bimap.identity()) -> Tuple[List[B], Callable[[List[B]], Many[A]]]:
218
+ ret = [v.bimap(r) if isinstance(v, AST) else r(v) for v in self.value]
219
+ def inv(bs: List[B]) -> Many[A]:
220
+ if len(bs) <= len(ret):
221
+ return Many(value = tuple(ret[i][1](bs[i]) for i in range(len(bs))))
221
222
  else:
222
- s = r(item, s)
223
- return s
223
+ half = [ret[i][1](bs[i]) for i in range(len(bs))]
224
+ tmp = [ret[-1][1](bs[i]) for i in range(len(ret)-1, len(bs))]
225
+ return Many(value = tuple(half + tmp))
226
+ return [v[0] for v in ret], inv
224
227
 
225
228
  class ThenKind(Enum):
226
229
  BOTH = '+'
227
230
  LEFT = '//'
228
231
  RIGHT = '>>'
229
232
 
230
- FlatThen = Tuple[Any, ...]
231
- MarkedThen = Tuple[Dict[str, Any] | Any, FlatThen]
232
-
233
233
  @dataclass(eq=True, frozen=True)
234
234
  class Then(Generic[A, B], AST):
235
235
  kind: ThenKind
236
236
  left: A
237
237
  right: B
238
- def walk(self, r: Reducer[A | B, S], s: S) -> S:
239
- if isinstance(self.left, AST):
240
- s = self.left.walk(r, s)
238
+ def arity(self)->int:
239
+ if self.kind == ThenKind.LEFT:
240
+ return self.left.arity() if isinstance(self.left, Then) else 1
241
+ elif self.kind == ThenKind.RIGHT:
242
+ return self.right.arity() if isinstance(self.right, Then) else 1
243
+ elif self.kind == ThenKind.BOTH:
244
+ left_arity = self.left.arity() if isinstance(self.left, Then) else 1
245
+ right_arity = self.right.arity() if isinstance(self.right, Then) else 1
246
+ return left_arity + right_arity
241
247
  else:
242
- s = r(self.left, s)
243
- if isinstance(self.right, AST):
244
- s = self.right.walk(r, s)
248
+ return 1
249
+
250
+ def bimap(self, r: Bimap[A|B, Any]=Bimap.identity()) -> Tuple[Any | Tuple[Any, ...], Callable[[Any | Tuple[Any, ...]], Then[A, B]]]:
251
+ def need_wrap(x: Any) -> bool:
252
+ return not (isinstance(x, Then) and x.kind == ThenKind.BOTH)
253
+ match self.kind:
254
+ case ThenKind.LEFT:
255
+ lb, linv = self.left.bimap(r) if isinstance(self.left, AST) else r(self.left)
256
+ return lb, lambda c: replace(self, left=cast(A, linv(c)))
257
+ case ThenKind.RIGHT:
258
+ rb, rinv = self.right.bimap(r) if isinstance(self.right, AST) else r(self.right)
259
+ return rb, lambda c: replace(self, right=cast(B, rinv(c)))
260
+ case ThenKind.BOTH:
261
+ lb, linv = self.left.bimap(r) if isinstance(self.left, AST) else r(self.left)
262
+ rb, rinv = self.right.bimap(r) if isinstance(self.right, AST) else r(self.right)
263
+ left_v = (lb,) if need_wrap(self.left) else lb
264
+ right_v = (rb,) if need_wrap(self.right) else rb
265
+ def invf(b: Tuple[C, ...]) -> Then[A, B]:
266
+ left_size = self.left.arity() if isinstance(self.left, Then) else 1
267
+ right_size = self.right.arity() if isinstance(self.right, Then) else 1
268
+ lraw: Tuple[Any, ...] = b[:left_size]
269
+ rraw: Tuple[Any, ...] = b[left_size:left_size + right_size]
270
+ lraw = lraw[0] if left_size == 1 else lraw
271
+ rraw = rraw[0] if right_size == 1 else rraw
272
+ la = linv(lraw)
273
+ ra = rinv(rraw)
274
+ return replace(self, left=cast(A, la), right=cast(B, ra))
275
+ return left_v + right_v, invf
276
+
277
+
278
+ class DataclassInstance(Protocol):
279
+ __dataclass_fields__: ClassVar[dict[str, Any]]
280
+
281
+
282
+ E = TypeVar("E", bound=DataclassInstance)
283
+
284
+ Collector = Type[E] | Callable[..., E]
285
+ @dataclass(frozen=True)
286
+ class Collect(Generic[A, E], AST):
287
+ collector: Collector
288
+ value: A
289
+ def bimap(self, r: Bimap[A, B]=Bimap.identity()) -> Tuple[B | E, Callable[[B | E], Collect[A, E]]]:
290
+ b, inner_f = r(self.value)
291
+ if isinstance(self.value, Then) and self.value.kind == ThenKind.BOTH:
292
+ assert isinstance(b, tuple), f"Expected tuple from Then.BOTH combinator, got {type(b)}"
293
+ index: List[str | int] = []
294
+ named_count = 0
295
+ for i, v in enumerate(b):
296
+ if isinstance(v, Marked):
297
+ index.append(v.name)
298
+ named_count += 1
299
+ else:
300
+ index.append(i - named_count)
301
+ named = {v.name: v.value for v in b if isinstance(v, Marked)}
302
+ unnamed = [v for v in b if not isinstance(v, Marked)]
303
+ ret: E = self.collector(*unnamed, **named)
304
+ def invf(e: E) -> Tuple[Any, ...]:
305
+ assert is_dataclass(e), f"Expected dataclass instance for collector inverse, got {type(e)}"
306
+ named_dict = asdict(e)
307
+ unnamed = []
308
+ for f in fields(e):
309
+ if f.name not in named:
310
+ unnamed.append(named_dict[f.name])
311
+ tmp = []
312
+ for x in index:
313
+ if isinstance(x, str):
314
+ tmp.append(Marked(name=x, value=named_dict[x]))
315
+ else:
316
+ tmp.append(unnamed[x])
317
+ return tuple(tmp)
318
+ return ret, lambda e: replace(self, value=inner_f(invf(e))) # type: ignore
245
319
  else:
246
- s = r(self.right, s)
247
- return s
320
+ return b, lambda e: replace(self, value=inner_f(e)) # type: ignore
248
321
 
322
+ #########################################################################################################################
249
323
  @dataclass(frozen=True)
250
324
  class Token(AST):
251
325
  token_type: Enum
@@ -255,11 +329,7 @@ class Token(AST):
255
329
 
256
330
  def __repr__(self) -> str:
257
331
  return self.__str__()
258
-
259
- def walk(self, r: Reducer['Token', S], s: S) -> S:
260
- return r(self, s)
261
-
262
-
332
+
263
333
  @runtime_checkable
264
334
  class TokenProtocol(Protocol):
265
335
  @property
@@ -290,89 +360,10 @@ ParseResult = Union[
290
360
  Marked['ParseResult[T]'],
291
361
  Choice['ParseResult[T]', 'ParseResult[T]'],
292
362
  Many['ParseResult[T]'],
363
+ Collect['ParseResult[T]', Any],
293
364
  Nothing,
294
365
  T,
295
366
  ]
296
367
 
297
368
 
298
369
 
299
- """
300
- @staticmethod
301
- def collect_marked(a: FlatThen, f: Optional[Callable[..., Any]] = None)->Tuple[MarkedThen, Callable[[MarkedThen], FlatThen]]:
302
- index: List[str | int] = []
303
- named_count = 0
304
- for i, v in enumerate(a):
305
- if isinstance(v, Marked):
306
- index.append(v.name)
307
- named_count += 1
308
- else:
309
- index.append(i - named_count)
310
- named = {v.name: v.value for v in a if isinstance(v, Marked)}
311
- unnamed = [v for v in a if not isinstance(v, Marked)]
312
- if f is None:
313
- ret = (named, tuple(unnamed))
314
- else:
315
- ret = (f(**named), tuple(unnamed))
316
- def invf(b: MarkedThen) -> Tuple[Any, ...]:
317
- named_value, unnamed_value = b
318
- assert isinstance(named_value, dict) or is_dataclass(named_value), f"Expected dict or dataclass for named values, got {type(named_value)}"
319
- if is_dataclass(named_value):
320
- named_dict = named | asdict(cast(Any, named_value))
321
- else:
322
- named_dict = named | named_value
323
- ret = []
324
- for x in index:
325
- if isinstance(x, str):
326
- assert x in named_dict, f"Missing named value: {x}"
327
- ret.append(named_dict[x])
328
- else:
329
- assert 0 <= x < len(unnamed_value), f"Missing unnamed value at index: {x}"
330
- ret.append(unnamed_value[x])
331
- return tuple(ret)
332
- return ret, invf
333
-
334
- def bimap(self, f: Bimap[Any, Any]=Bimap.identity()) -> Tuple[FlatThen, Callable[[FlatThen], Then[A, B]]]:
335
- match self.kind:
336
- case ThenKind.LEFT:
337
- lb, linv = self.left.bimap(f) if isinstance(self.left, AST) else f(self.left)
338
- return lb, lambda b: replace(self, left=linv(b))
339
- case ThenKind.RIGHT:
340
- rb, rinv = self.right.bimap(f) if isinstance(self.right, AST) else f(self.right)
341
- return rb, lambda b: replace(self, right=rinv(b))
342
- case ThenKind.BOTH:
343
- lb, linv = self.left.bimap(f) if isinstance(self.left, AST) else f(self.left)
344
- rb, rinv = self.right.bimap(f) if isinstance(self.right, AST) else f(self.right)
345
- left_v = (lb,) if not isinstance(self.left, Then) else lb
346
- right_v = (rb,) if not isinstance(self.right, Then) else rb
347
- def invf(b: Tuple[Any, ...]) -> Then[A, B]:
348
- left_size = self.left.arity() if isinstance(self.left, Then) else 1
349
- right_size = self.right.arity() if isinstance(self.right, Then) else 1
350
- lraw = b[:left_size]
351
- rraw = b[left_size:left_size + right_size]
352
- lraw = lraw[0] if left_size == 1 else lraw
353
- rraw = rraw[0] if right_size == 1 else rraw
354
- la = linv(lraw)
355
- ra = rinv(rraw)
356
- return replace(self, left=la, right=ra)
357
- return left_v + right_v, invf
358
-
359
- def bimap_collected(self, f: Bimap[Any, Any]=Bimap.identity()) -> Tuple[MarkedThen, Callable[[MarkedThen], Then[A, B]]]:
360
- data, invf = self.bimap(f)
361
- data, func = Then.collect_marked(data)
362
- return data, lambda d: invf(func(d))
363
-
364
-
365
- def arity(self)->int:
366
- if self.kind == ThenKind.LEFT:
367
- return self.left.arity() if isinstance(self.left, Then) else 1
368
- elif self.kind == ThenKind.RIGHT:
369
- return self.right.arity() if isinstance(self.right, Then) else 1
370
- elif self.kind == ThenKind.BOTH:
371
- left_arity = self.left.arity() if isinstance(self.left, Then) else 1
372
- right_arity = self.right.arity() if isinstance(self.right, Then) else 1
373
- return left_arity + right_arity
374
- else:
375
- return 1
376
-
377
-
378
- """
@@ -1,40 +1,40 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from typing import (
4
- Any, Tuple, Generator as YieldGen
4
+ Any, Tuple, Generator as YieldGen, TypeVar
5
5
  )
6
6
  from dataclasses import dataclass
7
7
  from syncraft.algebra import (
8
8
  Algebra, Either, Right,
9
9
  )
10
- from syncraft.ast import T, ParseResult, Choice, Many, Then, Marked
10
+ from syncraft.ast import TokenProtocol, ParseResult, Choice, Many, Then, Marked, Collect
11
11
 
12
12
  from syncraft.generator import GenState, Generator
13
13
 
14
14
  from syncraft.syntax import Syntax
15
15
 
16
16
 
17
-
17
+ T=TypeVar('T', bound=TokenProtocol)
18
18
  @dataclass(frozen=True)
19
19
  class Finder(Generator[T]):
20
20
  @classmethod
21
21
  def anything(cls)->Algebra[Any, GenState[T]]:
22
22
  def anything_run(input: GenState[T], use_cache:bool) -> Either[Any, Tuple[Any, GenState[T]]]:
23
23
  return Right((input.ast, input))
24
- return cls(anything_run, name=cls.__name__ + '.anything()')
24
+ return cls(anything_run, name=cls.__name__ + '.anything')
25
25
 
26
26
 
27
27
 
28
- anything = Syntax(lambda cls: cls.factory('anything')).describe(name="anything", fixity='infix')
28
+ anything = Syntax(lambda cls: cls.factory('anything')).describe(name="Anything", fixity='infix')
29
29
 
30
- def matches(syntax: Syntax[Any, Any], data: ParseResult[T])-> bool:
30
+ def matches(syntax: Syntax[Any, Any], data: ParseResult[Any])-> bool:
31
31
  gen = syntax(Finder)
32
- state = GenState.from_ast(ast = data, restore_pruned=True)
32
+ state = GenState[Any].from_ast(ast = data, restore_pruned=True)
33
33
  result = gen.run(state, use_cache=True)
34
34
  return isinstance(result, Right)
35
35
 
36
36
 
37
- def find(syntax: Syntax[Any, Any], data: ParseResult[T]) -> YieldGen[ParseResult[T], None, None]:
37
+ def find(syntax: Syntax[Any, Any], data: ParseResult[Any]) -> YieldGen[ParseResult[Any], None, None]:
38
38
  if matches(syntax, data):
39
39
  yield data
40
40
  match data:
@@ -48,10 +48,10 @@ def find(syntax: Syntax[Any, Any], data: ParseResult[T]) -> YieldGen[ParseResult
48
48
  yield from find(syntax, e)
49
49
  case Marked(value=value):
50
50
  yield from find(syntax, value)
51
- case Choice(left=left, right=right):
52
- if left is not None:
53
- yield from find(syntax, left)
54
- if right is not None:
55
- yield from find(syntax, right)
51
+ case Choice(value=value):
52
+ if value is not None:
53
+ yield from find(syntax, value)
54
+ case Collect(value=value):
55
+ yield from find(syntax, value)
56
56
  case _:
57
57
  pass
@@ -11,8 +11,8 @@ from syncraft.algebra import (
11
11
  )
12
12
 
13
13
  from syncraft.ast import (
14
- T, ParseResult, AST, Token, TokenSpec,
15
- Bindable, Nothing,
14
+ ParseResult, AST, Token, TokenSpec,
15
+ Nothing, TokenProtocol,
16
16
  Choice, Many, ChoiceKind,
17
17
  Then, ThenKind, Marked
18
18
  )
@@ -24,6 +24,14 @@ import rstr
24
24
  from functools import lru_cache
25
25
  import random
26
26
  from rich import print
27
+ from syncraft.constraint import Bindable
28
+
29
+ T = TypeVar('T', bound=TokenProtocol)
30
+
31
+ S = TypeVar('S', bound=Bindable)
32
+
33
+
34
+
27
35
  B = TypeVar('B')
28
36
 
29
37
 
@@ -63,9 +71,7 @@ class GenState(Bindable, Generic[T]):
63
71
  if isinstance(self.ast, Then) and (self.ast.kind != ThenKind.LEFT or self.restore_pruned):
64
72
  return replace(self, ast=self.ast.right)
65
73
  return replace(self, ast=None)
66
-
67
74
 
68
-
69
75
  def down(self, index: int) -> GenState[T]:
70
76
  if self.ast is None:
71
77
  return self
@@ -76,19 +82,27 @@ class GenState(Bindable, Generic[T]):
76
82
  raise TypeError(f"Invalid AST type({self.ast}) for down traversal")
77
83
 
78
84
  @classmethod
79
- def from_ast(cls, *, ast: Optional[ParseResult[T]], seed: int = 0, restore_pruned:bool=False) -> GenState[T]:
85
+ def from_ast(cls,
86
+ *,
87
+ ast: Optional[ParseResult[T]],
88
+ seed: int = 0,
89
+ restore_pruned:bool=False) -> GenState[T]:
80
90
  return cls(ast=ast, seed=seed, restore_pruned=restore_pruned)
81
91
 
82
-
83
-
84
-
85
-
86
92
  @lru_cache(maxsize=None)
87
- def token_type_from_string(token_type: Optional[TokenType], text: str, case_sensitive:bool)-> TokenType:
93
+ def token_type_from_string(token_type: Optional[TokenType],
94
+ text: str,
95
+ case_sensitive:bool = False)-> TokenType:
88
96
  if not isinstance(token_type, TokenType) or token_type == TokenType.VAR:
89
- for t in TokenType:
90
- if t.value == text or str(t.value).lower() == text.lower():
91
- return t
97
+ if case_sensitive:
98
+ for t in TokenType:
99
+ if t.value == text:
100
+ return t
101
+ else:
102
+ text = text.lower()
103
+ for t in TokenType:
104
+ if t.value == text or str(t.value).lower() == text:
105
+ return t
92
106
  return TokenType.VAR
93
107
  return token_type
94
108
 
@@ -121,13 +135,10 @@ class TokenGen(TokenSpec):
121
135
  else:
122
136
  text = "VALUE"
123
137
 
124
- return Token(token_type= token_type_from_string(self.token_type,
125
- text,
126
- self.case_sensitive),
127
- text=text)
138
+ return Token(token_type=token_type_from_string(self.token_type, text, case_sensitive=False), text=text)
128
139
 
129
140
  @staticmethod
130
- def from_string(string: str)->Token:
141
+ def from_string(string: str) -> Token:
131
142
  return Token(token_type=token_type_from_string(None, string, case_sensitive=False), text=string)
132
143
 
133
144
 
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
  import re
3
3
  from sqlglot import tokenize, TokenType, Parser as GlotParser, exp
4
4
  from typing import (
5
- Optional, List, Any, Tuple,
5
+ Optional, List, Any, Tuple, TypeVar,
6
6
  Generic
7
7
  )
8
8
  from syncraft.algebra import (
@@ -13,9 +13,11 @@ from enum import Enum
13
13
  from functools import reduce
14
14
  from syncraft.syntax import Syntax
15
15
 
16
- from syncraft.ast import Token, TokenSpec, AST, T, Bindable
16
+ from syncraft.ast import Token, TokenSpec, AST, TokenProtocol
17
+ from syncraft.constraint import Bindable
17
18
 
18
19
 
20
+ T = TypeVar('T', bound=TokenProtocol)
19
21
  @dataclass(frozen=True)
20
22
  class ParserState(Bindable, Generic[T]):
21
23
  input: Tuple[T, ...] = field(default_factory=tuple)
@@ -8,7 +8,7 @@ from dataclasses import dataclass, field, replace
8
8
  from functools import reduce
9
9
  from syncraft.algebra import Algebra, Error, Either, Right
10
10
  from syncraft.constraint import Variable, Bindable
11
- from syncraft.ast import Then, ThenKind, Marked, Choice, Many, ChoiceKind, Nothing, Collect, E
11
+ from syncraft.ast import Then, ThenKind, Marked, Choice, Many, ChoiceKind, Nothing, Collect, E, Collector
12
12
  from types import MethodType, FunctionType
13
13
 
14
14
  from rich import print
@@ -249,7 +249,7 @@ class Syntax(Generic[A, S]):
249
249
  ret = self.mark(var.name).map_all(bind_v) if var.name else self.map_all(bind_v)
250
250
  return ret.describe(name=f'bind({var.name})', fixity='postfix', parameter=(self,))
251
251
 
252
- def to(self, f: Type[E])-> Syntax[Collect[A, E], S]:
252
+ def to(self, f: Collector[E])-> Syntax[Collect[A, E], S]:
253
253
  def to_f(v: A) -> Collect[A, E]:
254
254
  if isinstance(v, Collect):
255
255
  return replace(v, collector=f)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syncraft
3
- Version: 0.1.28
3
+ Version: 0.1.29
4
4
  Summary: Parser combinator library
5
5
  Author-email: Michael Afmokt <michael@esacca.com>
6
6
  License-Expression: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes