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.
- {syncraft-0.1.28 → syncraft-0.1.29}/PKG-INFO +1 -1
- {syncraft-0.1.28 → syncraft-0.1.29}/pyproject.toml +1 -1
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/algebra.py +4 -1
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/ast.py +135 -144
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/finder.py +13 -13
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/generator.py +29 -18
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/parser.py +4 -2
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/syntax.py +2 -2
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/PKG-INFO +1 -1
- {syncraft-0.1.28 → syncraft-0.1.29}/LICENSE +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/README.md +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/setup.cfg +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/__init__.py +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/constraint.py +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/diagnostic.py +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/py.typed +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft/sqlite3.py +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/SOURCES.txt +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/dependency_links.txt +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/requires.txt +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/syncraft.egg-info/top_level.txt +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/tests/test_bimap.py +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/tests/test_parse.py +0 -0
- {syncraft-0.1.28 → syncraft-0.1.29}/tests/test_until.py +0 -0
|
@@ -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,
|
|
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,
|
|
7
|
-
|
|
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
|
-
|
|
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'
|
|
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
|
|
171
|
-
return
|
|
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
|
|
186
|
-
|
|
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
|
|
207
|
-
if self.value is
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
else
|
|
211
|
-
|
|
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
|
|
218
|
-
for
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
|
|
223
|
-
|
|
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
|
|
239
|
-
if
|
|
240
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
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
|
|
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="
|
|
28
|
+
anything = Syntax(lambda cls: cls.factory('anything')).describe(name="Anything", fixity='infix')
|
|
29
29
|
|
|
30
|
-
def matches(syntax: Syntax[Any, Any], data: ParseResult[
|
|
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[
|
|
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(
|
|
52
|
-
if
|
|
53
|
-
yield from find(syntax,
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
15
|
-
|
|
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,
|
|
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],
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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=
|
|
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,
|
|
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:
|
|
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)
|
|
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
|