omextra 0.0.0.dev496__py3-none-any.whl → 0.0.0.dev498__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/text/abnf/__init__.py +51 -18
- omextra/text/abnf/_dataclasses.py +246 -0
- omextra/text/abnf/base.py +21 -257
- omextra/text/abnf/core.py +22 -10
- omextra/text/abnf/grammars.py +235 -0
- omextra/text/abnf/internal.py +1 -1
- omextra/text/abnf/matches.py +145 -0
- omextra/text/abnf/meta.py +45 -12
- omextra/text/abnf/ops.py +76 -9
- omextra/text/abnf/opto.py +257 -0
- omextra/text/abnf/parsing.py +134 -20
- omextra/text/abnf/utils.py +38 -41
- omextra/text/abnf/visitors.py +1 -1
- {omextra-0.0.0.dev496.dist-info → omextra-0.0.0.dev498.dist-info}/METADATA +2 -2
- {omextra-0.0.0.dev496.dist-info → omextra-0.0.0.dev498.dist-info}/RECORD +19 -16
- {omextra-0.0.0.dev496.dist-info → omextra-0.0.0.dev498.dist-info}/WHEEL +0 -0
- {omextra-0.0.0.dev496.dist-info → omextra-0.0.0.dev498.dist-info}/entry_points.txt +0 -0
- {omextra-0.0.0.dev496.dist-info → omextra-0.0.0.dev498.dist-info}/licenses/LICENSE +0 -0
- {omextra-0.0.0.dev496.dist-info → omextra-0.0.0.dev498.dist-info}/top_level.txt +0 -0
omextra/text/abnf/__init__.py
CHANGED
|
@@ -5,20 +5,45 @@ Originally based on library by Charles Yeomans (see LICENSE file):
|
|
|
5
5
|
|
|
6
6
|
https://github.com/declaresub/abnf/tree/561ced67c0a8afc869ad0de5b39dbe4f6e71b0d8/src/abnf
|
|
7
7
|
|
|
8
|
-
It has however been
|
|
8
|
+
It has however been entirely rewritten.
|
|
9
9
|
|
|
10
10
|
====
|
|
11
11
|
|
|
12
12
|
TODO:
|
|
13
|
-
-
|
|
14
|
-
- get greedier
|
|
15
|
-
- match-powered optimizer
|
|
16
|
-
- greedily compile regexes
|
|
13
|
+
- opto
|
|
17
14
|
- error reporting
|
|
18
|
-
- codegen
|
|
15
|
+
- codegen?
|
|
16
|
+
- | as either(first_match=True)
|
|
17
|
+
- optional auto SPACE channel for ALL-UPCASE-RULE-NAMES
|
|
19
18
|
- fix_ws problem
|
|
20
19
|
- auto? no, need to keep lines / offsets accurate for errors
|
|
21
20
|
- relax CRLF rule by default?
|
|
21
|
+
- grammar transform? helper kwarg?
|
|
22
|
+
- kwarg to mark uppercase rules insignificant
|
|
23
|
+
- ebnf mode?
|
|
24
|
+
- peg / lalr engines?
|
|
25
|
+
- must always keep true abnf mode
|
|
26
|
+
- optionally separate lexing step
|
|
27
|
+
|
|
28
|
+
====
|
|
29
|
+
|
|
30
|
+
| Feature | EBNF | ABNF |
|
|
31
|
+
| ------------------------- | -------------- | ---------------- |
|
|
32
|
+
| Rule terminator | `;` | none |
|
|
33
|
+
| Alternation | `|` | `/` |
|
|
34
|
+
| Optional | `[a]` or `a?` | `[a]` |
|
|
35
|
+
| Zero or more | `a*` | `*a` |
|
|
36
|
+
| One or more | `a+` | `1*a` |
|
|
37
|
+
| Bounded repetition | `1..5 a` | `1*5a` |
|
|
38
|
+
| Character ranges | sometimes: | `%xNN-NN` |
|
|
39
|
+
| | `"0" .. "9"` | |
|
|
40
|
+
| Literal chars | `'a'` or `"a"` | `"a"` only |
|
|
41
|
+
| Case-insensitive literals | no | `%i"..."` |
|
|
42
|
+
| Comments | `(* *)` or | `;` |
|
|
43
|
+
| | `/* */` or | |
|
|
44
|
+
| | `-- ` | |
|
|
45
|
+
| Rule names | case-sensitive | case-insensitive |
|
|
46
|
+
|
|
22
47
|
"""
|
|
23
48
|
from omlish import dataclasses as _dc # noqa
|
|
24
49
|
|
|
@@ -33,16 +58,7 @@ _dc.init_package(
|
|
|
33
58
|
|
|
34
59
|
|
|
35
60
|
from .base import ( # noqa
|
|
36
|
-
Match,
|
|
37
|
-
longest_match,
|
|
38
|
-
|
|
39
61
|
Op,
|
|
40
|
-
|
|
41
|
-
Rule,
|
|
42
|
-
Grammar,
|
|
43
|
-
|
|
44
|
-
iter_parse,
|
|
45
|
-
parse,
|
|
46
62
|
)
|
|
47
63
|
|
|
48
64
|
from .core import ( # noqa
|
|
@@ -54,6 +70,21 @@ from .errors import ( # noqa
|
|
|
54
70
|
AbnfGrammarParseError,
|
|
55
71
|
)
|
|
56
72
|
|
|
73
|
+
from .grammars import ( # noqa
|
|
74
|
+
Channel,
|
|
75
|
+
Rule,
|
|
76
|
+
RulesCollection,
|
|
77
|
+
|
|
78
|
+
Grammar,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
from .matches import ( # noqa
|
|
82
|
+
Match,
|
|
83
|
+
|
|
84
|
+
longest_match,
|
|
85
|
+
filter_matches,
|
|
86
|
+
)
|
|
87
|
+
|
|
57
88
|
from .meta import ( # noqa
|
|
58
89
|
META_GRAMMAR_RULES,
|
|
59
90
|
META_GRAMMAR,
|
|
@@ -82,11 +113,13 @@ from .ops import ( # noqa
|
|
|
82
113
|
rule,
|
|
83
114
|
)
|
|
84
115
|
|
|
116
|
+
from .parsing import ( # noqa
|
|
117
|
+
iter_parse,
|
|
118
|
+
parse,
|
|
119
|
+
)
|
|
120
|
+
|
|
85
121
|
from .utils import ( # noqa
|
|
86
|
-
strip_insignificant_match_rules,
|
|
87
122
|
only_match_rules,
|
|
88
123
|
|
|
89
|
-
parse_rules,
|
|
90
|
-
|
|
91
124
|
fix_ws,
|
|
92
125
|
)
|
|
@@ -39,6 +39,8 @@ def _register(**kwargs):
|
|
|
39
39
|
cls_names=(
|
|
40
40
|
('omextra.text.abnf', 'MetaGrammarRuleMatchVisitor.QuotedString'),
|
|
41
41
|
('omextra.text.abnf', 'MetaGrammarRuleMatchVisitor.RuleName'),
|
|
42
|
+
('omextra.text.abnf', '_CaseInsensitiveStringLiteralRegexItem'),
|
|
43
|
+
('omextra.text.abnf', '_StringLiteralRegexItem'),
|
|
42
44
|
),
|
|
43
45
|
)
|
|
44
46
|
def _process_dataclass__30a5dd74853303d917aae5f67d4e7189615d1440():
|
|
@@ -436,3 +438,247 @@ def _process_dataclass__3dce49e08774c707abbc7a6513e35ccdc43001c9():
|
|
|
436
438
|
setattr(__dataclass__cls, '__init__', __init__)
|
|
437
439
|
|
|
438
440
|
return _process_dataclass
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
@_register(
|
|
444
|
+
plan_repr=(
|
|
445
|
+
"Plans(tup=(CopyPlan(fields=()), EqPlan(fields=()), FrozenPlan(fields=(), allow_dynamic_dunder_attrs=False), Ha"
|
|
446
|
+
"shPlan(action='add', fields=(), cache=False), InitPlan(fields=(), self_param='self', std_params=(), kw_only_pa"
|
|
447
|
+
"rams=(), frozen=True, slots=False, post_init_params=None, init_fns=(), validate_fns=()), ReprPlan(fields=(), i"
|
|
448
|
+
"d=False, terse=False, default_fn=None)))"
|
|
449
|
+
),
|
|
450
|
+
plan_repr_sha1='e1f7edfe11f2b721d6a656c46e698fedc95461bb',
|
|
451
|
+
op_ref_idents=(),
|
|
452
|
+
cls_names=(
|
|
453
|
+
('omextra.text.abnf', '_RegexItem'),
|
|
454
|
+
),
|
|
455
|
+
)
|
|
456
|
+
def _process_dataclass__e1f7edfe11f2b721d6a656c46e698fedc95461bb():
|
|
457
|
+
def _process_dataclass(
|
|
458
|
+
*,
|
|
459
|
+
__dataclass__cls,
|
|
460
|
+
__dataclass__FieldFnValidationError, # noqa
|
|
461
|
+
__dataclass__FieldTypeValidationError, # noqa
|
|
462
|
+
__dataclass__FnValidationError, # noqa
|
|
463
|
+
__dataclass__FrozenInstanceError=dataclasses.FrozenInstanceError, # noqa
|
|
464
|
+
__dataclass__FunctionType=types.FunctionType, # noqa
|
|
465
|
+
__dataclass__HAS_DEFAULT_FACTORY=dataclasses._HAS_DEFAULT_FACTORY, # noqa
|
|
466
|
+
__dataclass__MISSING=dataclasses.MISSING, # noqa
|
|
467
|
+
__dataclass__None=None, # noqa
|
|
468
|
+
__dataclass__TypeError=TypeError, # noqa
|
|
469
|
+
__dataclass___recursive_repr=reprlib.recursive_repr, # noqa
|
|
470
|
+
__dataclass__isinstance=isinstance, # noqa
|
|
471
|
+
__dataclass__object_setattr=object.__setattr__, # noqa
|
|
472
|
+
__dataclass__property=property, # noqa
|
|
473
|
+
):
|
|
474
|
+
def __copy__(self):
|
|
475
|
+
if self.__class__ is not __dataclass__cls:
|
|
476
|
+
raise TypeError(self)
|
|
477
|
+
return __dataclass__cls() # noqa
|
|
478
|
+
|
|
479
|
+
__copy__.__qualname__ = f"{__dataclass__cls.__qualname__}.__copy__"
|
|
480
|
+
if '__copy__' in __dataclass__cls.__dict__:
|
|
481
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __copy__ in class {__dataclass__cls.__name__}")
|
|
482
|
+
setattr(__dataclass__cls, '__copy__', __copy__)
|
|
483
|
+
|
|
484
|
+
def __eq__(self, other):
|
|
485
|
+
if self is other:
|
|
486
|
+
return True
|
|
487
|
+
if self.__class__ is not other.__class__:
|
|
488
|
+
return NotImplemented
|
|
489
|
+
return True
|
|
490
|
+
|
|
491
|
+
__eq__.__qualname__ = f"{__dataclass__cls.__qualname__}.__eq__"
|
|
492
|
+
if '__eq__' in __dataclass__cls.__dict__:
|
|
493
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __eq__ in class {__dataclass__cls.__name__}")
|
|
494
|
+
setattr(__dataclass__cls, '__eq__', __eq__)
|
|
495
|
+
|
|
496
|
+
def __setattr__(self, name, value):
|
|
497
|
+
if (
|
|
498
|
+
type(self) is __dataclass__cls
|
|
499
|
+
):
|
|
500
|
+
raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
|
|
501
|
+
super(__dataclass__cls, self).__setattr__(name, value)
|
|
502
|
+
|
|
503
|
+
__setattr__.__qualname__ = f"{__dataclass__cls.__qualname__}.__setattr__"
|
|
504
|
+
if '__setattr__' in __dataclass__cls.__dict__:
|
|
505
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __setattr__ in class {__dataclass__cls.__name__}")
|
|
506
|
+
setattr(__dataclass__cls, '__setattr__', __setattr__)
|
|
507
|
+
|
|
508
|
+
def __delattr__(self, name):
|
|
509
|
+
if (
|
|
510
|
+
type(self) is __dataclass__cls
|
|
511
|
+
):
|
|
512
|
+
raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
|
|
513
|
+
super(__dataclass__cls, self).__delattr__(name)
|
|
514
|
+
|
|
515
|
+
__delattr__.__qualname__ = f"{__dataclass__cls.__qualname__}.__delattr__"
|
|
516
|
+
if '__delattr__' in __dataclass__cls.__dict__:
|
|
517
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __delattr__ in class {__dataclass__cls.__name__}")
|
|
518
|
+
setattr(__dataclass__cls, '__delattr__', __delattr__)
|
|
519
|
+
|
|
520
|
+
def __hash__(self):
|
|
521
|
+
return hash(())
|
|
522
|
+
|
|
523
|
+
__hash__.__qualname__ = f"{__dataclass__cls.__qualname__}.__hash__"
|
|
524
|
+
setattr(__dataclass__cls, '__hash__', __hash__)
|
|
525
|
+
|
|
526
|
+
def __init__(
|
|
527
|
+
self,
|
|
528
|
+
) -> __dataclass__None:
|
|
529
|
+
pass
|
|
530
|
+
|
|
531
|
+
__init__.__qualname__ = f"{__dataclass__cls.__qualname__}.__init__"
|
|
532
|
+
if '__init__' in __dataclass__cls.__dict__:
|
|
533
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __init__ in class {__dataclass__cls.__name__}")
|
|
534
|
+
setattr(__dataclass__cls, '__init__', __init__)
|
|
535
|
+
|
|
536
|
+
@__dataclass___recursive_repr()
|
|
537
|
+
def __repr__(self):
|
|
538
|
+
parts = []
|
|
539
|
+
return (
|
|
540
|
+
f"{self.__class__.__qualname__}("
|
|
541
|
+
f"{', '.join(parts)}"
|
|
542
|
+
f")"
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
__repr__.__qualname__ = f"{__dataclass__cls.__qualname__}.__repr__"
|
|
546
|
+
if '__repr__' in __dataclass__cls.__dict__:
|
|
547
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __repr__ in class {__dataclass__cls.__name__}")
|
|
548
|
+
setattr(__dataclass__cls, '__repr__', __repr__)
|
|
549
|
+
|
|
550
|
+
return _process_dataclass
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
@_register(
|
|
554
|
+
plan_repr=(
|
|
555
|
+
"Plans(tup=(CopyPlan(fields=('ps',)), EqPlan(fields=('ps',)), FrozenPlan(fields=('ps',), allow_dynamic_dunder_a"
|
|
556
|
+
"ttrs=False), HashPlan(action='add', fields=('ps',), cache=False), InitPlan(fields=(InitPlan.Field(name='ps', a"
|
|
557
|
+
"nnotation=OpRef(name='init.fields.0.annotation'), default=None, default_factory=None, init=True, override=Fals"
|
|
558
|
+
"e, field_type=FieldType.INSTANCE, coerce=None, validate=None, check_type=None),), self_param='self', std_param"
|
|
559
|
+
"s=('ps',), kw_only_params=(), frozen=True, slots=False, post_init_params=None, init_fns=(), validate_fns=()), "
|
|
560
|
+
"ReprPlan(fields=(ReprPlan.Field(name='ps', kw_only=False, fn=None),), id=False, terse=False, default_fn=None))"
|
|
561
|
+
")"
|
|
562
|
+
),
|
|
563
|
+
plan_repr_sha1='f7dc3147180d5d4dc248e9c0d94aa0f1e503c4c7',
|
|
564
|
+
op_ref_idents=(
|
|
565
|
+
'__dataclass__init__fields__0__annotation',
|
|
566
|
+
),
|
|
567
|
+
cls_names=(
|
|
568
|
+
('omextra.text.abnf', '_RegexRegexItem'),
|
|
569
|
+
),
|
|
570
|
+
)
|
|
571
|
+
def _process_dataclass__f7dc3147180d5d4dc248e9c0d94aa0f1e503c4c7():
|
|
572
|
+
def _process_dataclass(
|
|
573
|
+
*,
|
|
574
|
+
__dataclass__cls,
|
|
575
|
+
__dataclass__init__fields__0__annotation,
|
|
576
|
+
__dataclass__FieldFnValidationError, # noqa
|
|
577
|
+
__dataclass__FieldTypeValidationError, # noqa
|
|
578
|
+
__dataclass__FnValidationError, # noqa
|
|
579
|
+
__dataclass__FrozenInstanceError=dataclasses.FrozenInstanceError, # noqa
|
|
580
|
+
__dataclass__FunctionType=types.FunctionType, # noqa
|
|
581
|
+
__dataclass__HAS_DEFAULT_FACTORY=dataclasses._HAS_DEFAULT_FACTORY, # noqa
|
|
582
|
+
__dataclass__MISSING=dataclasses.MISSING, # noqa
|
|
583
|
+
__dataclass__None=None, # noqa
|
|
584
|
+
__dataclass__TypeError=TypeError, # noqa
|
|
585
|
+
__dataclass___recursive_repr=reprlib.recursive_repr, # noqa
|
|
586
|
+
__dataclass__isinstance=isinstance, # noqa
|
|
587
|
+
__dataclass__object_setattr=object.__setattr__, # noqa
|
|
588
|
+
__dataclass__property=property, # noqa
|
|
589
|
+
):
|
|
590
|
+
def __copy__(self):
|
|
591
|
+
if self.__class__ is not __dataclass__cls:
|
|
592
|
+
raise TypeError(self)
|
|
593
|
+
return __dataclass__cls( # noqa
|
|
594
|
+
ps=self.ps,
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
__copy__.__qualname__ = f"{__dataclass__cls.__qualname__}.__copy__"
|
|
598
|
+
if '__copy__' in __dataclass__cls.__dict__:
|
|
599
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __copy__ in class {__dataclass__cls.__name__}")
|
|
600
|
+
setattr(__dataclass__cls, '__copy__', __copy__)
|
|
601
|
+
|
|
602
|
+
def __eq__(self, other):
|
|
603
|
+
if self is other:
|
|
604
|
+
return True
|
|
605
|
+
if self.__class__ is not other.__class__:
|
|
606
|
+
return NotImplemented
|
|
607
|
+
return (
|
|
608
|
+
self.ps == other.ps
|
|
609
|
+
)
|
|
610
|
+
|
|
611
|
+
__eq__.__qualname__ = f"{__dataclass__cls.__qualname__}.__eq__"
|
|
612
|
+
if '__eq__' in __dataclass__cls.__dict__:
|
|
613
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __eq__ in class {__dataclass__cls.__name__}")
|
|
614
|
+
setattr(__dataclass__cls, '__eq__', __eq__)
|
|
615
|
+
|
|
616
|
+
__dataclass___setattr_frozen_fields = {
|
|
617
|
+
'ps',
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
def __setattr__(self, name, value):
|
|
621
|
+
if (
|
|
622
|
+
type(self) is __dataclass__cls
|
|
623
|
+
or name in __dataclass___setattr_frozen_fields
|
|
624
|
+
):
|
|
625
|
+
raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
|
|
626
|
+
super(__dataclass__cls, self).__setattr__(name, value)
|
|
627
|
+
|
|
628
|
+
__setattr__.__qualname__ = f"{__dataclass__cls.__qualname__}.__setattr__"
|
|
629
|
+
if '__setattr__' in __dataclass__cls.__dict__:
|
|
630
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __setattr__ in class {__dataclass__cls.__name__}")
|
|
631
|
+
setattr(__dataclass__cls, '__setattr__', __setattr__)
|
|
632
|
+
|
|
633
|
+
__dataclass___delattr_frozen_fields = {
|
|
634
|
+
'ps',
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
def __delattr__(self, name):
|
|
638
|
+
if (
|
|
639
|
+
type(self) is __dataclass__cls
|
|
640
|
+
or name in __dataclass___delattr_frozen_fields
|
|
641
|
+
):
|
|
642
|
+
raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
|
|
643
|
+
super(__dataclass__cls, self).__delattr__(name)
|
|
644
|
+
|
|
645
|
+
__delattr__.__qualname__ = f"{__dataclass__cls.__qualname__}.__delattr__"
|
|
646
|
+
if '__delattr__' in __dataclass__cls.__dict__:
|
|
647
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __delattr__ in class {__dataclass__cls.__name__}")
|
|
648
|
+
setattr(__dataclass__cls, '__delattr__', __delattr__)
|
|
649
|
+
|
|
650
|
+
def __hash__(self):
|
|
651
|
+
return hash((
|
|
652
|
+
self.ps,
|
|
653
|
+
))
|
|
654
|
+
|
|
655
|
+
__hash__.__qualname__ = f"{__dataclass__cls.__qualname__}.__hash__"
|
|
656
|
+
setattr(__dataclass__cls, '__hash__', __hash__)
|
|
657
|
+
|
|
658
|
+
def __init__(
|
|
659
|
+
self,
|
|
660
|
+
ps: __dataclass__init__fields__0__annotation,
|
|
661
|
+
) -> __dataclass__None:
|
|
662
|
+
__dataclass__object_setattr(self, 'ps', ps)
|
|
663
|
+
|
|
664
|
+
__init__.__qualname__ = f"{__dataclass__cls.__qualname__}.__init__"
|
|
665
|
+
if '__init__' in __dataclass__cls.__dict__:
|
|
666
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __init__ in class {__dataclass__cls.__name__}")
|
|
667
|
+
setattr(__dataclass__cls, '__init__', __init__)
|
|
668
|
+
|
|
669
|
+
@__dataclass___recursive_repr()
|
|
670
|
+
def __repr__(self):
|
|
671
|
+
parts = []
|
|
672
|
+
parts.append(f"ps={self.ps!r}")
|
|
673
|
+
return (
|
|
674
|
+
f"{self.__class__.__qualname__}("
|
|
675
|
+
f"{', '.join(parts)}"
|
|
676
|
+
f")"
|
|
677
|
+
)
|
|
678
|
+
|
|
679
|
+
__repr__.__qualname__ = f"{__dataclass__cls.__qualname__}.__repr__"
|
|
680
|
+
if '__repr__' in __dataclass__cls.__dict__:
|
|
681
|
+
raise __dataclass__TypeError(f"Cannot overwrite attribute __repr__ in class {__dataclass__cls.__name__}")
|
|
682
|
+
setattr(__dataclass__cls, '__repr__', __repr__)
|
|
683
|
+
|
|
684
|
+
return _process_dataclass
|
omextra/text/abnf/base.py
CHANGED
|
@@ -1,105 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import itertools
|
|
1
|
+
import abc
|
|
3
2
|
import typing as ta
|
|
4
3
|
|
|
5
4
|
from omlish import check
|
|
6
5
|
from omlish import lang
|
|
7
6
|
|
|
8
|
-
from .errors import AbnfError
|
|
9
|
-
from .errors import AbnfIncompleteParseError
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
with lang.auto_proxy_import(globals()):
|
|
13
|
-
from . import ops
|
|
14
|
-
from . import parsing
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@ta.final
|
|
21
|
-
class Match(ta.NamedTuple):
|
|
22
|
-
op: 'Op'
|
|
23
|
-
start: int
|
|
24
|
-
end: int
|
|
25
|
-
children: tuple['Match', ...]
|
|
26
|
-
|
|
27
|
-
@property
|
|
28
|
-
def length(self) -> int:
|
|
29
|
-
return self.end - self.start
|
|
30
|
-
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
def __repr__(self) -> str:
|
|
34
|
-
return (
|
|
35
|
-
f'{self.__class__.__name__}('
|
|
36
|
-
f'{self.op._match_repr()}, ' # noqa
|
|
37
|
-
f'{self.start}, {self.end}'
|
|
38
|
-
f'{f", {self.children!r}" if self.children else ""})'
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
def render_to(
|
|
42
|
-
self,
|
|
43
|
-
write: ta.Callable[[str], ta.Any],
|
|
44
|
-
*,
|
|
45
|
-
indent: int | None = None,
|
|
46
|
-
_depth: int = 0,
|
|
47
|
-
) -> None:
|
|
48
|
-
ix: str | None = (' ' * (indent * _depth)) if indent is not None else None
|
|
49
|
-
if ix:
|
|
50
|
-
write(ix)
|
|
51
|
-
o = self.op
|
|
52
|
-
if isinstance(o, (ops.StringLiteral, ops.CaseInsensitiveStringLiteral)):
|
|
53
|
-
write(f'literal<{self.start}-{self.end}>({o.value!r})')
|
|
54
|
-
elif isinstance(o, ops.RangeLiteral):
|
|
55
|
-
write(f'literal<{self.start}-{self.end}>({o.value.lo!r}-{o.value.hi!r})')
|
|
56
|
-
else:
|
|
57
|
-
write(f'{o.__class__.__name__.lower()}<{self.start}-{self.end}>')
|
|
58
|
-
if isinstance(o, ops.RuleRef):
|
|
59
|
-
write(f':{o.name}')
|
|
60
|
-
if self.children:
|
|
61
|
-
write('(')
|
|
62
|
-
if ix is not None:
|
|
63
|
-
write('\n')
|
|
64
|
-
for i, c in enumerate(self.children):
|
|
65
|
-
if i and ix is None:
|
|
66
|
-
write(', ')
|
|
67
|
-
c.render_to(write, indent=indent, _depth=_depth + 1)
|
|
68
|
-
if ix is not None:
|
|
69
|
-
write(',\n')
|
|
70
|
-
if ix:
|
|
71
|
-
write(ix)
|
|
72
|
-
write(')')
|
|
73
|
-
|
|
74
|
-
def render(
|
|
75
|
-
self,
|
|
76
|
-
*,
|
|
77
|
-
indent: int | None = None,
|
|
78
|
-
) -> str:
|
|
79
|
-
sb = io.StringIO()
|
|
80
|
-
self.render_to(sb.write, indent=indent)
|
|
81
|
-
return sb.getvalue()
|
|
82
|
-
|
|
83
|
-
def __str__(self) -> str:
|
|
84
|
-
return self.render()
|
|
85
|
-
|
|
86
|
-
#
|
|
87
|
-
|
|
88
|
-
def map_children(self, fn: ta.Callable[['Match'], 'Match']) -> 'Match':
|
|
89
|
-
return self._replace(children=tuple(map(fn, self.children)))
|
|
90
|
-
|
|
91
|
-
def flat_map_children(self, fn: ta.Callable[['Match'], ta.Iterable['Match']]) -> 'Match':
|
|
92
|
-
return self._replace(children=tuple(itertools.chain.from_iterable(map(fn, self.children))))
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def longest_match(ms: ta.Iterable[Match]) -> Match | None:
|
|
96
|
-
bm: Match | None = None
|
|
97
|
-
bl = 0
|
|
98
|
-
for m in ms:
|
|
99
|
-
l = m.length
|
|
100
|
-
if bm is None or l > bl:
|
|
101
|
-
bm, bl = m, l
|
|
102
|
-
return bm
|
|
8
|
+
OpTuple: ta.TypeAlias = tuple['Op', ...]
|
|
103
9
|
|
|
104
10
|
|
|
105
11
|
##
|
|
@@ -110,171 +16,29 @@ class Op(lang.Abstract, lang.PackageSealed):
|
|
|
110
16
|
return f'{self.__class__.__name__}@{id(self):x}'
|
|
111
17
|
|
|
112
18
|
|
|
113
|
-
class
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
##
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
class Rule(lang.Final):
|
|
121
|
-
def __init__(
|
|
122
|
-
self,
|
|
123
|
-
name: str,
|
|
124
|
-
op: Op,
|
|
125
|
-
*,
|
|
126
|
-
insignificant: bool = False,
|
|
127
|
-
) -> None:
|
|
128
|
-
super().__init__()
|
|
129
|
-
|
|
130
|
-
self._name = check.non_empty_str(name)
|
|
131
|
-
self._name_f = name.casefold()
|
|
132
|
-
self._op = check.isinstance(op, Op)
|
|
133
|
-
self._insignificant = insignificant
|
|
19
|
+
class CompositeOp(Op, lang.Abstract):
|
|
20
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
21
|
+
super().__init_subclass__(**kwargs)
|
|
134
22
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def name(self) -> str:
|
|
140
|
-
return self._name
|
|
141
|
-
|
|
142
|
-
@property
|
|
143
|
-
def name_f(self) -> str:
|
|
144
|
-
return self._name_f
|
|
145
|
-
|
|
146
|
-
@property
|
|
147
|
-
def op(self) -> Op:
|
|
148
|
-
return self._op
|
|
149
|
-
|
|
150
|
-
@property
|
|
151
|
-
def insignificant(self) -> bool:
|
|
152
|
-
return self._insignificant
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
class Grammar(lang.Final):
|
|
156
|
-
def __init__(
|
|
157
|
-
self,
|
|
158
|
-
*rules: Rule,
|
|
159
|
-
root: Rule | str | None = None,
|
|
160
|
-
) -> None:
|
|
161
|
-
super().__init__()
|
|
162
|
-
|
|
163
|
-
rules_set: set[Rule] = set()
|
|
164
|
-
rules_by_name: dict[str, Rule] = {}
|
|
165
|
-
rules_by_name_f: dict[str, Rule] = {}
|
|
166
|
-
rules_by_op: dict[Op, Rule] = {}
|
|
167
|
-
for gr in rules:
|
|
168
|
-
check.not_in(gr, rules_set)
|
|
169
|
-
check.not_in(gr._name, rules_by_name) # noqa
|
|
170
|
-
check.not_in(gr._name_f, rules_by_name_f) # noqa
|
|
171
|
-
check.not_in(gr._op, rules_by_op) # noqa
|
|
172
|
-
rules_set.add(gr)
|
|
173
|
-
rules_by_name[gr._name] = gr # noqa
|
|
174
|
-
rules_by_name_f[gr._name_f] = gr # noqa
|
|
175
|
-
rules_by_op[gr._op] = gr # noqa
|
|
176
|
-
self._rules = rules_set
|
|
177
|
-
self._rules_by_name: ta.Mapping[str, Rule] = rules_by_name
|
|
178
|
-
self._rules_by_name_f: ta.Mapping[str, Rule] = rules_by_name_f
|
|
179
|
-
self._rules_by_op: ta.Mapping[Op, Rule] = rules_by_op
|
|
180
|
-
|
|
181
|
-
if isinstance(root, str):
|
|
182
|
-
root = rules_by_name_f[root.casefold()]
|
|
183
|
-
self._root = root
|
|
184
|
-
|
|
185
|
-
@property
|
|
186
|
-
def root(self) -> Rule | None:
|
|
187
|
-
return self._root
|
|
188
|
-
|
|
189
|
-
def rule(self, name: str) -> Rule | None:
|
|
190
|
-
return self._rules_by_name_f.get(name.casefold())
|
|
191
|
-
|
|
192
|
-
def iter_parse(
|
|
193
|
-
self,
|
|
194
|
-
source: str,
|
|
195
|
-
root: Rule | str | None = None,
|
|
196
|
-
*,
|
|
197
|
-
start: int = 0,
|
|
198
|
-
debug: int = 0,
|
|
199
|
-
) -> ta.Iterator[Match]:
|
|
200
|
-
if root is None:
|
|
201
|
-
if (root := self._root) is None:
|
|
202
|
-
raise AbnfError('No root or default root specified')
|
|
23
|
+
try:
|
|
24
|
+
leaf_op_cls = LeafOp
|
|
25
|
+
except NameError:
|
|
26
|
+
pass
|
|
203
27
|
else:
|
|
204
|
-
|
|
205
|
-
root = self._rules_by_name_f[root.casefold()]
|
|
206
|
-
else:
|
|
207
|
-
root = check.in_(check.isinstance(root, Rule), self._rules)
|
|
208
|
-
|
|
209
|
-
return parsing._iter_parse( # noqa
|
|
210
|
-
self,
|
|
211
|
-
source,
|
|
212
|
-
root._op, # noqa
|
|
213
|
-
start,
|
|
214
|
-
debug=debug,
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
def parse(
|
|
218
|
-
self,
|
|
219
|
-
source: str,
|
|
220
|
-
root: str | None = None,
|
|
221
|
-
*,
|
|
222
|
-
start: int = 0,
|
|
223
|
-
complete: bool = False,
|
|
224
|
-
debug: int = 0,
|
|
225
|
-
) -> Match | None:
|
|
226
|
-
if (match := longest_match(self.iter_parse(
|
|
227
|
-
source,
|
|
228
|
-
root,
|
|
229
|
-
start=start,
|
|
230
|
-
debug=debug,
|
|
231
|
-
))) is None:
|
|
232
|
-
return None
|
|
233
|
-
|
|
234
|
-
if complete and (match.start, match.end) != (start, len(source)):
|
|
235
|
-
raise AbnfIncompleteParseError
|
|
236
|
-
|
|
237
|
-
return match
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
##
|
|
28
|
+
check.not_issubclass(cls, leaf_op_cls)
|
|
241
29
|
|
|
30
|
+
@property
|
|
31
|
+
@abc.abstractmethod
|
|
32
|
+
def children(self) -> OpTuple:
|
|
33
|
+
raise NotImplementedError
|
|
242
34
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
*,
|
|
247
|
-
root: str | None = None,
|
|
248
|
-
start: int = 0,
|
|
249
|
-
) -> ta.Iterator[Match]:
|
|
250
|
-
if isinstance(obj, Grammar):
|
|
251
|
-
gram = obj
|
|
252
|
-
elif isinstance(obj, Rule):
|
|
253
|
-
check.none(root)
|
|
254
|
-
gram = Grammar(obj, root=obj)
|
|
255
|
-
elif isinstance(obj, Op):
|
|
256
|
-
check.none(root)
|
|
257
|
-
gram = Grammar(Rule('root', obj), root='root')
|
|
258
|
-
else:
|
|
259
|
-
raise TypeError(obj)
|
|
35
|
+
@abc.abstractmethod
|
|
36
|
+
def replace_children(self, *children: Op) -> Op:
|
|
37
|
+
raise NotImplementedError
|
|
260
38
|
|
|
261
|
-
return gram.iter_parse(
|
|
262
|
-
src,
|
|
263
|
-
root,
|
|
264
|
-
start=start,
|
|
265
|
-
)
|
|
266
39
|
|
|
40
|
+
class LeafOp(Op, lang.Abstract):
|
|
41
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
42
|
+
super().__init_subclass__(**kwargs)
|
|
267
43
|
|
|
268
|
-
|
|
269
|
-
obj: Grammar | Rule | Op,
|
|
270
|
-
src: str,
|
|
271
|
-
*,
|
|
272
|
-
root: str | None = None,
|
|
273
|
-
start: int = 0,
|
|
274
|
-
) -> Match | None:
|
|
275
|
-
return longest_match(iter_parse(
|
|
276
|
-
obj,
|
|
277
|
-
src,
|
|
278
|
-
root=root,
|
|
279
|
-
start=start,
|
|
280
|
-
))
|
|
44
|
+
check.not_issubclass(cls, CompositeOp)
|