syncraft 0.1.15__tar.gz → 0.1.17__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.15 → syncraft-0.1.17}/PKG-INFO +1 -1
- {syncraft-0.1.15 → syncraft-0.1.17}/pyproject.toml +1 -1
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/algebra.py +1 -11
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/ast.py +2 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/generator.py +29 -19
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft.egg-info/PKG-INFO +1 -1
- syncraft-0.1.17/tests/test_bimap.py +261 -0
- syncraft-0.1.15/tests/test_bimap.py +0 -88
- {syncraft-0.1.15 → syncraft-0.1.17}/LICENSE +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/README.md +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/setup.cfg +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/__init__.py +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/cmd.py +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/diagnostic.py +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/dsl.py +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/parser.py +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/py.typed +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft/sqlite3.py +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft.egg-info/SOURCES.txt +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft.egg-info/dependency_links.txt +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft.egg-info/requires.txt +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/syncraft.egg-info/top_level.txt +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/tests/test_parse.py +0 -0
- {syncraft-0.1.15 → syncraft-0.1.17}/tests/test_until.py +0 -0
|
@@ -170,17 +170,7 @@ class ThenResult(Generic[A, B], StructuralResult):
|
|
|
170
170
|
right: B
|
|
171
171
|
def bimap(self, ctx: Any) -> Tuple[Any, Callable[[Any], StructuralResult]]:
|
|
172
172
|
def branch(b: Any) -> Tuple[Any, Callable[[Any], StructuralResult]]:
|
|
173
|
-
if isinstance(b,
|
|
174
|
-
value, backward = b.bimap(ctx)
|
|
175
|
-
if isinstance(value, tuple):
|
|
176
|
-
x, y = ThenResult.flat(value)
|
|
177
|
-
return x, lambda data: ThenResult(self.kind, y(data), self.right)
|
|
178
|
-
else:
|
|
179
|
-
return value, backward
|
|
180
|
-
elif isinstance(b, StructuralResult):
|
|
181
|
-
return b.bimap(ctx)
|
|
182
|
-
else:
|
|
183
|
-
return b, lambda x: x
|
|
173
|
+
return b.bimap(ctx) if isinstance(b, StructuralResult) else (b, lambda x: x)
|
|
184
174
|
match self.kind:
|
|
185
175
|
case ThenKind.BOTH:
|
|
186
176
|
left_value, left_bmap = branch(self.left)
|
|
@@ -111,6 +111,7 @@ def token_type_from_string(token_type: Optional[TokenType], text: str, case_sens
|
|
|
111
111
|
|
|
112
112
|
@dataclass(frozen=True)
|
|
113
113
|
class TokenGen(TokenSpec):
|
|
114
|
+
|
|
114
115
|
def __str__(self) -> str:
|
|
115
116
|
tt = self.token_type.name if self.token_type else ""
|
|
116
117
|
txt = self.text if self.text else ""
|
|
@@ -141,30 +142,39 @@ class TokenGen(TokenSpec):
|
|
|
141
142
|
self.case_sensitive),
|
|
142
143
|
text=text)
|
|
143
144
|
|
|
144
|
-
|
|
145
|
+
@staticmethod
|
|
146
|
+
def from_string(string: str)->Token:
|
|
147
|
+
return Token(token_type=token_type_from_string(None, string, case_sensitive=False), text=string)
|
|
145
148
|
|
|
146
149
|
|
|
147
150
|
@dataclass(frozen=True)
|
|
148
151
|
class Generator(Algebra[GenResult[T], GenState[T]]):
|
|
149
152
|
def flat_map(self, f: Callable[[GenResult[T]], Algebra[B, GenState[T]]]) -> Algebra[B, GenState[T]]:
|
|
150
|
-
def flat_map_run(
|
|
151
|
-
wrapper =
|
|
152
|
-
input =
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
153
|
+
def flat_map_run(original: GenState[T], use_cache:bool) -> Either[Any, Tuple[B, GenState[T]]]:
|
|
154
|
+
wrapper = original.wrapper()
|
|
155
|
+
input = original if not original.is_named else original.down(0) # If the input is named, we need to go down to the first child
|
|
156
|
+
try:
|
|
157
|
+
lft = input.left()
|
|
158
|
+
match self.run(lft, use_cache=use_cache):
|
|
159
|
+
case Left(error):
|
|
160
|
+
return Left(error)
|
|
161
|
+
case Right((value, next_input)):
|
|
162
|
+
r = input.right()
|
|
163
|
+
match f(value).run(r, use_cache):
|
|
164
|
+
case Left(e):
|
|
165
|
+
return Left(e)
|
|
166
|
+
case Right((result, next_input)):
|
|
167
|
+
return Right((wrapper(result), next_input))
|
|
168
|
+
raise ValueError("flat_map should always return a value or an error.")
|
|
169
|
+
except Exception as e:
|
|
170
|
+
return Left(Error(
|
|
171
|
+
message=str(e),
|
|
172
|
+
this=self,
|
|
173
|
+
state=original,
|
|
174
|
+
error=e
|
|
175
|
+
))
|
|
176
|
+
return Generator(run_f = flat_map_run, name=self.name) # type: ignore
|
|
177
|
+
|
|
168
178
|
|
|
169
179
|
def many(self, *, at_least: int, at_most: Optional[int]) -> Algebra[ManyResult[GenResult[T]], GenState[T]]:
|
|
170
180
|
assert at_least > 0, "at_least must be greater than 0"
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from syncraft.algebra import NamedResult, Error, ManyResult, OrResult, ThenResult, ThenKind
|
|
3
|
+
from syncraft.parser import literal, parse, Parser
|
|
4
|
+
import syncraft.generator as gen
|
|
5
|
+
from syncraft.generator import TokenGen
|
|
6
|
+
from rich import print
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test1_simple_then() -> None:
|
|
10
|
+
A, B, C = literal("a"), literal("b"), literal("c")
|
|
11
|
+
syntax = A // B // C
|
|
12
|
+
sql = "a b c"
|
|
13
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
14
|
+
print("---" * 40)
|
|
15
|
+
print(ast)
|
|
16
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
17
|
+
print("---" * 40)
|
|
18
|
+
print(generated)
|
|
19
|
+
assert ast == generated
|
|
20
|
+
value, bmap = generated.bimap(None)
|
|
21
|
+
print(value)
|
|
22
|
+
assert bmap(value) == generated
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test2_named_results() -> None:
|
|
26
|
+
A, B = literal("a").bind("x").bind('z'), literal("b").bind("y")
|
|
27
|
+
syntax = A // B
|
|
28
|
+
sql = "a b"
|
|
29
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
30
|
+
print("---" * 40)
|
|
31
|
+
print(ast)
|
|
32
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
33
|
+
print("---" * 40)
|
|
34
|
+
print(generated)
|
|
35
|
+
assert ast == generated
|
|
36
|
+
value, bmap = generated.bimap(None)
|
|
37
|
+
print(value)
|
|
38
|
+
print(bmap(value))
|
|
39
|
+
assert bmap(value) == generated
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test3_many_literals() -> None:
|
|
43
|
+
A = literal("a")
|
|
44
|
+
syntax = A.many()
|
|
45
|
+
sql = "a a a"
|
|
46
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
47
|
+
print("---" * 40)
|
|
48
|
+
print(ast)
|
|
49
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
50
|
+
print("---" * 40)
|
|
51
|
+
print(generated)
|
|
52
|
+
assert ast == generated
|
|
53
|
+
value, bmap = generated.bimap(None)
|
|
54
|
+
print(value)
|
|
55
|
+
assert bmap(value) == generated
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test4_mixed_many_named() -> None:
|
|
59
|
+
A = literal("a").bind("x")
|
|
60
|
+
B = literal("b")
|
|
61
|
+
syntax = (A | B).many()
|
|
62
|
+
sql = "a b a"
|
|
63
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
64
|
+
print("---" * 40)
|
|
65
|
+
print(ast)
|
|
66
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
67
|
+
print("---" * 40)
|
|
68
|
+
print(generated)
|
|
69
|
+
assert ast == generated
|
|
70
|
+
value, bmap = generated.bimap(None)
|
|
71
|
+
print(value)
|
|
72
|
+
assert bmap(value) == generated
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test5_nested_then_many() -> None:
|
|
76
|
+
IF, THEN, END = literal("if"), literal("then"), literal("end")
|
|
77
|
+
syntax = (IF.many() // THEN.many()).many() // END
|
|
78
|
+
sql = "if if then end"
|
|
79
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
80
|
+
print("---" * 40)
|
|
81
|
+
print(ast)
|
|
82
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
83
|
+
print("---" * 40)
|
|
84
|
+
print(generated)
|
|
85
|
+
# assert ast == generated
|
|
86
|
+
value, bmap = generated.bimap(None)
|
|
87
|
+
print(value)
|
|
88
|
+
assert bmap(value) == generated
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_then_flatten():
|
|
93
|
+
A, B, C = literal("a"), literal("b"), literal("c")
|
|
94
|
+
syntax = A + (B + C)
|
|
95
|
+
sql = "a b c"
|
|
96
|
+
ast = parse(syntax(Parser), sql, dialect='sqlite')
|
|
97
|
+
print(ast)
|
|
98
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
99
|
+
assert ast == generated
|
|
100
|
+
value, bmap = ast.bimap(None)
|
|
101
|
+
assert bmap(value) == ast
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_named_in_then():
|
|
106
|
+
A = literal("a").bind("first")
|
|
107
|
+
B = literal("b").bind("second")
|
|
108
|
+
C = literal("c").bind("third")
|
|
109
|
+
syntax = A + B + C
|
|
110
|
+
sql = "a b c"
|
|
111
|
+
ast = parse(syntax(Parser), sql, dialect='sqlite')
|
|
112
|
+
print(ast)
|
|
113
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
114
|
+
assert ast == generated
|
|
115
|
+
value, bmap = ast.bimap(None)
|
|
116
|
+
assert isinstance(value, tuple)
|
|
117
|
+
print(value)
|
|
118
|
+
assert set(x.name for x in value if isinstance(x, NamedResult)) == {"first", "second", "third"}
|
|
119
|
+
assert bmap(value) == ast
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_named_in_many():
|
|
123
|
+
A = literal("x").bind("x")
|
|
124
|
+
syntax = A.many()
|
|
125
|
+
sql = "x x x"
|
|
126
|
+
ast = parse(syntax(Parser), sql, dialect='sqlite')
|
|
127
|
+
print(ast)
|
|
128
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
129
|
+
assert ast == generated
|
|
130
|
+
value, bmap = ast.bimap(None)
|
|
131
|
+
assert isinstance(value, list)
|
|
132
|
+
assert all(isinstance(v, NamedResult) for v in value if isinstance(v, NamedResult))
|
|
133
|
+
assert bmap(value) == ast
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_named_in_or():
|
|
137
|
+
A = literal("a").bind("a")
|
|
138
|
+
B = literal("b").bind("b")
|
|
139
|
+
syntax = A | B
|
|
140
|
+
sql = "b"
|
|
141
|
+
ast = parse(syntax(Parser), sql, dialect='sqlite')
|
|
142
|
+
print(ast)
|
|
143
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
144
|
+
assert ast == generated
|
|
145
|
+
value, bmap = ast.bimap(None)
|
|
146
|
+
assert isinstance(value, NamedResult)
|
|
147
|
+
assert value.name == "b"
|
|
148
|
+
assert bmap(value) == ast
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_deep_mix():
|
|
155
|
+
A = literal("a").bind("a")
|
|
156
|
+
B = literal("b")
|
|
157
|
+
C = literal("c").bind("c")
|
|
158
|
+
syntax = ((A + B) | C).many() + B
|
|
159
|
+
sql = "a b a b c b"
|
|
160
|
+
ast = parse(syntax(Parser), sql, dialect='sqlite')
|
|
161
|
+
print(ast)
|
|
162
|
+
generated = gen.generate(syntax(gen.Generator), ast)
|
|
163
|
+
print('---' * 40)
|
|
164
|
+
print(generated)
|
|
165
|
+
assert ast == generated
|
|
166
|
+
value, bmap = ast.bimap(None)
|
|
167
|
+
assert bmap(value) == ast
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def test_empty_many() -> None:
|
|
171
|
+
A = literal("a")
|
|
172
|
+
syntax = A.many() # This should allow empty matches
|
|
173
|
+
sql = ""
|
|
174
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
175
|
+
assert isinstance(ast, Error)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def test_backtracking_many() -> None:
|
|
179
|
+
A = literal("a")
|
|
180
|
+
B = literal("b")
|
|
181
|
+
syntax = (A.many() + B) # must not eat the final "a" needed for B
|
|
182
|
+
sql = "a a a a b"
|
|
183
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
184
|
+
value, bmap = ast.bimap(None)
|
|
185
|
+
assert value[-1] == TokenGen.from_string("b")
|
|
186
|
+
|
|
187
|
+
def test_deep_nesting() -> None:
|
|
188
|
+
A = literal("a")
|
|
189
|
+
syntax = A
|
|
190
|
+
for _ in range(100):
|
|
191
|
+
syntax = syntax + A
|
|
192
|
+
sql = " " .join("a" for _ in range(101))
|
|
193
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
194
|
+
assert ast is not None
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def test_nested_many() -> None:
|
|
198
|
+
A = literal("a")
|
|
199
|
+
syntax = (A.many().many()) # groups of groups of "a"
|
|
200
|
+
sql = "a a a"
|
|
201
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
202
|
+
assert isinstance(ast.focus, ManyResult)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def test_named_many() -> None:
|
|
206
|
+
A = literal("a").bind("alpha")
|
|
207
|
+
syntax = A.many()
|
|
208
|
+
sql = "a a"
|
|
209
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
210
|
+
# Expect [NamedResult("alpha", "a"), NamedResult("alpha", "a")]
|
|
211
|
+
flattened, _ = ast.bimap(None)
|
|
212
|
+
assert all(isinstance(x, NamedResult) for x in flattened)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_or_named() -> None:
|
|
216
|
+
A = literal("a").bind("x")
|
|
217
|
+
B = literal("b").bind("y")
|
|
218
|
+
syntax = A | B
|
|
219
|
+
sql = "b"
|
|
220
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
221
|
+
# Either NamedResult("y", "b") or just "b", depending on your design
|
|
222
|
+
assert isinstance(ast.focus, OrResult)
|
|
223
|
+
value, _ = ast.bimap(None)
|
|
224
|
+
assert value == NamedResult(name="y", value=TokenGen.from_string("b"))
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def test_then_associativity() -> None:
|
|
228
|
+
A = literal("a")
|
|
229
|
+
B = literal("b")
|
|
230
|
+
C = literal("c")
|
|
231
|
+
syntax = A + B + C
|
|
232
|
+
sql = "a b c"
|
|
233
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
234
|
+
# Should be ThenResult(ThenResult(A,B),C)
|
|
235
|
+
assert ast.focus == ThenResult(kind=ThenKind.BOTH,
|
|
236
|
+
left=ThenResult(kind=ThenKind.BOTH,
|
|
237
|
+
left=TokenGen.from_string('a'),
|
|
238
|
+
right=TokenGen.from_string('b')),
|
|
239
|
+
right=TokenGen.from_string('c'))
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def test_ambiguous() -> None:
|
|
243
|
+
A = literal("a")
|
|
244
|
+
B = literal("a") + literal("b")
|
|
245
|
+
syntax = A | B
|
|
246
|
+
sql = "a"
|
|
247
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
248
|
+
# Does it prefer A (shorter) or B (fails)? Depends on design.
|
|
249
|
+
assert ast.focus == OrResult(TokenGen.from_string("a"))
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def test_combo() -> None:
|
|
253
|
+
A = literal("a").bind("a")
|
|
254
|
+
B = literal("b")
|
|
255
|
+
C = literal("c").bind("c")
|
|
256
|
+
syntax = ((A + B).many() | C) + B
|
|
257
|
+
sql = "a b a b c b"
|
|
258
|
+
# Should fail, as we discussed earlier
|
|
259
|
+
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
260
|
+
assert isinstance(ast, Error)
|
|
261
|
+
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
from syncraft.parser import literal, variable, parse, Parser
|
|
3
|
-
from syncraft.ast import AST
|
|
4
|
-
import syncraft.generator as gen
|
|
5
|
-
from typing import Any
|
|
6
|
-
from rich import print
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def test1_simple_then() -> None:
|
|
10
|
-
A, B, C = literal("a"), literal("b"), literal("c")
|
|
11
|
-
syntax = A // B // C
|
|
12
|
-
sql = "a b c"
|
|
13
|
-
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
14
|
-
print("---" * 40)
|
|
15
|
-
print(ast)
|
|
16
|
-
generated = gen.generate(syntax(gen.Generator), ast)
|
|
17
|
-
print("---" * 40)
|
|
18
|
-
print(generated)
|
|
19
|
-
assert ast == generated
|
|
20
|
-
value, bmap = generated.bimap(None)
|
|
21
|
-
print(value)
|
|
22
|
-
assert bmap(value) == generated
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def test2_named_results() -> None:
|
|
26
|
-
A, B = literal("a").bind("x").bind('z'), literal("b").bind("y")
|
|
27
|
-
syntax = A // B
|
|
28
|
-
sql = "a b"
|
|
29
|
-
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
30
|
-
print("---" * 40)
|
|
31
|
-
print(ast)
|
|
32
|
-
generated = gen.generate(syntax(gen.Generator), ast)
|
|
33
|
-
print("---" * 40)
|
|
34
|
-
print(generated)
|
|
35
|
-
assert ast == generated
|
|
36
|
-
value, bmap = generated.bimap(None)
|
|
37
|
-
print(value)
|
|
38
|
-
print(bmap(value))
|
|
39
|
-
assert bmap(value) == generated
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def test3_many_literals() -> None:
|
|
43
|
-
A = literal("a")
|
|
44
|
-
syntax = A.many()
|
|
45
|
-
sql = "a a a"
|
|
46
|
-
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
47
|
-
print("---" * 40)
|
|
48
|
-
print(ast)
|
|
49
|
-
generated = gen.generate(syntax(gen.Generator), ast)
|
|
50
|
-
print("---" * 40)
|
|
51
|
-
print(generated)
|
|
52
|
-
assert ast == generated
|
|
53
|
-
value, bmap = generated.bimap(None)
|
|
54
|
-
print(value)
|
|
55
|
-
assert bmap(value) == generated
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def test4_mixed_many_named() -> None:
|
|
59
|
-
A = literal("a").bind("x")
|
|
60
|
-
B = literal("b")
|
|
61
|
-
syntax = (A | B).many()
|
|
62
|
-
sql = "a b a"
|
|
63
|
-
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
64
|
-
print("---" * 40)
|
|
65
|
-
print(ast)
|
|
66
|
-
generated = gen.generate(syntax(gen.Generator), ast)
|
|
67
|
-
print("---" * 40)
|
|
68
|
-
print(generated)
|
|
69
|
-
assert ast == generated
|
|
70
|
-
value, bmap = generated.bimap(None)
|
|
71
|
-
print(value)
|
|
72
|
-
assert bmap(value) == generated
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def test5_nested_then_many() -> None:
|
|
76
|
-
IF, THEN, END = literal("if"), literal("then"), literal("end")
|
|
77
|
-
syntax = (IF.many() // THEN.many()).many() // END
|
|
78
|
-
sql = "if if then end"
|
|
79
|
-
ast = parse(syntax(Parser), sql, dialect="sqlite")
|
|
80
|
-
print("---" * 40)
|
|
81
|
-
print(ast)
|
|
82
|
-
generated = gen.generate(syntax(gen.Generator), ast)
|
|
83
|
-
print("---" * 40)
|
|
84
|
-
print(generated)
|
|
85
|
-
# assert ast == generated
|
|
86
|
-
value, bmap = generated.bimap(None)
|
|
87
|
-
print(value)
|
|
88
|
-
assert bmap(value) == generated
|
|
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
|