syncraft 0.1.30__tar.gz → 0.1.31__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 (24) hide show
  1. {syncraft-0.1.30 → syncraft-0.1.31}/PKG-INFO +1 -1
  2. {syncraft-0.1.30 → syncraft-0.1.31}/pyproject.toml +1 -1
  3. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/algebra.py +6 -3
  4. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/ast.py +43 -32
  5. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/syntax.py +22 -13
  6. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/PKG-INFO +1 -1
  7. {syncraft-0.1.30 → syncraft-0.1.31}/LICENSE +0 -0
  8. {syncraft-0.1.30 → syncraft-0.1.31}/README.md +0 -0
  9. {syncraft-0.1.30 → syncraft-0.1.31}/setup.cfg +0 -0
  10. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/__init__.py +0 -0
  11. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/constraint.py +0 -0
  12. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/diagnostic.py +0 -0
  13. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/finder.py +0 -0
  14. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/generator.py +0 -0
  15. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/parser.py +0 -0
  16. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/py.typed +0 -0
  17. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft/sqlite3.py +0 -0
  18. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/SOURCES.txt +0 -0
  19. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/dependency_links.txt +0 -0
  20. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/requires.txt +0 -0
  21. {syncraft-0.1.30 → syncraft-0.1.31}/syncraft.egg-info/top_level.txt +0 -0
  22. {syncraft-0.1.30 → syncraft-0.1.31}/tests/test_bimap.py +0 -0
  23. {syncraft-0.1.30 → syncraft-0.1.31}/tests/test_parse.py +0 -0
  24. {syncraft-0.1.30 → syncraft-0.1.31}/tests/test_until.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syncraft
3
- Version: 0.1.30
3
+ Version: 0.1.31
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.1.30"
3
+ version = "0.1.31"
4
4
  description = "Parser combinator library"
5
5
  license = "MIT"
6
6
  license-files = ["LICENSE"]
@@ -5,12 +5,15 @@ from typing import (
5
5
  )
6
6
 
7
7
  import traceback
8
- from dataclasses import dataclass, replace, asdict
8
+ from dataclasses import dataclass, replace
9
9
  from weakref import WeakKeyDictionary
10
10
  from abc import ABC
11
- from syncraft.ast import ThenKind, Then, Choice, Many, ChoiceKind
11
+ from syncraft.ast import ThenKind, Then, Choice, Many, ChoiceKind, shallow_dict
12
12
  from syncraft.constraint import Bindable
13
13
 
14
+
15
+
16
+
14
17
  S = TypeVar('S', bound=Bindable)
15
18
 
16
19
  A = TypeVar('A') # Result type
@@ -64,7 +67,7 @@ class Error:
64
67
  lst = []
65
68
  current: Optional[Error] = self
66
69
  while current is not None:
67
- d = asdict(current)
70
+ d = shallow_dict(current)
68
71
  lst.append({k:v for k,v in d.items() if v is not None and k != 'previous'})
69
72
  current = current.previous
70
73
  return lst
@@ -4,14 +4,20 @@ from __future__ import annotations
4
4
  import re
5
5
  from typing import (
6
6
  Optional, Any, TypeVar, Tuple, runtime_checkable, cast,
7
- Generic, Callable, Union, Protocol, Type, List, ClassVar
7
+ Generic, Callable, Union, Protocol, Type, List, ClassVar,
8
+ Dict
8
9
  )
9
10
 
10
11
 
11
- from dataclasses import dataclass, replace, is_dataclass, asdict, fields
12
+ from dataclasses import dataclass, replace, is_dataclass, fields
12
13
  from enum import Enum
13
14
 
14
15
 
16
+ def shallow_dict(a: Any)->Dict[str, Any]:
17
+ assert is_dataclass(a), f"Expected dataclass instance for collector inverse, got {type(a)}"
18
+ return {f.name: getattr(a, f.name) for f in fields(a)}
19
+
20
+
15
21
 
16
22
 
17
23
  A = TypeVar('A')
@@ -287,37 +293,42 @@ class Collect(Generic[A, E], AST):
287
293
  collector: Collector
288
294
  value: A
289
295
  def bimap(self, r: Bimap[A, B]=Bimap.identity()) -> Tuple[B | E, Callable[[B | E], Collect[A, E]]]:
290
- b, inner_f = r(self.value)
291
- if isinstance(self.value, Then) and self.value.kind == ThenKind.BOTH:
292
- assert isinstance(b, tuple), f"Expected tuple from Then.BOTH combinator, got {type(b)}"
293
- index: List[str | int] = []
294
- named_count = 0
295
- for i, v in enumerate(b):
296
- if isinstance(v, Marked):
297
- index.append(v.name)
298
- named_count += 1
299
- else:
300
- index.append(i - named_count)
301
- named = {v.name: v.value for v in b if isinstance(v, Marked)}
302
- unnamed = [v for v in b if not isinstance(v, Marked)]
303
- ret: E = self.collector(*unnamed, **named)
304
- def invf(e: E) -> Tuple[Any, ...]:
305
- assert is_dataclass(e), f"Expected dataclass instance for collector inverse, got {type(e)}"
306
- named_dict = asdict(e)
307
- unnamed = []
308
- for f in fields(e):
309
- if f.name not in named:
310
- unnamed.append(named_dict[f.name])
311
- tmp = []
312
- for x in index:
313
- if isinstance(x, str):
314
- tmp.append(Marked(name=x, value=named_dict[x]))
296
+
297
+ def inv_one_positional(e: E) -> B:
298
+ assert is_dataclass(e), f"Expected dataclass instance for collector inverse, got {type(e)}"
299
+ named_dict = shallow_dict(e)
300
+ return named_dict[fields(e)[0].name]
301
+
302
+ b, inner_f = self.value.bimap(r) if isinstance(self.value, AST) else r(self.value)
303
+ if isinstance(self.value, Then):
304
+ if isinstance(b, tuple):
305
+ index: List[str | int] = []
306
+ named_count = 0
307
+ for i, v in enumerate(b):
308
+ if isinstance(v, Marked):
309
+ index.append(v.name)
310
+ named_count += 1
315
311
  else:
316
- tmp.append(unnamed[x])
317
- return tuple(tmp)
318
- return ret, lambda e: replace(self, value=inner_f(invf(e))) # type: ignore
319
- else:
320
- return b, lambda e: replace(self, value=inner_f(e)) # type: ignore
312
+ index.append(i - named_count)
313
+ named = {v.name: v.value for v in b if isinstance(v, Marked)}
314
+ unnamed = [v for v in b if not isinstance(v, Marked)]
315
+ ret: E = self.collector(*unnamed, **named)
316
+ def invf(e: E) -> Tuple[Any, ...]:
317
+ assert is_dataclass(e), f"Expected dataclass instance for collector inverse, got {type(e)}"
318
+ named_dict = shallow_dict(e)
319
+ unnamed = []
320
+ for f in fields(e):
321
+ if f.name not in named:
322
+ unnamed.append(named_dict[f.name])
323
+ tmp = []
324
+ for x in index:
325
+ if isinstance(x, str):
326
+ tmp.append(Marked(name=x, value=named_dict[x]))
327
+ else:
328
+ tmp.append(unnamed[x])
329
+ return tuple(tmp)
330
+ return ret, lambda e: replace(self, value=inner_f(invf(e))) # type: ignore
331
+ return self.collector(b), lambda e: replace(self, value=inner_f(inv_one_positional(e))) # type: ignore
321
332
 
322
333
  #########################################################################################################################
323
334
  @dataclass(frozen=True)
@@ -165,9 +165,24 @@ class Syntax(Generic[A, S]):
165
165
  def between(self, left: Syntax[B, S], right: Syntax[C, S]) -> Syntax[Then[B, Then[A, C]], S]:
166
166
  return left >> self // right
167
167
 
168
- def sep_by(self, sep: Syntax[B, S]) -> Syntax[Then[A, Choice[Many[Then[B, A]], Optional[Nothing]]], S]:
168
+ def sep_by(self,
169
+ sep: Syntax[B, S]) -> Syntax[Then[A, Choice[Many[Then[B, A]], Optional[Nothing]]], S]:
169
170
  ret: Syntax[Then[A, Choice[Many[Then[B, A]], Optional[Nothing]]], S] = (self + (sep >> self).many().optional())
170
- return ret.describe(
171
+ def f(a: Then[A, Choice[Many[A], Optional[Nothing]]]) -> Many[A]:
172
+ if a.right.kind == ChoiceKind.LEFT and isinstance(a.right.value, Many):
173
+ if len(a.right.value.value) == 0:
174
+ return Many(value = (a.left,))
175
+ else:
176
+ return Many(value = (a.left,) + a.right.value.value)
177
+ else:
178
+ return Many(value = (a.left,))
179
+ def i(a: Many[A]) -> Then[A, Choice[Many[A], Optional[Nothing]]]:
180
+ assert len(a.value) >= 1, f"sep_by expect at least one element, got {len(a.value)}. {a}"
181
+ if len(a.value) == 1:
182
+ return Then(kind=ThenKind.BOTH, left=a.value[0], right=Choice(kind=ChoiceKind.RIGHT, value=Nothing()))
183
+ else:
184
+ return Then(kind= ThenKind.BOTH, left=a.value[0], right=Choice(kind=ChoiceKind.LEFT, value=Many(value=a.value[1:])))
185
+ return ret.bimap(f,i).describe( # type: ignore
171
186
  name='sep_by',
172
187
  fixity='prefix',
173
188
  parameter=(self, sep))
@@ -191,17 +206,11 @@ class Syntax(Generic[A, S]):
191
206
  other = other if isinstance(other, Syntax) else self.lift(other).as_(Syntax[B, S])
192
207
  ret: Syntax[Then[A, B], S] = self.__class__(lambda cls: self.alg(cls).then_left(other.alg(cls))) # type: ignore
193
208
  return ret.describe(name=ThenKind.LEFT.value, fixity='infix', parameter=(self, other)).as_(Syntax[Then[A, B], S])
194
-
195
- def __lshift__(self, other: Syntax[B, S]) -> Syntax[Then[A, B], S]:
196
- return self.__floordiv__(other)
197
-
209
+
198
210
  def __rfloordiv__(self, other: Syntax[B, S]) -> Syntax[Then[B, A], S]:
199
211
  other = other if isinstance(other, Syntax) else self.lift(other).as_(Syntax[B, S])
200
212
  return other.__floordiv__(self)
201
213
 
202
- def __rlshift__(self, other: Syntax[B, S]) -> Syntax[Then[B, A], S]:
203
- return self.__rfloordiv__(other)
204
-
205
214
  def __add__(self, other: Syntax[B, S]) -> Syntax[Then[A, B], S]:
206
215
  other = other if isinstance(other, Syntax) else self.lift(other).as_(Syntax[B, S])
207
216
  ret: Syntax[Then[A, B], S] = self.__class__(lambda cls: self.alg(cls).then_both(other.alg(cls))) # type: ignore
@@ -260,16 +269,16 @@ class Syntax(Generic[A, S]):
260
269
  return self.bimap(to_f, ito_f).describe(name=f'to({f})', fixity='postfix', parameter=(self,))
261
270
 
262
271
 
263
- def mark(self, var: str) -> Syntax[Marked[A], S]:
272
+ def mark(self, name: str) -> Syntax[Marked[A], S]:
264
273
  def bind_s(value: A) -> Marked[A]:
265
274
  if isinstance(value, Marked):
266
- return replace(value, name=var)
275
+ return replace(value, name=name)
267
276
  else:
268
- return Marked(name=var, value=value)
277
+ return Marked(name=name, value=value)
269
278
  def ibind_s(m : Marked[A]) -> A:
270
279
  return m.value if isinstance(m, Marked) else m
271
280
 
272
- return self.bimap(bind_s, ibind_s).describe(name=f'bind("{var}")', fixity='postfix', parameter=(self,))
281
+ return self.bimap(bind_s, ibind_s).describe(name=f'bind("{name}")', fixity='postfix', parameter=(self,))
273
282
 
274
283
 
275
284
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syncraft
3
- Version: 0.1.30
3
+ Version: 0.1.31
4
4
  Summary: Parser combinator library
5
5
  Author-email: Michael Afmokt <michael@esacca.com>
6
6
  License-Expression: MIT
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