syncraft 0.1.30__py3-none-any.whl → 0.1.32__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
@@ -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
syncraft/ast.py CHANGED
@@ -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')
@@ -182,6 +188,11 @@ class AST:
182
188
 
183
189
  @dataclass(frozen=True)
184
190
  class Nothing(AST):
191
+ _instance = None
192
+ def __new__(cls):
193
+ if cls._instance is None:
194
+ cls._instance = super(Nothing, cls).__new__(cls)
195
+ return cls._instance
185
196
  def __str__(self)->str:
186
197
  return self.__class__.__name__
187
198
  def __repr__(self)->str:
@@ -220,8 +231,8 @@ class Many(Generic[A], AST):
220
231
  if len(bs) <= len(ret):
221
232
  return Many(value = tuple(ret[i][1](bs[i]) for i in range(len(bs))))
222
233
  else:
223
- half = [ret[i][1](bs[i]) for i in range(len(bs))]
224
- tmp = [ret[-1][1](bs[i]) for i in range(len(ret)-1, len(bs))]
234
+ half = [ret[i][1](bs[i]) for i in range(len(ret))]
235
+ tmp = [ret[-1][1](bs[i]) for i in range(len(ret), len(bs))]
225
236
  return Many(value = tuple(half + tmp))
226
237
  return [v[0] for v in ret], inv
227
238
 
@@ -287,37 +298,42 @@ class Collect(Generic[A, E], AST):
287
298
  collector: Collector
288
299
  value: A
289
300
  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]))
301
+
302
+ def inv_one_positional(e: E) -> B:
303
+ assert is_dataclass(e), f"Expected dataclass instance for collector inverse, got {type(e)}"
304
+ named_dict = shallow_dict(e)
305
+ return named_dict[fields(e)[0].name]
306
+
307
+ b, inner_f = self.value.bimap(r) if isinstance(self.value, AST) else r(self.value)
308
+ if isinstance(self.value, Then):
309
+ if isinstance(b, tuple):
310
+ index: List[str | int] = []
311
+ named_count = 0
312
+ for i, v in enumerate(b):
313
+ if isinstance(v, Marked):
314
+ index.append(v.name)
315
+ named_count += 1
315
316
  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
317
+ index.append(i - named_count)
318
+ named = {v.name: v.value for v in b if isinstance(v, Marked)}
319
+ unnamed = [v for v in b if not isinstance(v, Marked)]
320
+ ret: E = self.collector(*unnamed, **named)
321
+ def invf(e: E) -> Tuple[Any, ...]:
322
+ assert is_dataclass(e), f"Expected dataclass instance for collector inverse, got {type(e)}"
323
+ named_dict = shallow_dict(e)
324
+ unnamed = []
325
+ for f in fields(e):
326
+ if f.name not in named:
327
+ unnamed.append(named_dict[f.name])
328
+ tmp = []
329
+ for x in index:
330
+ if isinstance(x, str):
331
+ tmp.append(Marked(name=x, value=named_dict[x]))
332
+ else:
333
+ tmp.append(unnamed[x])
334
+ return tuple(tmp)
335
+ return ret, lambda e: replace(self, value=inner_f(invf(e))) # type: ignore
336
+ return self.collector(b), lambda e: replace(self, value=inner_f(inv_one_positional(e))) # type: ignore
321
337
 
322
338
  #########################################################################################################################
323
339
  @dataclass(frozen=True)
syncraft/syntax.py CHANGED
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import (
4
4
  Optional, Any, TypeVar, Generic, Callable, Tuple, cast,
5
- Type, Literal
5
+ Type, Literal, List
6
6
  )
7
7
  from dataclasses import dataclass, field, replace
8
8
  from functools import reduce
@@ -165,8 +165,29 @@ 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())
171
+ def f(a: Then[A, Choice[Many[Then[B, A]], Optional[Nothing]]]) -> Many[A]:
172
+ match a:
173
+ case Then(kind=ThenKind.BOTH, left=left, right=Choice(kind=ChoiceKind.RIGHT, value=Nothing())):
174
+ return Many(value = (left,))
175
+ case Then(kind=ThenKind.BOTH, left=left, right=Choice(kind=ChoiceKind.LEFT, value=Many(value=bs))):
176
+ return Many(value = (left,) + tuple([b.right for b in bs]))
177
+ case _:
178
+ raise ValueError(f"Bad data shape {a}")
179
+
180
+ def i(a: Many[A]) -> Then[A, Choice[Many[Then[B|None, A]], Optional[Nothing]]]:
181
+ assert len(a.value) >= 1, f"sep_by expect at least one element, got {len(a.value)}. {a}"
182
+ if len(a.value) == 1:
183
+ return Then(kind=ThenKind.BOTH, left=a.value[0], right=Choice(kind=ChoiceKind.RIGHT, value=Nothing()))
184
+ else:
185
+ v: List[Then[B|None, A]] = [Then(kind=ThenKind.RIGHT, right=x, left=None) for x in a.value[1:]]
186
+ return Then(kind= ThenKind.BOTH,
187
+ left=a.value[0],
188
+ right=Choice(kind=ChoiceKind.LEFT,
189
+ value=Many(value=tuple(v))))
190
+ ret = ret.bimap(f,i) # type: ignore
170
191
  return ret.describe(
171
192
  name='sep_by',
172
193
  fixity='prefix',
@@ -191,17 +212,11 @@ class Syntax(Generic[A, S]):
191
212
  other = other if isinstance(other, Syntax) else self.lift(other).as_(Syntax[B, S])
192
213
  ret: Syntax[Then[A, B], S] = self.__class__(lambda cls: self.alg(cls).then_left(other.alg(cls))) # type: ignore
193
214
  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
-
215
+
198
216
  def __rfloordiv__(self, other: Syntax[B, S]) -> Syntax[Then[B, A], S]:
199
217
  other = other if isinstance(other, Syntax) else self.lift(other).as_(Syntax[B, S])
200
218
  return other.__floordiv__(self)
201
219
 
202
- def __rlshift__(self, other: Syntax[B, S]) -> Syntax[Then[B, A], S]:
203
- return self.__rfloordiv__(other)
204
-
205
220
  def __add__(self, other: Syntax[B, S]) -> Syntax[Then[A, B], S]:
206
221
  other = other if isinstance(other, Syntax) else self.lift(other).as_(Syntax[B, S])
207
222
  ret: Syntax[Then[A, B], S] = self.__class__(lambda cls: self.alg(cls).then_both(other.alg(cls))) # type: ignore
@@ -260,16 +275,16 @@ class Syntax(Generic[A, S]):
260
275
  return self.bimap(to_f, ito_f).describe(name=f'to({f})', fixity='postfix', parameter=(self,))
261
276
 
262
277
 
263
- def mark(self, var: str) -> Syntax[Marked[A], S]:
278
+ def mark(self, name: str) -> Syntax[Marked[A], S]:
264
279
  def bind_s(value: A) -> Marked[A]:
265
280
  if isinstance(value, Marked):
266
- return replace(value, name=var)
281
+ return replace(value, name=name)
267
282
  else:
268
- return Marked(name=var, value=value)
283
+ return Marked(name=name, value=value)
269
284
  def ibind_s(m : Marked[A]) -> A:
270
285
  return m.value if isinstance(m, Marked) else m
271
286
 
272
- return self.bimap(bind_s, ibind_s).describe(name=f'bind("{var}")', fixity='postfix', parameter=(self,))
287
+ return self.bimap(bind_s, ibind_s).describe(name=f'bind("{name}")', fixity='postfix', parameter=(self,))
273
288
 
274
289
 
275
290
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: syncraft
3
- Version: 0.1.30
3
+ Version: 0.1.32
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
  syncraft/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- syncraft/algebra.py,sha256=gXs4rD6Inp6kGf5Vd5kHGgmb2K_qFlWFQ09i7tmcCmo,15662
3
- syncraft/ast.py,sha256=MSzEvpXoEPxbLX_tYwKbvNEpPzyGc22-poGtHsc1S30,13747
2
+ syncraft/algebra.py,sha256=0bf_kT4b5FeF6isxNESZPbv_nzhDAbbMEID7S0RMJmQ,15677
3
+ syncraft/ast.py,sha256=4EzHOa72UzI3nehFkYZmgz3ex7l7zwiyhy75bchppNI,14454
4
4
  syncraft/constraint.py,sha256=uT-ELzvv8J-s-Y1VYkXePUezseqCLhqzYUzFBYs0HsE,6418
5
5
  syncraft/diagnostic.py,sha256=cgwcQnCcgrCRX3h-oGTDb5rcJAtitPV3LfH9eLvO93E,2837
6
6
  syncraft/finder.py,sha256=L75A0bAjdlntWk-Y1rCeINBOzGeGdE_zHrTmcpQ7m9g,1875
@@ -8,9 +8,9 @@ syncraft/generator.py,sha256=C3N0Nxk9grN6iPxLHt1Ur2xzS5S-9LsNvMMc-ehd36E,12981
8
8
  syncraft/parser.py,sha256=RkQwFv00rOI-n4kvG4baGVTdK46T-_Hw7OJ0FB7g72g,11379
9
9
  syncraft/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  syncraft/sqlite3.py,sha256=Pq09IHZOwuWg5W82l9D1flzd36QV0TOHQpTJ5U02V8g,34701
11
- syncraft/syntax.py,sha256=a3g-qcTHpIicMO0KseHuKe5liNfYawLRO-M1eCBS6d4,16574
12
- syncraft-0.1.30.dist-info/licenses/LICENSE,sha256=wHSV424U5csa3339dy1AZbsz2xsd0hrkMx2QK48CcUk,1062
13
- syncraft-0.1.30.dist-info/METADATA,sha256=hS0hq05nMjQnQTPDCeFxrvlkybCLjdsowLHLayIgHJE,1041
14
- syncraft-0.1.30.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- syncraft-0.1.30.dist-info/top_level.txt,sha256=Kq3t8ESXB2xW1Xt3uPmkENFc-c4f2pamNmaURBk7zc8,9
16
- syncraft-0.1.30.dist-info/RECORD,,
11
+ syncraft/syntax.py,sha256=ZqprL1EB8NFusM0Pcz9_uufLL4RTyzUAvMLkG14dOvU,17704
12
+ syncraft-0.1.32.dist-info/licenses/LICENSE,sha256=wHSV424U5csa3339dy1AZbsz2xsd0hrkMx2QK48CcUk,1062
13
+ syncraft-0.1.32.dist-info/METADATA,sha256=6jkJsi6ayD-miCVzm2Xm2hK385HkbfZeaAOUBTwhyp4,1041
14
+ syncraft-0.1.32.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ syncraft-0.1.32.dist-info/top_level.txt,sha256=Kq3t8ESXB2xW1Xt3uPmkENFc-c4f2pamNmaURBk7zc8,9
16
+ syncraft-0.1.32.dist-info/RECORD,,