syncraft 0.1.30__tar.gz → 0.1.31__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.30 → syncraft-0.1.31}/PKG-INFO +1 -1
- {syncraft-0.1.30 → syncraft-0.1.31}/pyproject.toml +1 -1
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/algebra.py +6 -3
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/ast.py +43 -32
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/syntax.py +22 -13
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/PKG-INFO +1 -1
- {syncraft-0.1.30 → syncraft-0.1.31}/LICENSE +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/README.md +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/setup.cfg +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/__init__.py +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/constraint.py +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/diagnostic.py +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/finder.py +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/generator.py +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/parser.py +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/py.typed +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/sqlite3.py +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/SOURCES.txt +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/dependency_links.txt +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/requires.txt +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/top_level.txt +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/tests/test_bimap.py +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/tests/test_parse.py +0 -0
- {syncraft-0.1.30 → syncraft-0.1.31}/tests/test_until.py +0 -0
|
@@ -5,12 +5,15 @@ from typing import (
|
|
|
5
5
|
)
|
|
6
6
|
|
|
7
7
|
import traceback
|
|
8
|
-
from dataclasses import dataclass, replace
|
|
8
|
+
from dataclasses import dataclass, replace
|
|
9
9
|
from weakref import WeakKeyDictionary
|
|
10
10
|
from abc import ABC
|
|
11
|
-
from syncraft.ast import ThenKind, Then, Choice, Many, ChoiceKind
|
|
11
|
+
from syncraft.ast import ThenKind, Then, Choice, Many, ChoiceKind, shallow_dict
|
|
12
12
|
from syncraft.constraint import Bindable
|
|
13
13
|
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
14
17
|
S = TypeVar('S', bound=Bindable)
|
|
15
18
|
|
|
16
19
|
A = TypeVar('A') # Result type
|
|
@@ -64,7 +67,7 @@ class Error:
|
|
|
64
67
|
lst = []
|
|
65
68
|
current: Optional[Error] = self
|
|
66
69
|
while current is not None:
|
|
67
|
-
d =
|
|
70
|
+
d = shallow_dict(current)
|
|
68
71
|
lst.append({k:v for k,v in d.items() if v is not None and k != 'previous'})
|
|
69
72
|
current = current.previous
|
|
70
73
|
return lst
|
|
@@ -4,14 +4,20 @@ from __future__ import annotations
|
|
|
4
4
|
import re
|
|
5
5
|
from typing import (
|
|
6
6
|
Optional, Any, TypeVar, Tuple, runtime_checkable, cast,
|
|
7
|
-
Generic, Callable, Union, Protocol, Type, List, ClassVar
|
|
7
|
+
Generic, Callable, Union, Protocol, Type, List, ClassVar,
|
|
8
|
+
Dict
|
|
8
9
|
)
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
from dataclasses import dataclass, replace, is_dataclass,
|
|
12
|
+
from dataclasses import dataclass, replace, is_dataclass, fields
|
|
12
13
|
from enum import Enum
|
|
13
14
|
|
|
14
15
|
|
|
16
|
+
def shallow_dict(a: Any)->Dict[str, Any]:
|
|
17
|
+
assert is_dataclass(a), f"Expected dataclass instance for collector inverse, got {type(a)}"
|
|
18
|
+
return {f.name: getattr(a, f.name) for f in fields(a)}
|
|
19
|
+
|
|
20
|
+
|
|
15
21
|
|
|
16
22
|
|
|
17
23
|
A = TypeVar('A')
|
|
@@ -287,37 +293,42 @@ class Collect(Generic[A, E], AST):
|
|
|
287
293
|
collector: Collector
|
|
288
294
|
value: A
|
|
289
295
|
def bimap(self, r: Bimap[A, B]=Bimap.identity()) -> Tuple[B | E, Callable[[B | E], Collect[A, E]]]:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
assert
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
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]))
|
|
296
|
+
|
|
297
|
+
def inv_one_positional(e: E) -> B:
|
|
298
|
+
assert is_dataclass(e), f"Expected dataclass instance for collector inverse, got {type(e)}"
|
|
299
|
+
named_dict = shallow_dict(e)
|
|
300
|
+
return named_dict[fields(e)[0].name]
|
|
301
|
+
|
|
302
|
+
b, inner_f = self.value.bimap(r) if isinstance(self.value, AST) else r(self.value)
|
|
303
|
+
if isinstance(self.value, Then):
|
|
304
|
+
if isinstance(b, tuple):
|
|
305
|
+
index: List[str | int] = []
|
|
306
|
+
named_count = 0
|
|
307
|
+
for i, v in enumerate(b):
|
|
308
|
+
if isinstance(v, Marked):
|
|
309
|
+
index.append(v.name)
|
|
310
|
+
named_count += 1
|
|
315
311
|
else:
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
312
|
+
index.append(i - named_count)
|
|
313
|
+
named = {v.name: v.value for v in b if isinstance(v, Marked)}
|
|
314
|
+
unnamed = [v for v in b if not isinstance(v, Marked)]
|
|
315
|
+
ret: E = self.collector(*unnamed, **named)
|
|
316
|
+
def invf(e: E) -> Tuple[Any, ...]:
|
|
317
|
+
assert is_dataclass(e), f"Expected dataclass instance for collector inverse, got {type(e)}"
|
|
318
|
+
named_dict = shallow_dict(e)
|
|
319
|
+
unnamed = []
|
|
320
|
+
for f in fields(e):
|
|
321
|
+
if f.name not in named:
|
|
322
|
+
unnamed.append(named_dict[f.name])
|
|
323
|
+
tmp = []
|
|
324
|
+
for x in index:
|
|
325
|
+
if isinstance(x, str):
|
|
326
|
+
tmp.append(Marked(name=x, value=named_dict[x]))
|
|
327
|
+
else:
|
|
328
|
+
tmp.append(unnamed[x])
|
|
329
|
+
return tuple(tmp)
|
|
330
|
+
return ret, lambda e: replace(self, value=inner_f(invf(e))) # type: ignore
|
|
331
|
+
return self.collector(b), lambda e: replace(self, value=inner_f(inv_one_positional(e))) # type: ignore
|
|
321
332
|
|
|
322
333
|
#########################################################################################################################
|
|
323
334
|
@dataclass(frozen=True)
|
|
@@ -165,9 +165,24 @@ class Syntax(Generic[A, S]):
|
|
|
165
165
|
def between(self, left: Syntax[B, S], right: Syntax[C, S]) -> Syntax[Then[B, Then[A, C]], S]:
|
|
166
166
|
return left >> self // right
|
|
167
167
|
|
|
168
|
-
def sep_by(self,
|
|
168
|
+
def sep_by(self,
|
|
169
|
+
sep: Syntax[B, S]) -> Syntax[Then[A, Choice[Many[Then[B, A]], Optional[Nothing]]], S]:
|
|
169
170
|
ret: Syntax[Then[A, Choice[Many[Then[B, A]], Optional[Nothing]]], S] = (self + (sep >> self).many().optional())
|
|
170
|
-
|
|
171
|
+
def f(a: Then[A, Choice[Many[A], Optional[Nothing]]]) -> Many[A]:
|
|
172
|
+
if a.right.kind == ChoiceKind.LEFT and isinstance(a.right.value, Many):
|
|
173
|
+
if len(a.right.value.value) == 0:
|
|
174
|
+
return Many(value = (a.left,))
|
|
175
|
+
else:
|
|
176
|
+
return Many(value = (a.left,) + a.right.value.value)
|
|
177
|
+
else:
|
|
178
|
+
return Many(value = (a.left,))
|
|
179
|
+
def i(a: Many[A]) -> Then[A, Choice[Many[A], Optional[Nothing]]]:
|
|
180
|
+
assert len(a.value) >= 1, f"sep_by expect at least one element, got {len(a.value)}. {a}"
|
|
181
|
+
if len(a.value) == 1:
|
|
182
|
+
return Then(kind=ThenKind.BOTH, left=a.value[0], right=Choice(kind=ChoiceKind.RIGHT, value=Nothing()))
|
|
183
|
+
else:
|
|
184
|
+
return Then(kind= ThenKind.BOTH, left=a.value[0], right=Choice(kind=ChoiceKind.LEFT, value=Many(value=a.value[1:])))
|
|
185
|
+
return ret.bimap(f,i).describe( # type: ignore
|
|
171
186
|
name='sep_by',
|
|
172
187
|
fixity='prefix',
|
|
173
188
|
parameter=(self, sep))
|
|
@@ -191,17 +206,11 @@ class Syntax(Generic[A, S]):
|
|
|
191
206
|
other = other if isinstance(other, Syntax) else self.lift(other).as_(Syntax[B, S])
|
|
192
207
|
ret: Syntax[Then[A, B], S] = self.__class__(lambda cls: self.alg(cls).then_left(other.alg(cls))) # type: ignore
|
|
193
208
|
return ret.describe(name=ThenKind.LEFT.value, fixity='infix', parameter=(self, other)).as_(Syntax[Then[A, B], S])
|
|
194
|
-
|
|
195
|
-
def __lshift__(self, other: Syntax[B, S]) -> Syntax[Then[A, B], S]:
|
|
196
|
-
return self.__floordiv__(other)
|
|
197
|
-
|
|
209
|
+
|
|
198
210
|
def __rfloordiv__(self, other: Syntax[B, S]) -> Syntax[Then[B, A], S]:
|
|
199
211
|
other = other if isinstance(other, Syntax) else self.lift(other).as_(Syntax[B, S])
|
|
200
212
|
return other.__floordiv__(self)
|
|
201
213
|
|
|
202
|
-
def __rlshift__(self, other: Syntax[B, S]) -> Syntax[Then[B, A], S]:
|
|
203
|
-
return self.__rfloordiv__(other)
|
|
204
|
-
|
|
205
214
|
def __add__(self, other: Syntax[B, S]) -> Syntax[Then[A, B], S]:
|
|
206
215
|
other = other if isinstance(other, Syntax) else self.lift(other).as_(Syntax[B, S])
|
|
207
216
|
ret: Syntax[Then[A, B], S] = self.__class__(lambda cls: self.alg(cls).then_both(other.alg(cls))) # type: ignore
|
|
@@ -260,16 +269,16 @@ class Syntax(Generic[A, S]):
|
|
|
260
269
|
return self.bimap(to_f, ito_f).describe(name=f'to({f})', fixity='postfix', parameter=(self,))
|
|
261
270
|
|
|
262
271
|
|
|
263
|
-
def mark(self,
|
|
272
|
+
def mark(self, name: str) -> Syntax[Marked[A], S]:
|
|
264
273
|
def bind_s(value: A) -> Marked[A]:
|
|
265
274
|
if isinstance(value, Marked):
|
|
266
|
-
return replace(value, name=
|
|
275
|
+
return replace(value, name=name)
|
|
267
276
|
else:
|
|
268
|
-
return Marked(name=
|
|
277
|
+
return Marked(name=name, value=value)
|
|
269
278
|
def ibind_s(m : Marked[A]) -> A:
|
|
270
279
|
return m.value if isinstance(m, Marked) else m
|
|
271
280
|
|
|
272
|
-
return self.bimap(bind_s, ibind_s).describe(name=f'bind("{
|
|
281
|
+
return self.bimap(bind_s, ibind_s).describe(name=f'bind("{name}")', fixity='postfix', parameter=(self,))
|
|
273
282
|
|
|
274
283
|
|
|
275
284
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|