syncraft 0.1.25__tar.gz → 0.1.26__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.
- {syncraft-0.1.25 → syncraft-0.1.26}/PKG-INFO +3 -3
- {syncraft-0.1.25 → syncraft-0.1.26}/README.md +2 -2
- {syncraft-0.1.25 → syncraft-0.1.26}/pyproject.toml +1 -1
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft/algebra.py +40 -24
- syncraft-0.1.26/syncraft/ast.py +187 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft/constraint.py +12 -4
- syncraft-0.1.26/syncraft/finder.py +57 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft/generator.py +92 -94
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft/parser.py +5 -7
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft/syntax.py +41 -39
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft.egg-info/PKG-INFO +3 -3
- {syncraft-0.1.25 → syncraft-0.1.26}/tests/test_bimap.py +56 -56
- {syncraft-0.1.25 → syncraft-0.1.26}/tests/test_parse.py +3 -3
- {syncraft-0.1.25 → syncraft-0.1.26}/tests/test_until.py +2 -2
- syncraft-0.1.25/syncraft/ast.py +0 -348
- syncraft-0.1.25/syncraft/finder.py +0 -79
- {syncraft-0.1.25 → syncraft-0.1.26}/LICENSE +0 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/setup.cfg +0 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft/__init__.py +0 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft/diagnostic.py +0 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft/py.typed +0 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft/sqlite3.py +0 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft.egg-info/SOURCES.txt +0 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft.egg-info/dependency_links.txt +0 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft.egg-info/requires.txt +0 -0
- {syncraft-0.1.25 → syncraft-0.1.26}/syncraft.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: syncraft
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.26
|
|
4
4
|
Summary: Parser combinator library
|
|
5
5
|
Author-email: Michael Afmokt <michael@esacca.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -31,7 +31,7 @@ pip install syncraft
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
## TODO
|
|
34
|
-
- [ ]
|
|
35
|
-
- [ ]
|
|
34
|
+
- [ ] simplify the result of then_left and then_right by bimap the result in syntax.
|
|
35
|
+
- [ ] simplify the result of sep_by and between by bimap the result in syntax
|
|
36
36
|
- [ ] Try the parsing, generation, and data processing machinery on SQLite3 syntax. So that I can have direct feedback on the usability of this library and a fully functional SQLite3 library.
|
|
37
37
|
- [ ] Make the library as fast as possible and feasible.
|
|
@@ -16,7 +16,7 @@ pip install syncraft
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
## TODO
|
|
19
|
-
- [ ]
|
|
20
|
-
- [ ]
|
|
19
|
+
- [ ] simplify the result of then_left and then_right by bimap the result in syntax.
|
|
20
|
+
- [ ] simplify the result of sep_by and between by bimap the result in syntax
|
|
21
21
|
- [ ] Try the parsing, generation, and data processing machinery on SQLite3 syntax. So that I can have direct feedback on the usability of this library and a fully functional SQLite3 library.
|
|
22
22
|
- [ ] Make the library as fast as possible and feasible.
|
|
@@ -8,7 +8,7 @@ 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,
|
|
11
|
+
from syncraft.ast import ThenKind, Then, S, Choice, Many, ChoiceKind
|
|
12
12
|
|
|
13
13
|
A = TypeVar('A') # Result type
|
|
14
14
|
B = TypeVar('B') # Mapped result type
|
|
@@ -235,15 +235,24 @@ class Algebra(ABC, Generic[A, S]):
|
|
|
235
235
|
return lazy_self
|
|
236
236
|
|
|
237
237
|
|
|
238
|
-
######################################################## fundamental combinators ############################################
|
|
239
|
-
def
|
|
240
|
-
def
|
|
238
|
+
######################################################## fundamental combinators ############################################
|
|
239
|
+
def fmap(self, f: Callable[[A], B]) -> Algebra[B, S]:
|
|
240
|
+
def fmap_run(input: S, use_cache:bool) -> Either[Any, Tuple[B, S]]:
|
|
241
241
|
parsed = self.run(input, use_cache)
|
|
242
242
|
if isinstance(parsed, Right):
|
|
243
243
|
return Right((f(parsed.value[0]), parsed.value[1]))
|
|
244
244
|
else:
|
|
245
245
|
return cast(Either[Any, Tuple[B, S]], parsed)
|
|
246
|
-
return self.__class__(
|
|
246
|
+
return self.__class__(fmap_run, name=self.name) # type: ignore
|
|
247
|
+
|
|
248
|
+
def imap(self, f: Callable[[B], A]) -> Algebra[A, S]:
|
|
249
|
+
return self.map_state(lambda s: s.map(f))
|
|
250
|
+
|
|
251
|
+
def map(self, f: Callable[[A], B]) -> Algebra[B, S]:
|
|
252
|
+
return self.fmap(f)
|
|
253
|
+
|
|
254
|
+
def bimap(self, f: Callable[[A], B], i: Callable[[B], A]) -> Algebra[A, S]:
|
|
255
|
+
return self.fmap(f).as_(Algebra[A, S]).imap(i)
|
|
247
256
|
|
|
248
257
|
def map_all(self, f: Callable[[Either[Any, Tuple[A, S]]], Either[Any, Tuple[B, S]]])->Algebra[B, S]:
|
|
249
258
|
def map_all_run(input: S, use_cache:bool) -> Either[Any, Tuple[B, S]]:
|
|
@@ -275,41 +284,48 @@ class Algebra(ABC, Generic[A, S]):
|
|
|
275
284
|
return self.__class__(flat_map_run, name=self.name) # type: ignore
|
|
276
285
|
|
|
277
286
|
|
|
278
|
-
def or_else(self: Algebra[A, S], other: Algebra[B, S]) -> Algebra[
|
|
279
|
-
def or_else_run(input: S, use_cache:bool) -> Either[Any, Tuple[
|
|
287
|
+
def or_else(self: Algebra[A, S], other: Algebra[B, S]) -> Algebra[Choice[A, B], S]:
|
|
288
|
+
def or_else_run(input: S, use_cache:bool) -> Either[Any, Tuple[Choice[A, B], S]]:
|
|
280
289
|
match self.run(input, use_cache):
|
|
281
290
|
case Right((value, state)):
|
|
282
|
-
return Right((
|
|
291
|
+
return Right((Choice(kind=ChoiceKind.LEFT, left=value, right=None), state))
|
|
283
292
|
case Left(err):
|
|
284
293
|
if isinstance(err, Error) and err.committed:
|
|
285
294
|
return Left(err)
|
|
286
295
|
match other.run(input, use_cache):
|
|
287
296
|
case Right((other_value, other_state)):
|
|
288
|
-
return Right((
|
|
297
|
+
return Right((Choice(kind=ChoiceKind.RIGHT, left=None, right=other_value), other_state))
|
|
289
298
|
case Left(other_err):
|
|
290
299
|
return Left(other_err)
|
|
291
300
|
raise TypeError(f"Unexpected result type from {other}")
|
|
292
301
|
raise TypeError(f"Unexpected result type from {self}")
|
|
293
302
|
return self.__class__(or_else_run, name=f'{self.name} | {other.name}') # type: ignore
|
|
294
303
|
|
|
295
|
-
def then_both(self, other: 'Algebra[B, S]') -> 'Algebra[
|
|
296
|
-
def then_both_f(a: A) -> Algebra[
|
|
297
|
-
def combine(b: B) ->
|
|
298
|
-
return
|
|
299
|
-
return other.
|
|
304
|
+
def then_both(self, other: 'Algebra[B, S]') -> 'Algebra[Then[A, B], S]':
|
|
305
|
+
def then_both_f(a: A) -> Algebra[Then[A, B], S]:
|
|
306
|
+
def combine(b: B) -> Then[A, B]:
|
|
307
|
+
return Then(left=a, right=b, kind=ThenKind.BOTH)
|
|
308
|
+
return other.fmap(combine)
|
|
300
309
|
return self.flat_map(then_both_f).named(f'{self.name} + {other.name}')
|
|
301
|
-
|
|
302
|
-
def then_left(self, other: Algebra[B, S]) -> Algebra[ThenResult[A, B], S]:
|
|
303
|
-
return self.then_both(other).map(lambda b: replace(b, kind = ThenKind.LEFT)).named(f'{self.name} // {other.name}')
|
|
304
|
-
|
|
305
|
-
def then_right(self, other: Algebra[B, S]) -> Algebra[ThenResult[A, B], S]:
|
|
306
|
-
return self.then_both(other).map(lambda b: replace(b, kind=ThenKind.RIGHT)).named(f'{self.name} >> {other.name}')
|
|
307
|
-
|
|
308
310
|
|
|
309
|
-
def
|
|
311
|
+
def then_left(self, other: Algebra[B, S]) -> 'Algebra[Then[A, B], S]':
|
|
312
|
+
def then_left_f(a: A) -> Algebra[Then[A, B], S]:
|
|
313
|
+
def combine(b: B) -> Then[A, B]:
|
|
314
|
+
return Then(left=a, right=b, kind=ThenKind.LEFT)
|
|
315
|
+
return other.fmap(combine)
|
|
316
|
+
return self.flat_map(then_left_f).named(f'{self.name} // {other.name}')
|
|
317
|
+
|
|
318
|
+
def then_right(self, other: Algebra[B, S]) -> 'Algebra[Then[A, B], S]':
|
|
319
|
+
def then_right_f(a: A) -> Algebra[Then[A, B], S]:
|
|
320
|
+
def combine(b: B) -> Then[A, B]:
|
|
321
|
+
return Then(left=a, right=b, kind=ThenKind.RIGHT)
|
|
322
|
+
return other.fmap(combine)
|
|
323
|
+
return self.flat_map(then_right_f).named(f'{self.name} >> {other.name}')
|
|
324
|
+
|
|
325
|
+
def many(self, *, at_least: int, at_most: Optional[int]) -> Algebra[Many[A], S]:
|
|
310
326
|
assert at_least > 0, "at_least must be greater than 0"
|
|
311
327
|
assert at_most is None or at_least <= at_most, "at_least must be less than or equal to at_most"
|
|
312
|
-
def many_run(input: S, use_cache:bool) -> Either[Any, Tuple[
|
|
328
|
+
def many_run(input: S, use_cache:bool) -> Either[Any, Tuple[Many[A], S]]:
|
|
313
329
|
ret: List[A] = []
|
|
314
330
|
current_input = input
|
|
315
331
|
while True:
|
|
@@ -333,7 +349,7 @@ class Algebra(ABC, Generic[A, S]):
|
|
|
333
349
|
this=self,
|
|
334
350
|
state=current_input
|
|
335
351
|
))
|
|
336
|
-
return Right((
|
|
352
|
+
return Right((Many(value=tuple(ret)), current_input))
|
|
337
353
|
return self.__class__(many_run, name=f'*({self.name})') # type: ignore
|
|
338
354
|
|
|
339
355
|
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import re
|
|
5
|
+
from typing import (
|
|
6
|
+
Optional, Any, TypeVar, Tuple, runtime_checkable,
|
|
7
|
+
Dict, Generic, Callable, Union, cast, List, Protocol, Type
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
from dataclasses import dataclass, replace, is_dataclass, asdict
|
|
12
|
+
from enum import Enum
|
|
13
|
+
|
|
14
|
+
from syncraft.constraint import Binding, Variable, Bindable
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
A = TypeVar('A')
|
|
19
|
+
B = TypeVar('B')
|
|
20
|
+
C = TypeVar('C')
|
|
21
|
+
S = TypeVar('S', bound=Bindable)
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True)
|
|
24
|
+
class Reducer(Generic[A, S]):
|
|
25
|
+
run_f: Callable[[A, S], S]
|
|
26
|
+
def __call__(self, a: A, s: S) -> S:
|
|
27
|
+
return self.run_f(a, s)
|
|
28
|
+
|
|
29
|
+
def map(self, f: Callable[[B], A]) -> Reducer[B, S]:
|
|
30
|
+
def map_run(b: B, s: S) -> S:
|
|
31
|
+
return self(f(b), s)
|
|
32
|
+
return Reducer(map_run)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass(frozen=True)
|
|
37
|
+
class Bimap(Generic[A, B]):
|
|
38
|
+
run_f: Callable[[A], Tuple[B, Callable[[B], A]]]
|
|
39
|
+
def __call__(self, a: A) -> Tuple[B, Callable[[B], A]]:
|
|
40
|
+
return self.run_f(a)
|
|
41
|
+
def __rshift__(self, other: Bimap[B, C]) -> Bimap[A, C]:
|
|
42
|
+
def then_run(a: A) -> Tuple[C, Callable[[C], A]]:
|
|
43
|
+
b, inv1 = self(a)
|
|
44
|
+
c, inv2 = other(b)
|
|
45
|
+
def inv(c2: C) -> A:
|
|
46
|
+
return inv1(inv2(c2))
|
|
47
|
+
return c, inv
|
|
48
|
+
return Bimap(then_run)
|
|
49
|
+
@staticmethod
|
|
50
|
+
def const(a: B)->Bimap[B, B]:
|
|
51
|
+
return Bimap(lambda _: (a, lambda b: b))
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def identity()->Bimap[Any, Any]:
|
|
55
|
+
return Bimap(lambda a: (a, lambda b: b))
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def when(cond: Callable[[A], bool],
|
|
59
|
+
then: Bimap[A, B],
|
|
60
|
+
otherwise: Optional[Bimap[A, C]] = None) -> Bimap[A, A | B | C]:
|
|
61
|
+
def when_run(a:A) -> Tuple[A | B | C, Callable[[A | B | C], A]]:
|
|
62
|
+
bimap = then if cond(a) else (otherwise if otherwise is not None else Bimap.identity())
|
|
63
|
+
abc, inv = bimap(a)
|
|
64
|
+
def inv_f(b: Any) -> A:
|
|
65
|
+
return inv(b)
|
|
66
|
+
return abc, inv_f
|
|
67
|
+
return Bimap(when_run)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass(frozen=True)
|
|
72
|
+
class Biarrow(Generic[S, A, B]):
|
|
73
|
+
forward: Callable[[S, A], Tuple[S, B]]
|
|
74
|
+
inverse: Callable[[S, B], Tuple[S, A]]
|
|
75
|
+
def __rshift__(self, other: Biarrow[S, B, C]) -> Biarrow[S, A, C]:
|
|
76
|
+
def fwd(s: S, a: A) -> Tuple[S, C]:
|
|
77
|
+
s1, b = self.forward(s, a)
|
|
78
|
+
return other.forward(s1, b)
|
|
79
|
+
def inv(s: S, c: C) -> Tuple[S, A]:
|
|
80
|
+
s1, b = other.inverse(s, c)
|
|
81
|
+
return self.inverse(s1, b)
|
|
82
|
+
return Biarrow(
|
|
83
|
+
forward=fwd,
|
|
84
|
+
inverse=inv
|
|
85
|
+
)
|
|
86
|
+
@staticmethod
|
|
87
|
+
def identity()->Biarrow[S, A, A]:
|
|
88
|
+
return Biarrow(
|
|
89
|
+
forward=lambda s, x: (s, x),
|
|
90
|
+
inverse=lambda s, y: (s, y)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def when(condition: Callable[..., bool],
|
|
95
|
+
then: Biarrow[S, A, B],
|
|
96
|
+
otherwise: Optional[Biarrow[S, A, B]] = None) -> Callable[..., Biarrow[S, A, B]]:
|
|
97
|
+
def _when(*args:Any, **kwargs:Any) -> Biarrow[S, A, B]:
|
|
98
|
+
return then if condition(*args, **kwargs) else (otherwise or Biarrow.identity())
|
|
99
|
+
return _when
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass(frozen=True)
|
|
103
|
+
class AST:
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
class ChoiceKind(Enum):
|
|
107
|
+
LEFT = 'left'
|
|
108
|
+
RIGHT = 'right'
|
|
109
|
+
@dataclass(frozen=True)
|
|
110
|
+
class Choice(Generic[A, B], AST):
|
|
111
|
+
kind: ChoiceKind
|
|
112
|
+
left: Optional[A]
|
|
113
|
+
right: Optional[B]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass(frozen=True)
|
|
117
|
+
class Many(Generic[A], AST):
|
|
118
|
+
value: Tuple[A, ...]
|
|
119
|
+
|
|
120
|
+
@dataclass(frozen=True)
|
|
121
|
+
class Marked(Generic[A], AST):
|
|
122
|
+
name: str
|
|
123
|
+
value: A
|
|
124
|
+
class ThenKind(Enum):
|
|
125
|
+
BOTH = '+'
|
|
126
|
+
LEFT = '//'
|
|
127
|
+
RIGHT = '>>'
|
|
128
|
+
|
|
129
|
+
FlatThen = Tuple[Any, ...]
|
|
130
|
+
MarkedThen = Tuple[Dict[str, Any] | Any, FlatThen]
|
|
131
|
+
|
|
132
|
+
@dataclass(eq=True, frozen=True)
|
|
133
|
+
class Then(Generic[A, B], AST):
|
|
134
|
+
kind: ThenKind
|
|
135
|
+
left: Optional[A]
|
|
136
|
+
right: Optional[B]
|
|
137
|
+
|
|
138
|
+
@runtime_checkable
|
|
139
|
+
class TokenProtocol(Protocol):
|
|
140
|
+
@property
|
|
141
|
+
def token_type(self) -> Enum: ...
|
|
142
|
+
@property
|
|
143
|
+
def text(self) -> str: ...
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclass(frozen=True)
|
|
147
|
+
class Token:
|
|
148
|
+
token_type: Enum
|
|
149
|
+
text: str
|
|
150
|
+
def __str__(self) -> str:
|
|
151
|
+
return f"{self.token_type.name}({self.text})"
|
|
152
|
+
|
|
153
|
+
def __repr__(self) -> str:
|
|
154
|
+
return self.__str__()
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@dataclass(frozen=True)
|
|
159
|
+
class TokenSpec:
|
|
160
|
+
token_type: Optional[Enum] = None
|
|
161
|
+
text: Optional[str] = None
|
|
162
|
+
case_sensitive: bool = False
|
|
163
|
+
regex: Optional[re.Pattern[str]] = None
|
|
164
|
+
|
|
165
|
+
def is_valid(self, token: TokenProtocol) -> bool:
|
|
166
|
+
type_match = self.token_type is None or token.token_type == self.token_type
|
|
167
|
+
value_match = self.text is None or (token.text.strip() == self.text.strip() if self.case_sensitive else
|
|
168
|
+
token.text.strip().upper() == self.text.strip().upper())
|
|
169
|
+
value_match = value_match or (self.regex is not None and self.regex.fullmatch(token.text) is not None)
|
|
170
|
+
return type_match and value_match
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
T = TypeVar('T', bound=TokenProtocol)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
ParseResult = Union[
|
|
179
|
+
Then['ParseResult[T]', 'ParseResult[T]'],
|
|
180
|
+
Marked['ParseResult[T]'],
|
|
181
|
+
Choice['ParseResult[T]', 'ParseResult[T]'],
|
|
182
|
+
Many['ParseResult[T]'],
|
|
183
|
+
T,
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import Callable, Generic, Tuple, TypeVar, Optional, Any,
|
|
2
|
+
from typing import Callable, Generic, Tuple, TypeVar, Optional, Any, Self
|
|
3
3
|
from enum import Enum
|
|
4
4
|
from dataclasses import dataclass, field, replace
|
|
5
5
|
import collections.abc
|
|
@@ -109,9 +109,17 @@ class Binding:
|
|
|
109
109
|
ret[var].append(node)
|
|
110
110
|
return FrozenDict({k: tuple(vs) for k, vs in ret.items()})
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
|
|
113
|
+
A = TypeVar('A')
|
|
114
|
+
@dataclass(frozen=True)
|
|
115
|
+
class Bindable:
|
|
116
|
+
binding: Binding = field(default_factory=Binding)
|
|
117
|
+
|
|
118
|
+
def map(self, f: Callable[[Any], Any])->Self:
|
|
119
|
+
return self
|
|
120
|
+
|
|
121
|
+
def bind(self, var: Variable, node:Any)->Self:
|
|
122
|
+
return replace(self, binding=self.binding.bind(var, node))
|
|
115
123
|
|
|
116
124
|
|
|
117
125
|
class Quantifier(Enum):
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import (
|
|
4
|
+
Any, Tuple, Optional, Generator as YieldGen
|
|
5
|
+
)
|
|
6
|
+
from dataclasses import dataclass, replace
|
|
7
|
+
from syncraft.algebra import (
|
|
8
|
+
Algebra, Either, Right,
|
|
9
|
+
)
|
|
10
|
+
from syncraft.ast import T, ParseResult, Choice, Many, Then, Marked
|
|
11
|
+
|
|
12
|
+
from syncraft.generator import GenState, Generator
|
|
13
|
+
from sqlglot import TokenType
|
|
14
|
+
from syncraft.syntax import Syntax
|
|
15
|
+
import re
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class Finder(Generator[T]):
|
|
20
|
+
@classmethod
|
|
21
|
+
def anything(cls)->Algebra[Any, GenState[T]]:
|
|
22
|
+
def anything_run(input: GenState[T], use_cache:bool) -> Either[Any, Tuple[Any, GenState[T]]]:
|
|
23
|
+
return Right((input.ast, input))
|
|
24
|
+
return cls(anything_run, name=cls.__name__ + '.anything()')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
anything = Syntax(lambda cls: cls.factory('anything')).describe(name="anything", fixity='infix')
|
|
29
|
+
|
|
30
|
+
def matches(syntax: Syntax[Any, Any], data: ParseResult[T])-> bool:
|
|
31
|
+
gen = syntax(Finder)
|
|
32
|
+
state = GenState.from_ast(ast = data, restore_pruned=True)
|
|
33
|
+
result = gen.run(state, use_cache=True)
|
|
34
|
+
return isinstance(result, Right)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def find(syntax: Syntax[Any, Any], data: ParseResult[T]) -> YieldGen[ParseResult[T], None, None]:
|
|
38
|
+
if matches(syntax, data):
|
|
39
|
+
yield data
|
|
40
|
+
match data:
|
|
41
|
+
case Then(left=left, right=right):
|
|
42
|
+
if left is not None:
|
|
43
|
+
yield from find(syntax, left)
|
|
44
|
+
if right is not None:
|
|
45
|
+
yield from find(syntax, right)
|
|
46
|
+
case Many(value = value):
|
|
47
|
+
for e in value:
|
|
48
|
+
yield from find(syntax, e)
|
|
49
|
+
case Marked(value=value):
|
|
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)
|
|
56
|
+
case _:
|
|
57
|
+
pass
|