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 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(ABC, Generic[A, S]):
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
- name: Optional[str] = None,
126
- quant: Quantifier = Quantifier.FORALL)->Constraint:
127
- sig = inspect.signature(f)
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 or f.__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 Constraint.predicate(f, name=name, quant=Quantifier.FORALL)
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 Constraint.predicate(f, name=name, quant=Quantifier.EXISTS)
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
- from rich import print
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
- gen = syntax(Generator)
298
- state = GenState.from_ast(ast=data, seed=seed, restore_pruned=restore_pruned)
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
- sql: str,
187
- dialect: str) -> AST | Any:
188
- parser = syntax(Parser)
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, overload
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
- from rich import print
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
- def all(*parsers: Syntax[Any, S]) -> Syntax[Then[Any, Any], S]:
324
- return reduce(lambda a, b: a + b, parsers) if len(parsers) > 0 else success(Nothing())
325
-
326
- def first(*parsers: Syntax[Any, S]) -> Syntax[Any, S]:
327
- return reduce(lambda a, b: a // b, parsers) if len(parsers) > 0 else success(Nothing())
328
-
329
- def last(*parsers: Syntax[Any, S]) -> Syntax[Any, S]:
330
- return reduce(lambda a, b: a >> b, parsers) if len(parsers) > 0 else success(Nothing())
331
-
332
- def bind(* parsers: Syntax[Any, S] | Tuple[str, Syntax[Any, S]]) -> Syntax[Any, S]:
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syncraft
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Parser combinator library
5
5
  Author-email: Michael Afmokt <michael@esacca.com>
6
6
  License-Expression: MIT
@@ -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,,
@@ -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,,