syncraft 0.2.1__tar.gz → 0.2.2__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.

Files changed (27) hide show
  1. {syncraft-0.2.1 → syncraft-0.2.2}/PKG-INFO +1 -1
  2. {syncraft-0.2.1 → syncraft-0.2.2}/pyproject.toml +1 -1
  3. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/constraint.py +28 -8
  4. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/generator.py +1 -1
  5. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/parser.py +3 -3
  6. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/syntax.py +1 -1
  7. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft.egg-info/PKG-INFO +1 -1
  8. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft.egg-info/SOURCES.txt +1 -0
  9. syncraft-0.2.2/tests/test_constraint.py +53 -0
  10. {syncraft-0.2.1 → syncraft-0.2.2}/LICENSE +0 -0
  11. {syncraft-0.2.1 → syncraft-0.2.2}/README.md +0 -0
  12. {syncraft-0.2.1 → syncraft-0.2.2}/setup.cfg +0 -0
  13. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/__init__.py +0 -0
  14. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/algebra.py +0 -0
  15. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/ast.py +0 -0
  16. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/diagnostic.py +0 -0
  17. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/finder.py +0 -0
  18. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/py.typed +0 -0
  19. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft/sqlite3.py +0 -0
  20. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft.egg-info/dependency_links.txt +0 -0
  21. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft.egg-info/requires.txt +0 -0
  22. {syncraft-0.2.1 → syncraft-0.2.2}/syncraft.egg-info/top_level.txt +0 -0
  23. {syncraft-0.2.1 → syncraft-0.2.2}/tests/test_bimap.py +0 -0
  24. {syncraft-0.2.1 → syncraft-0.2.2}/tests/test_find.py +0 -0
  25. {syncraft-0.2.1 → syncraft-0.2.2}/tests/test_parse.py +0 -0
  26. {syncraft-0.2.1 → syncraft-0.2.2}/tests/test_to.py +0 -0
  27. {syncraft-0.2.1 → syncraft-0.2.2}/tests/test_until.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syncraft
3
- Version: 0.2.1
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "syncraft"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "Parser combinator library"
5
5
  license = "MIT"
6
6
  license-files = ["LICENSE"]
@@ -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
 
@@ -297,7 +297,7 @@ class Generator(Algebra[ParseResult[T], GenState[T]]):
297
297
  def generate(syntax: Syntax[Any, Any],
298
298
  data: Optional[ParseResult[Any]] = None,
299
299
  seed: int = 0,
300
- restore_pruned: bool = False) -> Tuple[AST, FrozenDict[str, AST]] | Tuple[Any, None]:
300
+ restore_pruned: bool = False) -> Tuple[AST, FrozenDict[str, Tuple[AST, ...]]] | Tuple[Any, None]:
301
301
  from syncraft.syntax import run
302
302
  return run(syntax, Generator, False, ast=data, seed=seed, restore_pruned=restore_pruned)
303
303
 
@@ -69,9 +69,9 @@ class ParserState(Bindable, Generic[T]):
69
69
  @dataclass(frozen=True)
70
70
  class Parser(Algebra[T, ParserState[T]]):
71
71
  @classmethod
72
- def state(cls, sql: str, dialect: str) -> ParserState[Token]:
72
+ def state(cls, sql: str, dialect: str) -> ParserState[T]:
73
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)
74
+ return ParserState.from_tokens(tokens) # type: ignore
75
75
 
76
76
  @classmethod
77
77
  def token(cls,
@@ -188,7 +188,7 @@ def sqlglot(parser: Syntax[Any, Any],
188
188
  return parser.map(lambda tokens: [e for e in gp.parse(raw_tokens=tokens) if e is not None])
189
189
 
190
190
 
191
- def parse(syntax: Syntax[Any, Any], sql: str, dialect: str) -> Tuple[AST, FrozenDict[str, AST]] | Tuple[Any, None]:
191
+ def parse(syntax: Syntax[Any, Any], sql: str, dialect: str) -> Tuple[AST, FrozenDict[str, Tuple[AST, ...]]] | Tuple[Any, None]:
192
192
  from syncraft.syntax import run
193
193
  return run(syntax, Parser, True, sql=sql, dialect=dialect)
194
194
 
@@ -319,7 +319,7 @@ 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
- def run(syntax: Syntax[A, S], alg: Type[Algebra[A, S]], use_cache:bool, *args: Any, **kwargs: Any) -> Tuple[Any, FrozenDict[str, Any]] | Tuple[Any, None]:
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
323
  parser = syntax(alg)
324
324
  input: Optional[S] = alg.state(*args, **kwargs)
325
325
  if input:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syncraft
3
- Version: 0.2.1
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
@@ -18,6 +18,7 @@ syncraft.egg-info/dependency_links.txt
18
18
  syncraft.egg-info/requires.txt
19
19
  syncraft.egg-info/top_level.txt
20
20
  tests/test_bimap.py
21
+ tests/test_constraint.py
21
22
  tests/test_find.py
22
23
  tests/test_parse.py
23
24
  tests/test_to.py
@@ -0,0 +1,53 @@
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 syncraft.constraint import forall, exists
8
+ from rich import print
9
+ import syncraft.generator as gen
10
+ from dataclasses import dataclass
11
+
12
+
13
+ def test_to() -> None:
14
+ @dataclass
15
+ class IfThenElse:
16
+ condition: Any
17
+ then: Any
18
+ otherwise: Any
19
+
20
+ @dataclass
21
+ class While:
22
+ condition:Any
23
+ body:Any
24
+
25
+ WHILE = literal("while")
26
+ IF = literal("if")
27
+ ELSE = literal("else")
28
+ THEN = literal("then")
29
+ END = literal("end")
30
+ A = literal('a')
31
+ B = literal('b')
32
+ C = literal('c')
33
+ D = literal('d')
34
+ M = literal(',')
35
+ var = A | B | C | D
36
+ condition = var.sep_by(M).mark('condition').bind()
37
+ ifthenelse = (IF >> condition
38
+ // THEN
39
+ + var.sep_by(M).mark('then').bind()
40
+ // ELSE
41
+ + var.sep_by(M).mark('otherwise').bind()
42
+ // END).to(IfThenElse).many()
43
+ syntax = (WHILE >> condition
44
+ + ifthenelse.mark('body').bind()
45
+ // ~END).to(While)
46
+ sql = 'while b if a,b then c,d else a,d end if a,b then c,d else a,d end'
47
+ ast, bound = parse(syntax, sql, dialect='sqlite')
48
+ def p(condition, then, otherwise)->bool:
49
+ print({'condition':condition, 'then':then, 'otherwise':otherwise})
50
+ return True
51
+ if bound is not None:
52
+ forall(p)(bound)
53
+ g, bound = gen.generate(syntax, ast, restore_pruned=True)
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