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.
- omextra/formats/goyaml/__init__.py +2 -2
- omextra/text/abnf/__init__.py +10 -0
- omextra/text/abnf/base.py +31 -11
- omextra/text/abnf/errors.py +4 -0
- omextra/text/abnf/meta.py +58 -34
- omextra/text/abnf/parsers.py +0 -2
- omextra/text/abnf/utils.py +8 -0
- {omextra-0.0.0.dev473.dist-info → omextra-0.0.0.dev474.dist-info}/METADATA +2 -2
- {omextra-0.0.0.dev473.dist-info → omextra-0.0.0.dev474.dist-info}/RECORD +13 -13
- {omextra-0.0.0.dev473.dist-info → omextra-0.0.0.dev474.dist-info}/WHEEL +0 -0
- {omextra-0.0.0.dev473.dist-info → omextra-0.0.0.dev474.dist-info}/entry_points.txt +0 -0
- {omextra-0.0.0.dev473.dist-info → omextra-0.0.0.dev474.dist-info}/licenses/LICENSE +0 -0
- {omextra-0.0.0.dev473.dist-info → omextra-0.0.0.dev474.dist-info}/top_level.txt +0 -0
|
@@ -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
|
|
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
|
|
omextra/text/abnf/__init__.py
CHANGED
|
@@ -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
|
-
|
|
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
|
|
235
|
-
def __init__(
|
|
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
|
|
omextra/text/abnf/errors.py
CHANGED
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(
|
|
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
|
)
|
omextra/text/abnf/parsers.py
CHANGED
|
@@ -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
|
|
omextra/text/abnf/utils.py
CHANGED
|
@@ -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.
|
|
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.
|
|
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=
|
|
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=
|
|
68
|
-
omextra/text/abnf/base.py,sha256=
|
|
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=
|
|
71
|
-
omextra/text/abnf/meta.py,sha256=
|
|
72
|
-
omextra/text/abnf/parsers.py,sha256=
|
|
73
|
-
omextra/text/abnf/utils.py,sha256=
|
|
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.
|
|
149
|
-
omextra-0.0.0.
|
|
150
|
-
omextra-0.0.0.
|
|
151
|
-
omextra-0.0.0.
|
|
152
|
-
omextra-0.0.0.
|
|
153
|
-
omextra-0.0.0.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|