syncraft 0.1.31__tar.gz → 0.1.33__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.31 → syncraft-0.1.33}/PKG-INFO +1 -1
- {syncraft-0.1.31 → syncraft-0.1.33}/pyproject.toml +1 -1
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/ast.py +7 -2
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/syntax.py +18 -12
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft.egg-info/PKG-INFO +1 -1
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft.egg-info/SOURCES.txt +1 -0
- syncraft-0.1.33/tests/test_to.py +51 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/LICENSE +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/README.md +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/setup.cfg +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/__init__.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/algebra.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/constraint.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/diagnostic.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/finder.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/generator.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/parser.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/py.typed +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft/sqlite3.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft.egg-info/dependency_links.txt +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft.egg-info/requires.txt +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/syncraft.egg-info/top_level.txt +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/tests/test_bimap.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/tests/test_parse.py +0 -0
- {syncraft-0.1.31 → syncraft-0.1.33}/tests/test_until.py +0 -0
|
@@ -188,6 +188,11 @@ class AST:
|
|
|
188
188
|
|
|
189
189
|
@dataclass(frozen=True)
|
|
190
190
|
class Nothing(AST):
|
|
191
|
+
_instance = None
|
|
192
|
+
def __new__(cls):
|
|
193
|
+
if cls._instance is None:
|
|
194
|
+
cls._instance = super(Nothing, cls).__new__(cls)
|
|
195
|
+
return cls._instance
|
|
191
196
|
def __str__(self)->str:
|
|
192
197
|
return self.__class__.__name__
|
|
193
198
|
def __repr__(self)->str:
|
|
@@ -226,8 +231,8 @@ class Many(Generic[A], AST):
|
|
|
226
231
|
if len(bs) <= len(ret):
|
|
227
232
|
return Many(value = tuple(ret[i][1](bs[i]) for i in range(len(bs))))
|
|
228
233
|
else:
|
|
229
|
-
half = [ret[i][1](bs[i]) for i in range(len(
|
|
230
|
-
tmp = [ret[-1][1](bs[i]) for i in range(len(ret)
|
|
234
|
+
half = [ret[i][1](bs[i]) for i in range(len(ret))]
|
|
235
|
+
tmp = [ret[-1][1](bs[i]) for i in range(len(ret), len(bs))]
|
|
231
236
|
return Many(value = tuple(half + tmp))
|
|
232
237
|
return [v[0] for v in ret], inv
|
|
233
238
|
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import (
|
|
4
4
|
Optional, Any, TypeVar, Generic, Callable, Tuple, cast,
|
|
5
|
-
Type, Literal
|
|
5
|
+
Type, Literal, List
|
|
6
6
|
)
|
|
7
7
|
from dataclasses import dataclass, field, replace
|
|
8
8
|
from functools import reduce
|
|
@@ -168,21 +168,27 @@ class Syntax(Generic[A, S]):
|
|
|
168
168
|
def sep_by(self,
|
|
169
169
|
sep: Syntax[B, S]) -> Syntax[Then[A, Choice[Many[Then[B, A]], Optional[Nothing]]], S]:
|
|
170
170
|
ret: Syntax[Then[A, Choice[Many[Then[B, A]], Optional[Nothing]]], S] = (self + (sep >> self).many().optional())
|
|
171
|
-
def f(a: Then[A, Choice[Many[A], Optional[Nothing]]]) -> Many[A]:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return Many(value = (
|
|
175
|
-
|
|
176
|
-
return Many(value = (
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
171
|
+
def f(a: Then[A, Choice[Many[Then[B, A]], Optional[Nothing]]]) -> Many[A]:
|
|
172
|
+
match a:
|
|
173
|
+
case Then(kind=ThenKind.BOTH, left=left, right=Choice(kind=ChoiceKind.RIGHT, value=Nothing())):
|
|
174
|
+
return Many(value = (left,))
|
|
175
|
+
case Then(kind=ThenKind.BOTH, left=left, right=Choice(kind=ChoiceKind.LEFT, value=Many(value=bs))):
|
|
176
|
+
return Many(value = (left,) + tuple([b.right for b in bs]))
|
|
177
|
+
case _:
|
|
178
|
+
raise ValueError(f"Bad data shape {a}")
|
|
179
|
+
|
|
180
|
+
def i(a: Many[A]) -> Then[A, Choice[Many[Then[B|None, A]], Optional[Nothing]]]:
|
|
180
181
|
assert len(a.value) >= 1, f"sep_by expect at least one element, got {len(a.value)}. {a}"
|
|
181
182
|
if len(a.value) == 1:
|
|
182
183
|
return Then(kind=ThenKind.BOTH, left=a.value[0], right=Choice(kind=ChoiceKind.RIGHT, value=Nothing()))
|
|
183
184
|
else:
|
|
184
|
-
|
|
185
|
-
|
|
185
|
+
v: List[Then[B|None, A]] = [Then(kind=ThenKind.RIGHT, right=x, left=None) for x in a.value[1:]]
|
|
186
|
+
return Then(kind= ThenKind.BOTH,
|
|
187
|
+
left=a.value[0],
|
|
188
|
+
right=Choice(kind=ChoiceKind.LEFT,
|
|
189
|
+
value=Many(value=tuple(v))))
|
|
190
|
+
ret = ret.bimap(f,i) # type: ignore
|
|
191
|
+
return ret.describe(
|
|
186
192
|
name='sep_by',
|
|
187
193
|
fixity='prefix',
|
|
188
194
|
parameter=(self, sep))
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Any, List, Tuple
|
|
3
|
+
from syncraft.algebra import Either, Left, Right, Error
|
|
4
|
+
from syncraft.ast import Marked, Then, ThenKind, Many, Nothing
|
|
5
|
+
from syncraft.parser import literal, variable, parse, Parser, Token
|
|
6
|
+
from syncraft.generator import TokenGen
|
|
7
|
+
from rich import print
|
|
8
|
+
import syncraft.generator as gen
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_to() -> None:
|
|
13
|
+
@dataclass
|
|
14
|
+
class IfThenElse:
|
|
15
|
+
condition: Any
|
|
16
|
+
then: Any
|
|
17
|
+
otherwise: Any
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class While:
|
|
21
|
+
condition:Any
|
|
22
|
+
body:Any
|
|
23
|
+
|
|
24
|
+
WHILE = literal("while")
|
|
25
|
+
IF = literal("if")
|
|
26
|
+
ELSE = literal("else")
|
|
27
|
+
THEN = literal("then")
|
|
28
|
+
END = literal("end")
|
|
29
|
+
A = literal('a')
|
|
30
|
+
B = literal('b')
|
|
31
|
+
C = literal('c')
|
|
32
|
+
D = literal('d')
|
|
33
|
+
M = literal(',')
|
|
34
|
+
var = A | B | C | D
|
|
35
|
+
condition = var.sep_by(M).mark('condition')
|
|
36
|
+
ifthenelse = (IF >> condition
|
|
37
|
+
// THEN
|
|
38
|
+
+ var.sep_by(M).mark('then')
|
|
39
|
+
// ELSE
|
|
40
|
+
+ var.sep_by(M).mark('otherwise')
|
|
41
|
+
// END).to(IfThenElse).many()
|
|
42
|
+
syntax = (WHILE >> condition
|
|
43
|
+
+ ifthenelse.mark('body')
|
|
44
|
+
// ~END).to(While)
|
|
45
|
+
sql = 'while b,c,c if a,b then c,d else a,d end if a,b then c,d else a,d end'
|
|
46
|
+
ast = parse(syntax, sql, dialect='sqlite')
|
|
47
|
+
g = gen.generate(syntax, ast, restore_pruned=True)
|
|
48
|
+
assert ast == g
|
|
49
|
+
x, f = g.bimap()
|
|
50
|
+
print(x)
|
|
51
|
+
assert gen.generate(syntax, f(x), restore_pruned=True) == ast
|
|
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
|