syncraft 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl
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/algebra.py +5 -2
- syncraft/constraint.py +28 -8
- syncraft/generator.py +9 -10
- syncraft/parser.py +10 -13
- syncraft/syntax.py +15 -49
- {syncraft-0.2.0.dist-info → syncraft-0.2.2.dist-info}/METADATA +1 -1
- syncraft-0.2.2.dist-info/RECORD +16 -0
- syncraft-0.2.0.dist-info/RECORD +0 -16
- {syncraft-0.2.0.dist-info → syncraft-0.2.2.dist-info}/WHEEL +0 -0
- {syncraft-0.2.0.dist-info → syncraft-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {syncraft-0.2.0.dist-info → syncraft-0.2.2.dist-info}/top_level.txt +0 -0
syncraft/algebra.py
CHANGED
|
@@ -7,7 +7,6 @@ from typing import (
|
|
|
7
7
|
import traceback
|
|
8
8
|
from dataclasses import dataclass, replace
|
|
9
9
|
from weakref import WeakKeyDictionary
|
|
10
|
-
from abc import ABC
|
|
11
10
|
from syncraft.ast import ThenKind, Then, Choice, Many, ChoiceKind, shallow_dict
|
|
12
11
|
from syncraft.constraint import Bindable
|
|
13
12
|
|
|
@@ -75,12 +74,16 @@ class Error:
|
|
|
75
74
|
|
|
76
75
|
|
|
77
76
|
@dataclass(frozen=True)
|
|
78
|
-
class Algebra(
|
|
77
|
+
class Algebra(Generic[A, S]):
|
|
79
78
|
######################################################## shared among all subclasses ########################################################
|
|
80
79
|
run_f: Callable[[S, bool], Either[Any, Tuple[A, S]]]
|
|
81
80
|
name: Hashable
|
|
82
81
|
_cache: ClassVar[WeakKeyDictionary[Any, Dict[Any, object | Either[Any, Tuple[Any, Any]]]]] = WeakKeyDictionary()
|
|
83
82
|
|
|
83
|
+
@classmethod
|
|
84
|
+
def state(cls, *args:Any, **kwargs:Any)->Optional[S]:
|
|
85
|
+
return None
|
|
86
|
+
|
|
84
87
|
def named(self, name: Hashable) -> 'Algebra[A, S]':
|
|
85
88
|
return replace(self, name=name)
|
|
86
89
|
|
syncraft/constraint.py
CHANGED
|
@@ -5,6 +5,7 @@ from dataclasses import dataclass, field, replace
|
|
|
5
5
|
import collections.abc
|
|
6
6
|
from collections import defaultdict
|
|
7
7
|
from itertools import product
|
|
8
|
+
from inspect import Signature
|
|
8
9
|
import inspect
|
|
9
10
|
|
|
10
11
|
K = TypeVar('K')
|
|
@@ -122,9 +123,9 @@ class Constraint:
|
|
|
122
123
|
def predicate(cls,
|
|
123
124
|
f: Callable[..., bool],
|
|
124
125
|
*,
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
sig: Signature,
|
|
127
|
+
name: str,
|
|
128
|
+
quant: Quantifier)->Constraint:
|
|
128
129
|
pos_params = []
|
|
129
130
|
kw_params = []
|
|
130
131
|
for pname, param in sig.parameters.items():
|
|
@@ -160,12 +161,31 @@ class Constraint:
|
|
|
160
161
|
else:
|
|
161
162
|
return ConstraintResult(result = all(eval_combo(c) for c in all_combos), unbound=frozenset())
|
|
162
163
|
|
|
163
|
-
return cls(run_f=run_f, name=name
|
|
164
|
+
return cls(run_f=run_f, name=name)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def predicate(f: Callable[..., bool],
|
|
168
|
+
*,
|
|
169
|
+
name: Optional[str] = None,
|
|
170
|
+
quant: Quantifier = Quantifier.FORALL,
|
|
171
|
+
bimap: bool = True) -> Constraint:
|
|
172
|
+
name = name or f.__name__
|
|
173
|
+
sig = inspect.signature(f)
|
|
174
|
+
if bimap:
|
|
175
|
+
def wrapper(*args: Any, **kwargs:Any) -> bool:
|
|
176
|
+
mapped_args = [a.bimap()[0] if hasattr(a, "bimap") else a for a in args]
|
|
177
|
+
mapped_kwargs = {k: (v.bimap()[0] if hasattr(v, "bimap") else v) for k,v in kwargs.items()}
|
|
178
|
+
return f(*mapped_args, **mapped_kwargs)
|
|
179
|
+
|
|
180
|
+
return Constraint.predicate(wrapper, sig=sig, name=name, quant=quant)
|
|
181
|
+
else:
|
|
182
|
+
return Constraint.predicate(f, sig=sig, name=name, quant=quant)
|
|
164
183
|
|
|
165
|
-
def forall(f: Callable[..., bool], name: Optional[str] = None) -> Constraint:
|
|
166
|
-
return
|
|
184
|
+
def forall(f: Callable[..., bool], name: Optional[str] = None, bimap: bool=True) -> Constraint:
|
|
185
|
+
return predicate(f, name=name, quant=Quantifier.FORALL, bimap=bimap)
|
|
167
186
|
|
|
168
|
-
def exists(f: Callable[..., bool], name: Optional[str] = None) -> Constraint:
|
|
169
|
-
return
|
|
187
|
+
def exists(f: Callable[..., bool], name: Optional[str] = None, bimap:bool = True) -> Constraint:
|
|
188
|
+
return predicate(f, name=name, quant=Quantifier.EXISTS, bimap=bimap)
|
|
189
|
+
|
|
170
190
|
|
|
171
191
|
|
syncraft/generator.py
CHANGED
|
@@ -16,14 +16,14 @@ from syncraft.ast import (
|
|
|
16
16
|
Choice, Many, ChoiceKind,
|
|
17
17
|
Then, ThenKind, Marked
|
|
18
18
|
)
|
|
19
|
-
|
|
19
|
+
from syncraft.constraint import FrozenDict
|
|
20
20
|
from syncraft.syntax import Syntax
|
|
21
21
|
from sqlglot import TokenType
|
|
22
22
|
import re
|
|
23
23
|
import rstr
|
|
24
24
|
from functools import lru_cache
|
|
25
25
|
import random
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
from syncraft.constraint import Bindable
|
|
28
28
|
|
|
29
29
|
T = TypeVar('T', bound=TokenProtocol)
|
|
@@ -144,6 +144,10 @@ class TokenGen(TokenSpec):
|
|
|
144
144
|
|
|
145
145
|
@dataclass(frozen=True)
|
|
146
146
|
class Generator(Algebra[ParseResult[T], GenState[T]]):
|
|
147
|
+
@classmethod
|
|
148
|
+
def state(cls, ast: Optional[ParseResult[T]] = None, seed: int = 0, restore_pruned: bool = False)->GenState[T]:
|
|
149
|
+
return GenState.from_ast(ast=ast, seed=seed, restore_pruned=restore_pruned)
|
|
150
|
+
|
|
147
151
|
def flat_map(self, f: Callable[[ParseResult[T]], Algebra[B, GenState[T]]]) -> Algebra[B, GenState[T]]:
|
|
148
152
|
def flat_map_run(input: GenState[T], use_cache:bool) -> Either[Any, Tuple[B, GenState[T]]]:
|
|
149
153
|
try:
|
|
@@ -293,14 +297,9 @@ class Generator(Algebra[ParseResult[T], GenState[T]]):
|
|
|
293
297
|
def generate(syntax: Syntax[Any, Any],
|
|
294
298
|
data: Optional[ParseResult[Any]] = None,
|
|
295
299
|
seed: int = 0,
|
|
296
|
-
restore_pruned: bool = False) -> AST | Any:
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
result = gen.run(state, use_cache=False)
|
|
300
|
-
if isinstance(result, Right):
|
|
301
|
-
return result.value[0]
|
|
302
|
-
assert isinstance(result, Left), "Generator must return Either[Any, Tuple[Any, Any]]"
|
|
303
|
-
return result.value
|
|
300
|
+
restore_pruned: bool = False) -> Tuple[AST, FrozenDict[str, Tuple[AST, ...]]] | Tuple[Any, None]:
|
|
301
|
+
from syncraft.syntax import run
|
|
302
|
+
return run(syntax, Generator, False, ast=data, seed=seed, restore_pruned=restore_pruned)
|
|
304
303
|
|
|
305
304
|
|
|
306
305
|
|
syncraft/parser.py
CHANGED
|
@@ -5,6 +5,7 @@ from typing import (
|
|
|
5
5
|
Optional, List, Any, Tuple, TypeVar,
|
|
6
6
|
Generic
|
|
7
7
|
)
|
|
8
|
+
from syncraft.constraint import FrozenDict
|
|
8
9
|
from syncraft.algebra import (
|
|
9
10
|
Either, Left, Right, Error, Algebra
|
|
10
11
|
)
|
|
@@ -67,6 +68,11 @@ class ParserState(Bindable, Generic[T]):
|
|
|
67
68
|
|
|
68
69
|
@dataclass(frozen=True)
|
|
69
70
|
class Parser(Algebra[T, ParserState[T]]):
|
|
71
|
+
@classmethod
|
|
72
|
+
def state(cls, sql: str, dialect: str) -> ParserState[T]:
|
|
73
|
+
tokens = tuple([Token(token_type=token.token_type, text=token.text) for token in tokenize(sql, dialect=dialect)])
|
|
74
|
+
return ParserState.from_tokens(tokens) # type: ignore
|
|
75
|
+
|
|
70
76
|
@classmethod
|
|
71
77
|
def token(cls,
|
|
72
78
|
token_type: Optional[Enum] = None,
|
|
@@ -182,21 +188,12 @@ def sqlglot(parser: Syntax[Any, Any],
|
|
|
182
188
|
return parser.map(lambda tokens: [e for e in gp.parse(raw_tokens=tokens) if e is not None])
|
|
183
189
|
|
|
184
190
|
|
|
185
|
-
def parse(syntax: Syntax[Any, Any],
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
input: ParserState[Token] = token_state(sql, dialect=dialect)
|
|
190
|
-
result = parser.run(input, True)
|
|
191
|
-
if isinstance(result, Right):
|
|
192
|
-
return result.value[0]
|
|
193
|
-
assert isinstance(result, Left), "Parser must return Either[E, Tuple[A, S]]"
|
|
194
|
-
return result.value
|
|
191
|
+
def parse(syntax: Syntax[Any, Any], sql: str, dialect: str) -> Tuple[AST, FrozenDict[str, Tuple[AST, ...]]] | Tuple[Any, None]:
|
|
192
|
+
from syncraft.syntax import run
|
|
193
|
+
return run(syntax, Parser, True, sql=sql, dialect=dialect)
|
|
194
|
+
|
|
195
195
|
|
|
196
196
|
|
|
197
|
-
def token_state(sql: str, dialect: str) -> ParserState[Token]:
|
|
198
|
-
tokens = tuple([Token(token_type=token.token_type, text=token.text) for token in tokenize(sql, dialect=dialect)])
|
|
199
|
-
return ParserState.from_tokens(tokens)
|
|
200
197
|
|
|
201
198
|
def token(token_type: Optional[Enum] = None,
|
|
202
199
|
text: Optional[str] = None,
|
syncraft/syntax.py
CHANGED
|
@@ -2,17 +2,17 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import (
|
|
4
4
|
Optional, Any, TypeVar, Generic, Callable, Tuple, cast,
|
|
5
|
-
Type, Literal, List
|
|
5
|
+
Type, Literal, List
|
|
6
6
|
)
|
|
7
7
|
from dataclasses import dataclass, field, replace
|
|
8
8
|
from functools import reduce
|
|
9
|
-
from syncraft.algebra import Algebra, Error, Either, Right
|
|
10
|
-
from syncraft.constraint import Bindable
|
|
9
|
+
from syncraft.algebra import Algebra, Error, Either, Right, Left
|
|
10
|
+
from syncraft.constraint import Bindable, FrozenDict
|
|
11
11
|
from syncraft.ast import Then, ThenKind, Marked, Choice, Many, ChoiceKind, Nothing, Collect, E, Collector
|
|
12
12
|
from types import MethodType, FunctionType
|
|
13
13
|
import keyword
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
|
|
17
17
|
def valid_name(name: str) -> bool:
|
|
18
18
|
return (name.isidentifier()
|
|
@@ -319,49 +319,15 @@ def success(value: Any) -> Syntax[Any, Any]:
|
|
|
319
319
|
def choice(*parsers: Syntax[Any, S]) -> Syntax[Any, S]:
|
|
320
320
|
return reduce(lambda a, b: a | b, parsers) if len(parsers) > 0 else success(Nothing())
|
|
321
321
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
def is_named_parser(x: Any) -> bool:
|
|
334
|
-
return isinstance(x, tuple) and len(x) == 2 and isinstance(x[0], str) and isinstance(x[1], Syntax)
|
|
335
|
-
|
|
336
|
-
def to_parser(x: Syntax[Any, S] | Tuple[str, Syntax[Any, S]])->Syntax[Any, S]:
|
|
337
|
-
if isinstance(x, tuple) and len(x) == 2 and isinstance(x[0], str) and isinstance(x[1], Syntax):
|
|
338
|
-
if isinstance(x[0], str):
|
|
339
|
-
|
|
340
|
-
return x[1].bind(x[0])
|
|
341
|
-
else:
|
|
342
|
-
raise ValueError(f"Invalid variable type(must be str | Variable): {x[0]}", x)
|
|
343
|
-
elif isinstance(x, Syntax):
|
|
344
|
-
return x
|
|
345
|
-
else:
|
|
346
|
-
raise ValueError(f"Invalid parser or tuple: {x}", x)
|
|
347
|
-
ret: Optional[Syntax[Any, S]] = None
|
|
348
|
-
has_data = False
|
|
349
|
-
for p in parsers:
|
|
350
|
-
just_parser = to_parser(p)
|
|
351
|
-
if has_data:
|
|
352
|
-
if ret is not None:
|
|
353
|
-
if is_named_parser(p):
|
|
354
|
-
ret = ret + just_parser
|
|
355
|
-
else:
|
|
356
|
-
ret = ret // just_parser
|
|
357
|
-
else:
|
|
358
|
-
ret = just_parser
|
|
359
|
-
else:
|
|
360
|
-
has_data = is_named_parser(p)
|
|
361
|
-
if ret is None:
|
|
362
|
-
ret = just_parser
|
|
363
|
-
else:
|
|
364
|
-
ret = ret >> just_parser
|
|
365
|
-
|
|
366
|
-
return ret if ret is not None else success(Nothing())
|
|
322
|
+
def run(syntax: Syntax[A, S], alg: Type[Algebra[A, S]], use_cache:bool, *args: Any, **kwargs: Any) -> Tuple[Any, FrozenDict[str, Tuple[Any, ...]]] | Tuple[Any, None]:
|
|
323
|
+
parser = syntax(alg)
|
|
324
|
+
input: Optional[S] = alg.state(*args, **kwargs)
|
|
325
|
+
if input:
|
|
326
|
+
result = parser.run(input, use_cache=use_cache)
|
|
327
|
+
if isinstance(result, Right):
|
|
328
|
+
return result.value[0], result.value[1].binding.bound()
|
|
329
|
+
assert isinstance(result, Left), "Algebra must return Either[E, Tuple[A, S]]"
|
|
330
|
+
return result.value, None
|
|
331
|
+
else:
|
|
332
|
+
return Error(this=None, message="Algebra failed to create initial state"), None
|
|
367
333
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
syncraft/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
syncraft/algebra.py,sha256=2pyxbllcRsaDS_rEXfagBenZ_etSjMNdlVYxPkoU7cQ,15849
|
|
3
|
+
syncraft/ast.py,sha256=TAHj8IOgx_QtlI4zxFr2DRGZ4dwNGsb6TiH0TH9adIg,14556
|
|
4
|
+
syncraft/constraint.py,sha256=4HDWXgq9ZKacKBViBxIWhbRqgZNP7cZHXOSFMyGMaaA,7274
|
|
5
|
+
syncraft/diagnostic.py,sha256=cgwcQnCcgrCRX3h-oGTDb5rcJAtitPV3LfH9eLvO93E,2837
|
|
6
|
+
syncraft/finder.py,sha256=Wr7wiBuO9IaXBmYBA4DNXmoeEWteRIp-UetnuRScapM,1920
|
|
7
|
+
syncraft/generator.py,sha256=sa0Uyq2azFh5kW3RVsPS7aFmtR5sfBYODa5K2Fg_Jy8,13074
|
|
8
|
+
syncraft/parser.py,sha256=azO1P7c2QJK_XPZtrMnK6CyTHRdlQaT9rAqfyZNtUK0,11293
|
|
9
|
+
syncraft/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
syncraft/sqlite3.py,sha256=Pq09IHZOwuWg5W82l9D1flzd36QV0TOHQpTJ5U02V8g,34701
|
|
11
|
+
syncraft/syntax.py,sha256=kKECtd-yIIho6DjG0fHYNpqNkJ9_zo01S7bOWUUT0VA,16294
|
|
12
|
+
syncraft-0.2.2.dist-info/licenses/LICENSE,sha256=wHSV424U5csa3339dy1AZbsz2xsd0hrkMx2QK48CcUk,1062
|
|
13
|
+
syncraft-0.2.2.dist-info/METADATA,sha256=VlHmCHpIuBIfamHJ6jPr6PbGCShaR0mcTE6foAtk8nI,988
|
|
14
|
+
syncraft-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
+
syncraft-0.2.2.dist-info/top_level.txt,sha256=Kq3t8ESXB2xW1Xt3uPmkENFc-c4f2pamNmaURBk7zc8,9
|
|
16
|
+
syncraft-0.2.2.dist-info/RECORD,,
|
syncraft-0.2.0.dist-info/RECORD
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
syncraft/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
syncraft/algebra.py,sha256=U28UIKK4oh2yIuvOqKYeo4_lDkX3Sy_nHSaHnIabcbk,15769
|
|
3
|
-
syncraft/ast.py,sha256=TAHj8IOgx_QtlI4zxFr2DRGZ4dwNGsb6TiH0TH9adIg,14556
|
|
4
|
-
syncraft/constraint.py,sha256=9VvnZtL3Q63qnU-j3cgTQm8cMrIXdgSgl4qIEF-YCx4,6509
|
|
5
|
-
syncraft/diagnostic.py,sha256=cgwcQnCcgrCRX3h-oGTDb5rcJAtitPV3LfH9eLvO93E,2837
|
|
6
|
-
syncraft/finder.py,sha256=Wr7wiBuO9IaXBmYBA4DNXmoeEWteRIp-UetnuRScapM,1920
|
|
7
|
-
syncraft/generator.py,sha256=C0vpJotp982anrSXq1-EdjQU_OMI_vDCa7uTdJK8M5M,12987
|
|
8
|
-
syncraft/parser.py,sha256=RkQwFv00rOI-n4kvG4baGVTdK46T-_Hw7OJ0FB7g72g,11379
|
|
9
|
-
syncraft/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
syncraft/sqlite3.py,sha256=Pq09IHZOwuWg5W82l9D1flzd36QV0TOHQpTJ5U02V8g,34701
|
|
11
|
-
syncraft/syntax.py,sha256=yuU1_c160RWhxGLZUo2jjgba99CU84VaWCP8Cy86I_I,17487
|
|
12
|
-
syncraft-0.2.0.dist-info/licenses/LICENSE,sha256=wHSV424U5csa3339dy1AZbsz2xsd0hrkMx2QK48CcUk,1062
|
|
13
|
-
syncraft-0.2.0.dist-info/METADATA,sha256=vzYdcSzl69EHcv8-3s3Od-OdlA1EDI8yqlU8l6zESmo,988
|
|
14
|
-
syncraft-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
-
syncraft-0.2.0.dist-info/top_level.txt,sha256=Kq3t8ESXB2xW1Xt3uPmkENFc-c4f2pamNmaURBk7zc8,9
|
|
16
|
-
syncraft-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|