omextra 0.0.0.dev473__py3-none-any.whl → 0.0.0.dev474__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.
@@ -5,7 +5,7 @@ A *manual*, near-direct, 'lite'-compatible translation of go-yaml (see LICENSE f
5
5
 
6
6
  The primary reasons for.. doing this.. are as follows:
7
7
 
8
- - Most importantly for '@omlish-lite' usage - yaml parsing is, whether or not we like it, here to stay for things like
8
+ - Most importantly for '@omlish-lite' usage - yaml parsing is, whether we like it or not, here to stay for things like
9
9
  docker-compose - and reading these files in amalgamated scripts like omdev.ci and omdev.pyproject is a hard
10
10
  requirement for them.
11
11
 
@@ -17,7 +17,7 @@ The primary reasons for.. doing this.. are as follows:
17
17
  pile of regexes, but this codebase itself already uses anchors in its compose.yml, at which point (given the
18
18
  potential failure modes of automated infra machinery) that's extremely not acceptable.
19
19
 
20
- - Additionally, as giant yaml files are so pervasive these days, it's useful to be able to programmatically parse
20
+ - Additionally, as giant yaml files are so pervasive these days, it's useful to be able to programmatically parse and
21
21
  manipulate them with full, perfect preservation of all stylistic choices, whitespace, comments, etc. This is already
22
22
  partially done here by wrapping pyyaml nodes, but it's not complete and very fragile.
23
23
 
@@ -6,6 +6,16 @@ Originally based on library by Charles Yeomans (see LICENSE file):
6
6
  https://github.com/declaresub/abnf/tree/561ced67c0a8afc869ad0de5b39dbe4f6e71b0d8/src/abnf
7
7
 
8
8
  It has however been nearly entirely rewritten.
9
+
10
+ ====
11
+
12
+ TODO:
13
+ - cache lol
14
+ - get greedier
15
+ - match-powered optimizer
16
+ - greedily compile regexes
17
+ - error reporting
18
+ - codegen
9
19
  """
10
20
 
11
21
 
omextra/text/abnf/base.py CHANGED
@@ -1,11 +1,3 @@
1
- """
2
- TODO:
3
- - cache lol
4
- - get greedier
5
- - match-powered optimizer
6
- - greedily compile regexes
7
- - error reporting
8
- """
9
1
  import abc
10
2
  import io
11
3
  import itertools
@@ -201,6 +193,7 @@ class Grammar(lang.Final):
201
193
  root: Rule | str | None = None,
202
194
  *,
203
195
  start: int = 0,
196
+ debug: bool = False,
204
197
  ) -> ta.Iterator[Match]:
205
198
  if root is None:
206
199
  if (root := self._root) is None:
@@ -211,7 +204,13 @@ class Grammar(lang.Final):
211
204
  else:
212
205
  root = check.in_(check.isinstance(root, Rule), self._rules)
213
206
 
214
- ctx = _Context(self, source)
207
+ ctx_cls: type[_Context]
208
+ if debug:
209
+ ctx_cls = _DebugContext
210
+ else:
211
+ ctx_cls = _Context
212
+ ctx = ctx_cls(self, source)
213
+
215
214
  return ctx.iter_parse(root._parser, start) # noqa
216
215
 
217
216
  def parse(
@@ -220,19 +219,25 @@ class Grammar(lang.Final):
220
219
  root: str | None = None,
221
220
  *,
222
221
  start: int = 0,
222
+ debug: bool = False,
223
223
  ) -> Match | None:
224
224
  return longest_match(self.iter_parse(
225
225
  source,
226
226
  root,
227
227
  start=start,
228
+ debug=debug,
228
229
  ))
229
230
 
230
231
 
231
232
  ##
232
233
 
233
234
 
234
- class _Context(lang.Final):
235
- def __init__(self, grammar: Grammar, source: str) -> None:
235
+ class _Context:
236
+ def __init__(
237
+ self,
238
+ grammar: Grammar,
239
+ source: str,
240
+ ) -> None:
236
241
  super().__init__()
237
242
 
238
243
  self._grammar = grammar
@@ -250,6 +255,21 @@ class _Context(lang.Final):
250
255
  return parser._iter_parse(self, start) # noqa
251
256
 
252
257
 
258
+ class _DebugContext(_Context):
259
+ _level: int = 0
260
+
261
+ def iter_parse(self, parser: Parser, start: int) -> ta.Iterator[Match]:
262
+ print(f'{" " * self._level}enter: {parser=} {start=}')
263
+ try:
264
+ self._level += 1
265
+ for m in super().iter_parse(parser, start): # noqa
266
+ # print(f'{" " * (self._level - 1)}match: {parser=} {start=}')
267
+ yield m
268
+ finally:
269
+ self._level -= 1
270
+ print(f'{" " * self._level}exit: {parser=} {start=}')
271
+
272
+
253
273
  ##
254
274
 
255
275
 
@@ -2,5 +2,9 @@ class AbnfError(Exception):
2
2
  pass
3
3
 
4
4
 
5
+ class AbnfIncompleteParseError(AbnfError):
6
+ pass
7
+
8
+
5
9
  class AbnfGrammarParseError(AbnfError):
6
10
  pass
omextra/text/abnf/meta.py CHANGED
@@ -473,6 +473,21 @@ class MetaGrammarRuleVisitor(RuleVisitor[ta.Any]):
473
473
  else:
474
474
  raise ValueError(m)
475
475
 
476
+ @RuleVisitor.register('repeat')
477
+ def visit_repeat_rule(self, m: Match) -> ta.Any:
478
+ s = check.non_empty_str(self._source[m.start:m.end])
479
+ if s == '*':
480
+ return Repeat.Times(0)
481
+ elif '*' in s:
482
+ check.state(s.count('*') == 1)
483
+ if s.endswith('*'):
484
+ return Repeat.Times(int(s[:-1]))
485
+ else:
486
+ mi, mx = s.split('*')
487
+ return Repeat.Times(int(mi), int(mx))
488
+ else:
489
+ return Repeat.Times(n := int(s), n)
490
+
476
491
  @RuleVisitor.register('element')
477
492
  def visit_element_rule(self, m: Match) -> ta.Any:
478
493
  c = self.visit_match(check.single(m.children))
@@ -483,6 +498,40 @@ class MetaGrammarRuleVisitor(RuleVisitor[ta.Any]):
483
498
  else:
484
499
  raise TypeError(c)
485
500
 
501
+ @RuleVisitor.register('group')
502
+ def visit_group_rule(self, m: Match) -> ta.Any:
503
+ return self.visit_match(check.single(m.children))
504
+
505
+ @RuleVisitor.register('option')
506
+ def visit_option_rule(self, m: Match) -> ta.Any:
507
+ c = self.visit_match(check.single(m.children))
508
+ return option(check.isinstance(c, Parser))
509
+
510
+ @RuleVisitor.register('num-val')
511
+ def visit_num_val_rule(self, m: Match) -> ta.Any:
512
+ return self.visit_match(check.single(m.children))
513
+
514
+ def _parse_num_val(self, s: str, base: int) -> Parser:
515
+ if '-' in s:
516
+ check.not_in('.', s)
517
+ lo, hi = [chr(int(p, base)) for p in s.split('-')]
518
+ return literal(lo, hi)
519
+ elif '.' in s:
520
+ check.not_in('-', s)
521
+ cs = [chr(int(p, base)) for p in s.split('.')]
522
+ return concat(*[literal(c, c) for c in cs])
523
+ else:
524
+ c = chr(int(s, base))
525
+ return literal(c, c)
526
+
527
+ @RuleVisitor.register('dec-val')
528
+ def visit_dec_val_rule(self, m: Match) -> ta.Any:
529
+ return self._parse_num_val(self._source[m.start + 1:m.end], 10)
530
+
531
+ @RuleVisitor.register('hex-val')
532
+ def visit_hex_val_rule(self, m: Match) -> ta.Any:
533
+ return self._parse_num_val(self._source[m.start + 1:m.end], 16)
534
+
486
535
  @RuleVisitor.register('char-val')
487
536
  def visit_char_val_rule(self, m: Match) -> ta.Any:
488
537
  return self.visit_match(check.single(m.children))
@@ -504,48 +553,22 @@ class MetaGrammarRuleVisitor(RuleVisitor[ta.Any]):
504
553
  check.state(self._source[m.end - 1] == '"')
505
554
  return self.QuotedString(self._source[m.start + 1:m.end - 1])
506
555
 
507
- @RuleVisitor.register('repeat')
508
- def visit_repeat_rule(self, m: Match) -> ta.Any:
509
- # !!! FIXME: boneheaded args, repeat(1, c) currently means 1-*, should be exactly 1-1, should explicitly pass
510
- # None for *
511
- s = self._source[m.start:m.end]
512
- if '*' in s:
513
- check.state(s.count('*') == 1)
514
- if s.endswith('*'):
515
- return Repeat.Times(int(s[:-1]))
516
- else:
517
- mi, mx = s.split('*')
518
- return Repeat.Times(int(mi), int(mx))
519
- else:
520
- return Repeat.Times(n := int(s), n)
521
-
522
- @RuleVisitor.register('group')
523
- def visit_group_rule(self, m: Match) -> ta.Any:
524
- return self.visit_match(check.single(m.children))
525
-
526
- @RuleVisitor.register('num-val')
527
- def visit_num_val_rule(self, m: Match) -> ta.Any:
528
- return self.visit_match(check.single(m.children))
529
-
530
- @RuleVisitor.register('hex-val')
531
- def visit_hex_val_rule(self, m: Match) -> ta.Any:
532
- s = self._source[m.start + 1:m.end]
533
- if '-' in s:
534
- lo, hi = [chr(int(p, 16)) for p in s.split('-')]
535
- return literal(lo, hi)
536
- else:
537
- c = chr(int(s, 16))
538
- return literal(c, c)
539
-
540
556
 
541
557
  def parse_grammar(
542
558
  source: str,
543
559
  *,
544
560
  no_core_rules: bool = False,
561
+ root: str | None = None,
562
+ **kwargs: ta.Any,
545
563
  ) -> Grammar:
546
564
  source = fix_grammar_ws(source)
547
565
 
548
- if (mg_m := parse_rules(META_GRAMMAR, source)) is None:
566
+ if (mg_m := parse_rules(
567
+ META_GRAMMAR,
568
+ source,
569
+ complete=True,
570
+ **kwargs,
571
+ )) is None:
549
572
  raise AbnfGrammarParseError(source)
550
573
 
551
574
  check.isinstance(mg_m.parser, Repeat)
@@ -556,4 +579,5 @@ def parse_grammar(
556
579
  return Grammar(
557
580
  *rules,
558
581
  *(CORE_RULES if not no_core_rules else []),
582
+ root=root,
559
583
  )
@@ -242,8 +242,6 @@ def repeat(min: int, max: int | None, child: Parser) -> Repeat: # noqa
242
242
 
243
243
 
244
244
  def repeat(*args):
245
- # !!! FIXME: boneheaded args, repeat(1, c) currently means 1-*, should be exactly 1-1, should explicitly pass
246
- # None for *
247
245
  min: int # noqa
248
246
  max: int | None # noqa
249
247
 
@@ -6,6 +6,7 @@ from omlish import check
6
6
 
7
7
  from .base import Grammar
8
8
  from .base import Match
9
+ from .errors import AbnfIncompleteParseError
9
10
  from .parsers import RuleRef
10
11
 
11
12
 
@@ -41,15 +42,22 @@ def parse_rules(
41
42
  grammar: Grammar,
42
43
  source: str,
43
44
  root: str | None = None,
45
+ *,
46
+ start: int = 0,
47
+ complete: bool = False,
44
48
  **kwargs: ta.Any,
45
49
  ) -> Match | None:
46
50
  if (match := grammar.parse(
47
51
  source,
48
52
  root,
53
+ start=start,
49
54
  **kwargs,
50
55
  )) is None:
51
56
  return None
52
57
 
58
+ if complete and (match.start, match.end) != (start, len(source)):
59
+ raise AbnfIncompleteParseError
60
+
53
61
  match = only_match_rules(match)
54
62
  match = strip_insignificant_match_rules(match, grammar)
55
63
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omextra
3
- Version: 0.0.0.dev473
3
+ Version: 0.0.0.dev474
4
4
  Summary: omextra
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Python: >=3.13
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: omlish==0.0.0.dev473
17
+ Requires-Dist: omlish==0.0.0.dev474
18
18
  Dynamic: license-file
19
19
 
20
20
  # Overview
@@ -20,7 +20,7 @@ omextra/collections/hamt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
20
20
  omextra/collections/hamt/_hamt.c,sha256=LDYWBuAl4685DbAZICrzO--EfIN8PjHZq0MUJYBAD74,100898
21
21
  omextra/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  omextra/formats/goyaml/LICENSE,sha256=qkavv9cjd59BFIFOMVMJMrC3FCEIELrBTA-GPhAFkoY,1071
23
- omextra/formats/goyaml/__init__.py,sha256=HuJqVB6wyqzQcHMRCW9r3ciPnjl3UvhDT-LjRp7kHDo,1817
23
+ omextra/formats/goyaml/__init__.py,sha256=Wf7WukYGHk2Pqep2ZGRzz2ZznXcay0oVVmrqvqgYIoo,1821
24
24
  omextra/formats/goyaml/ast.py,sha256=55CyoNRiaDmu6YeKE_PRt51fE7zr35YcTWSDzVRjPRo,69984
25
25
  omextra/formats/goyaml/errors.py,sha256=UQfuManw4kOJKnXrV6MjFqt0ZU6KkwZL75KMdQQ6ZyU,949
26
26
  omextra/formats/goyaml/parsing.py,sha256=vZotOxOhLTrE9AGfXbSZcDrVC652PJ3K3ageu6aRT6Q,90558
@@ -64,13 +64,13 @@ omextra/sql/parsing/_antlr/MinisqlVisitor.py,sha256=UPs2qA2VlNRP_LMwF0DpMxMir9tI
64
64
  omextra/sql/parsing/_antlr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
65
65
  omextra/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
66
  omextra/text/abnf/LICENSE,sha256=UJzrhSePw9TVm0VfkVmx9NRHkPS1n6jx2UgajTb14ts,1054
67
- omextra/text/abnf/__init__.py,sha256=v1ABrlcdhCB8ezqHZPl3MZ6SYoEZNerGET5MHjFYhP8,967
68
- omextra/text/abnf/base.py,sha256=oO9e8Rd0kjdjJ6wWtpzIJOcY_E0QgUSAltpuwqWx-aQ,7476
67
+ omextra/text/abnf/__init__.py,sha256=4ckTD1WSkte_7LzO7vvhcZ17uEdSrNdnpkkuJBRJ2BY,1095
68
+ omextra/text/abnf/base.py,sha256=xDlMH9jaGXh2PN4DMR6AIMB-zOU_MVy20BcEd6Bpu4U,8128
69
69
  omextra/text/abnf/core.py,sha256=VUD52hKgDsesvPjmhL1UZVXtpYr-EpWyBprdy722YTY,2303
70
- omextra/text/abnf/errors.py,sha256=z_RMXMYhPwSUb1neJpJG-XUvkSS87uLJEX9p4wmXQfU,88
71
- omextra/text/abnf/meta.py,sha256=ltiq70jpTB8Ab3jTfqRubmRdI-42SLPXztLk1_EWFLU,13704
72
- omextra/text/abnf/parsers.py,sha256=BA5XdbiWh4UyabV4-rajSjHBOBXNa6ieTDs9CwM4nRU,9351
73
- omextra/text/abnf/utils.py,sha256=OWJe9DvSidOLNzkbdUXdLupDKEIDy6TtQFPVjDmyCng,1420
70
+ omextra/text/abnf/errors.py,sha256=uj1oQvRVRlWkMG8mpmcRUg25kICeIJx5EWAVij3pmXc,142
71
+ omextra/text/abnf/meta.py,sha256=1i2AAGZBLEQhF2HUYQPr385qAMMYLEo0dZT-dcH2Gv0,14447
72
+ omextra/text/abnf/parsers.py,sha256=JKRff1lXbjbKokGL5IBG9tnPflrQ0Fd7X--MRcKTdtE,9209
73
+ omextra/text/abnf/utils.py,sha256=UXJ0MlTkigm3cWuKVU1Ao3bVjQKqy6sZgPni1aVgFgk,1667
74
74
  omextra/text/abnf/visitors.py,sha256=kAWPmc3fAOLynLoVl_-ciG_TA3XG7HPca9_I1vI4rL0,1288
75
75
  omextra/text/antlr/__init__.py,sha256=88bMl_28cfSKslgOkMGYXqALgsHz3KC4LFvAVtzj7k8,89
76
76
  omextra/text/antlr/delimit.py,sha256=s0Jlu6oOamtuyWv_V98P0YC7HmgFJBF7GHVsDfMYTdI,3476
@@ -145,9 +145,9 @@ omextra/text/antlr/cli/__main__.py,sha256=ckYkj0drxabBVwWYewH2SS36TTeAxllZtS4xEl
145
145
  omextra/text/antlr/cli/cli.py,sha256=LW8pJNmySBOV3g8QxquPjUgxFv7YblzEyi555hHH3_M,1234
146
146
  omextra/text/antlr/cli/consts.py,sha256=HUYJP9j4RfeuuQv6HFd2oFMS0piWJ9Sq1tbeAs4OlBc,290
147
147
  omextra/text/antlr/cli/gen.py,sha256=HYleVptrpynwcl6GspX6O9_oMRSxwdYAQGuUFfDYse8,5236
148
- omextra-0.0.0.dev473.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
149
- omextra-0.0.0.dev473.dist-info/METADATA,sha256=4KrfUl4grgwui8gUkPsKwH83Mo313ZP45Rjibw5Vqhk,1001
150
- omextra-0.0.0.dev473.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
151
- omextra-0.0.0.dev473.dist-info/entry_points.txt,sha256=-MFAMks5HgZ60Ore0Wl5lKVKk8z4kf1Ls3WY9E_OlCU,37
152
- omextra-0.0.0.dev473.dist-info/top_level.txt,sha256=o1nCNRejLMcayDngLuWMWwaeOucz33BXbpuoVvvzjPc,8
153
- omextra-0.0.0.dev473.dist-info/RECORD,,
148
+ omextra-0.0.0.dev474.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
149
+ omextra-0.0.0.dev474.dist-info/METADATA,sha256=urA8Yo0Co_EPdfsAHGrSSZff9wEKE6t3ASadx1mlgvQ,1001
150
+ omextra-0.0.0.dev474.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
151
+ omextra-0.0.0.dev474.dist-info/entry_points.txt,sha256=-MFAMks5HgZ60Ore0Wl5lKVKk8z4kf1Ls3WY9E_OlCU,37
152
+ omextra-0.0.0.dev474.dist-info/top_level.txt,sha256=o1nCNRejLMcayDngLuWMWwaeOucz33BXbpuoVvvzjPc,8
153
+ omextra-0.0.0.dev474.dist-info/RECORD,,