omextra 0.0.0.dev497__py3-none-any.whl → 0.0.0.dev499__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 +45 -14
- omextra/text/abnf/_dataclasses.py +246 -0
- omextra/text/abnf/base.py +6 -279
- omextra/text/abnf/core.py +22 -10
- omextra/text/abnf/grammars.py +235 -0
- omextra/text/abnf/matches.py +145 -0
- omextra/text/abnf/meta.py +39 -17
- omextra/text/abnf/ops.py +67 -5
- omextra/text/abnf/opto.py +167 -64
- omextra/text/abnf/parsing.py +53 -5
- omextra/text/abnf/utils.py +38 -41
- omextra/text/abnf/visitors.py +1 -1
- {omextra-0.0.0.dev497.dist-info → omextra-0.0.0.dev499.dist-info}/METADATA +2 -2
- {omextra-0.0.0.dev497.dist-info → omextra-0.0.0.dev499.dist-info}/RECORD +18 -16
- {omextra-0.0.0.dev497.dist-info → omextra-0.0.0.dev499.dist-info}/WHEEL +0 -0
- {omextra-0.0.0.dev497.dist-info → omextra-0.0.0.dev499.dist-info}/entry_points.txt +0 -0
- {omextra-0.0.0.dev497.dist-info → omextra-0.0.0.dev499.dist-info}/licenses/LICENSE +0 -0
- {omextra-0.0.0.dev497.dist-info → omextra-0.0.0.dev499.dist-info}/top_level.txt +0 -0
omextra/text/abnf/__init__.py
CHANGED
|
@@ -13,10 +13,37 @@ TODO:
|
|
|
13
13
|
- opto
|
|
14
14
|
- error reporting
|
|
15
15
|
- codegen?
|
|
16
|
+
- | as either(first_match=True)
|
|
17
|
+
- optional auto SPACE channel for ALL-UPCASE-RULE-NAMES
|
|
16
18
|
- fix_ws problem
|
|
17
19
|
- auto? no, need to keep lines / offsets accurate for errors
|
|
18
20
|
- relax CRLF rule by default?
|
|
19
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
|
+
|
|
20
47
|
"""
|
|
21
48
|
from omlish import dataclasses as _dc # noqa
|
|
22
49
|
|
|
@@ -31,16 +58,7 @@ _dc.init_package(
|
|
|
31
58
|
|
|
32
59
|
|
|
33
60
|
from .base import ( # noqa
|
|
34
|
-
Match,
|
|
35
|
-
longest_match,
|
|
36
|
-
|
|
37
61
|
Op,
|
|
38
|
-
|
|
39
|
-
Rule,
|
|
40
|
-
Grammar,
|
|
41
|
-
|
|
42
|
-
iter_parse,
|
|
43
|
-
parse,
|
|
44
62
|
)
|
|
45
63
|
|
|
46
64
|
from .core import ( # noqa
|
|
@@ -52,6 +70,21 @@ from .errors import ( # noqa
|
|
|
52
70
|
AbnfGrammarParseError,
|
|
53
71
|
)
|
|
54
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
|
+
|
|
55
88
|
from .meta import ( # noqa
|
|
56
89
|
META_GRAMMAR_RULES,
|
|
57
90
|
META_GRAMMAR,
|
|
@@ -80,15 +113,13 @@ from .ops import ( # noqa
|
|
|
80
113
|
rule,
|
|
81
114
|
)
|
|
82
115
|
|
|
83
|
-
from .
|
|
84
|
-
|
|
116
|
+
from .parsing import ( # noqa
|
|
117
|
+
iter_parse,
|
|
118
|
+
parse,
|
|
85
119
|
)
|
|
86
120
|
|
|
87
121
|
from .utils import ( # noqa
|
|
88
|
-
strip_insignificant_match_rules,
|
|
89
122
|
only_match_rules,
|
|
90
123
|
|
|
91
|
-
parse_rules,
|
|
92
|
-
|
|
93
124
|
fix_ws,
|
|
94
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,109 +1,11 @@
|
|
|
1
1
|
import abc
|
|
2
|
-
import io
|
|
3
|
-
import itertools
|
|
4
2
|
import typing as ta
|
|
5
3
|
|
|
6
4
|
from omlish import check
|
|
7
5
|
from omlish import lang
|
|
8
6
|
|
|
9
|
-
from .errors import AbnfError
|
|
10
|
-
from .errors import AbnfIncompleteParseError
|
|
11
7
|
|
|
12
|
-
|
|
13
|
-
with lang.auto_proxy_import(globals()):
|
|
14
|
-
from . import internal
|
|
15
|
-
from . import ops
|
|
16
|
-
from . import parsing
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@ta.final
|
|
23
|
-
class Match(ta.NamedTuple):
|
|
24
|
-
op: 'Op'
|
|
25
|
-
start: int
|
|
26
|
-
end: int
|
|
27
|
-
children: tuple['Match', ...]
|
|
28
|
-
|
|
29
|
-
@property
|
|
30
|
-
def length(self) -> int:
|
|
31
|
-
return self.end - self.start
|
|
32
|
-
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
def __repr__(self) -> str:
|
|
36
|
-
return (
|
|
37
|
-
f'{self.__class__.__name__}('
|
|
38
|
-
f'{self.op._match_repr()}, ' # noqa
|
|
39
|
-
f'{self.start}, {self.end}'
|
|
40
|
-
f'{f", {self.children!r}" if self.children else ""})'
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
def render_to(
|
|
44
|
-
self,
|
|
45
|
-
write: ta.Callable[[str], ta.Any],
|
|
46
|
-
*,
|
|
47
|
-
indent: int | None = None,
|
|
48
|
-
_depth: int = 0,
|
|
49
|
-
) -> None:
|
|
50
|
-
ix: str | None = (' ' * (indent * _depth)) if indent is not None else None
|
|
51
|
-
if ix:
|
|
52
|
-
write(ix)
|
|
53
|
-
o = self.op
|
|
54
|
-
if isinstance(o, (ops.StringLiteral, ops.CaseInsensitiveStringLiteral)):
|
|
55
|
-
write(f'literal<{self.start}-{self.end}>({o.value!r})')
|
|
56
|
-
elif isinstance(o, ops.RangeLiteral):
|
|
57
|
-
write(f'literal<{self.start}-{self.end}>({o.value.lo!r}-{o.value.hi!r})')
|
|
58
|
-
elif isinstance(o, internal.Regex):
|
|
59
|
-
write(f'regex<{self.start}-{self.end}>({o.pat.pattern!r})')
|
|
60
|
-
else:
|
|
61
|
-
write(f'{o.__class__.__name__.lower()}<{self.start}-{self.end}>')
|
|
62
|
-
if isinstance(o, ops.RuleRef):
|
|
63
|
-
write(f':{o.name}')
|
|
64
|
-
if self.children:
|
|
65
|
-
write('(')
|
|
66
|
-
if ix is not None:
|
|
67
|
-
write('\n')
|
|
68
|
-
for i, c in enumerate(self.children):
|
|
69
|
-
if i and ix is None:
|
|
70
|
-
write(', ')
|
|
71
|
-
c.render_to(write, indent=indent, _depth=_depth + 1)
|
|
72
|
-
if ix is not None:
|
|
73
|
-
write(',\n')
|
|
74
|
-
if ix:
|
|
75
|
-
write(ix)
|
|
76
|
-
write(')')
|
|
77
|
-
|
|
78
|
-
def render(
|
|
79
|
-
self,
|
|
80
|
-
*,
|
|
81
|
-
indent: int | None = None,
|
|
82
|
-
) -> str:
|
|
83
|
-
sb = io.StringIO()
|
|
84
|
-
self.render_to(sb.write, indent=indent)
|
|
85
|
-
return sb.getvalue()
|
|
86
|
-
|
|
87
|
-
def __str__(self) -> str:
|
|
88
|
-
return self.render()
|
|
89
|
-
|
|
90
|
-
#
|
|
91
|
-
|
|
92
|
-
def map_children(self, fn: ta.Callable[['Match'], 'Match']) -> 'Match':
|
|
93
|
-
return self._replace(children=tuple(map(fn, self.children)))
|
|
94
|
-
|
|
95
|
-
def flat_map_children(self, fn: ta.Callable[['Match'], ta.Iterable['Match']]) -> 'Match':
|
|
96
|
-
return self._replace(children=tuple(itertools.chain.from_iterable(map(fn, self.children))))
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def longest_match(ms: ta.Iterable[Match]) -> Match | None:
|
|
100
|
-
bm: Match | None = None
|
|
101
|
-
bl = 0
|
|
102
|
-
for m in ms:
|
|
103
|
-
l = m.length
|
|
104
|
-
if bm is None or l > bl:
|
|
105
|
-
bm, bl = m, l
|
|
106
|
-
return bm
|
|
8
|
+
OpTuple: ta.TypeAlias = tuple['Op', ...]
|
|
107
9
|
|
|
108
10
|
|
|
109
11
|
##
|
|
@@ -127,7 +29,11 @@ class CompositeOp(Op, lang.Abstract):
|
|
|
127
29
|
|
|
128
30
|
@property
|
|
129
31
|
@abc.abstractmethod
|
|
130
|
-
def children(self) ->
|
|
32
|
+
def children(self) -> OpTuple:
|
|
33
|
+
raise NotImplementedError
|
|
34
|
+
|
|
35
|
+
@abc.abstractmethod
|
|
36
|
+
def replace_children(self, *children: Op) -> Op:
|
|
131
37
|
raise NotImplementedError
|
|
132
38
|
|
|
133
39
|
|
|
@@ -136,182 +42,3 @@ class LeafOp(Op, lang.Abstract):
|
|
|
136
42
|
super().__init_subclass__(**kwargs)
|
|
137
43
|
|
|
138
44
|
check.not_issubclass(cls, CompositeOp)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
##
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
class Rule(lang.Final):
|
|
145
|
-
def __init__(
|
|
146
|
-
self,
|
|
147
|
-
name: str,
|
|
148
|
-
op: Op,
|
|
149
|
-
*,
|
|
150
|
-
insignificant: bool = False,
|
|
151
|
-
) -> None:
|
|
152
|
-
super().__init__()
|
|
153
|
-
|
|
154
|
-
self._name = check.non_empty_str(name)
|
|
155
|
-
self._op = check.isinstance(op, Op)
|
|
156
|
-
self._insignificant = insignificant
|
|
157
|
-
|
|
158
|
-
self._name_f = name.casefold()
|
|
159
|
-
|
|
160
|
-
def __repr__(self) -> str:
|
|
161
|
-
return f'{self.__class__.__name__}({self._name!r})'
|
|
162
|
-
|
|
163
|
-
def replace_op(self, op: Op) -> 'Rule':
|
|
164
|
-
return Rule(
|
|
165
|
-
self._name,
|
|
166
|
-
op,
|
|
167
|
-
insignificant=self._insignificant,
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
@property
|
|
171
|
-
def name(self) -> str:
|
|
172
|
-
return self._name
|
|
173
|
-
|
|
174
|
-
@property
|
|
175
|
-
def name_f(self) -> str:
|
|
176
|
-
return self._name_f
|
|
177
|
-
|
|
178
|
-
@property
|
|
179
|
-
def op(self) -> Op:
|
|
180
|
-
return self._op
|
|
181
|
-
|
|
182
|
-
@property
|
|
183
|
-
def insignificant(self) -> bool:
|
|
184
|
-
return self._insignificant
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
class Grammar(lang.Final):
|
|
188
|
-
def __init__(
|
|
189
|
-
self,
|
|
190
|
-
*rules: Rule,
|
|
191
|
-
root: Rule | str | None = None,
|
|
192
|
-
) -> None:
|
|
193
|
-
super().__init__()
|
|
194
|
-
|
|
195
|
-
rules_set: set[Rule] = set()
|
|
196
|
-
rules_by_name: dict[str, Rule] = {}
|
|
197
|
-
rules_by_name_f: dict[str, Rule] = {}
|
|
198
|
-
rules_by_op: dict[Op, Rule] = {}
|
|
199
|
-
for gr in rules:
|
|
200
|
-
check.isinstance(gr, Rule)
|
|
201
|
-
check.not_in(gr, rules_set)
|
|
202
|
-
check.not_in(gr._name, rules_by_name) # noqa
|
|
203
|
-
check.not_in(gr._name_f, rules_by_name_f) # noqa
|
|
204
|
-
check.not_in(gr._op, rules_by_op) # noqa
|
|
205
|
-
rules_set.add(gr)
|
|
206
|
-
rules_by_name[gr._name] = gr # noqa
|
|
207
|
-
rules_by_name_f[gr._name_f] = gr # noqa
|
|
208
|
-
rules_by_op[gr._op] = gr # noqa
|
|
209
|
-
self._rules = rules_set
|
|
210
|
-
self._rules_by_name: ta.Mapping[str, Rule] = rules_by_name
|
|
211
|
-
self._rules_by_name_f: ta.Mapping[str, Rule] = rules_by_name_f
|
|
212
|
-
self._rules_by_op: ta.Mapping[Op, Rule] = rules_by_op
|
|
213
|
-
|
|
214
|
-
if isinstance(root, str):
|
|
215
|
-
root = rules_by_name_f[root.casefold()]
|
|
216
|
-
self._root = root
|
|
217
|
-
|
|
218
|
-
@property
|
|
219
|
-
def root(self) -> Rule | None:
|
|
220
|
-
return self._root
|
|
221
|
-
|
|
222
|
-
def rule(self, name: str) -> Rule | None:
|
|
223
|
-
return self._rules_by_name_f.get(name.casefold())
|
|
224
|
-
|
|
225
|
-
def iter_parse(
|
|
226
|
-
self,
|
|
227
|
-
source: str,
|
|
228
|
-
root: Rule | str | None = None,
|
|
229
|
-
*,
|
|
230
|
-
start: int = 0,
|
|
231
|
-
debug: int = 0,
|
|
232
|
-
**kwargs: ta.Any,
|
|
233
|
-
) -> ta.Iterator[Match]:
|
|
234
|
-
if root is None:
|
|
235
|
-
if (root := self._root) is None:
|
|
236
|
-
raise AbnfError('No root or default root specified')
|
|
237
|
-
else:
|
|
238
|
-
if isinstance(root, str):
|
|
239
|
-
root = self._rules_by_name_f[root.casefold()]
|
|
240
|
-
else:
|
|
241
|
-
root = check.in_(check.isinstance(root, Rule), self._rules)
|
|
242
|
-
|
|
243
|
-
return parsing._iter_parse( # noqa
|
|
244
|
-
self,
|
|
245
|
-
source,
|
|
246
|
-
root._op, # noqa
|
|
247
|
-
start,
|
|
248
|
-
debug=debug,
|
|
249
|
-
**kwargs,
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
def parse(
|
|
253
|
-
self,
|
|
254
|
-
source: str,
|
|
255
|
-
root: str | None = None,
|
|
256
|
-
*,
|
|
257
|
-
start: int = 0,
|
|
258
|
-
complete: bool = False,
|
|
259
|
-
debug: int = 0,
|
|
260
|
-
**kwargs: ta.Any,
|
|
261
|
-
) -> Match | None:
|
|
262
|
-
if (match := longest_match(self.iter_parse(
|
|
263
|
-
source,
|
|
264
|
-
root,
|
|
265
|
-
start=start,
|
|
266
|
-
debug=debug,
|
|
267
|
-
**kwargs,
|
|
268
|
-
))) is None:
|
|
269
|
-
return None
|
|
270
|
-
|
|
271
|
-
if complete and (match.start, match.end) != (start, len(source)):
|
|
272
|
-
raise AbnfIncompleteParseError
|
|
273
|
-
|
|
274
|
-
return match
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
##
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
def iter_parse(
|
|
281
|
-
obj: Grammar | Rule | Op,
|
|
282
|
-
src: str,
|
|
283
|
-
*,
|
|
284
|
-
root: str | None = None,
|
|
285
|
-
start: int = 0,
|
|
286
|
-
) -> ta.Iterator[Match]:
|
|
287
|
-
if isinstance(obj, Grammar):
|
|
288
|
-
gram = obj
|
|
289
|
-
elif isinstance(obj, Rule):
|
|
290
|
-
check.none(root)
|
|
291
|
-
gram = Grammar(obj, root=obj)
|
|
292
|
-
elif isinstance(obj, Op):
|
|
293
|
-
check.none(root)
|
|
294
|
-
gram = Grammar(Rule('root', obj), root='root')
|
|
295
|
-
else:
|
|
296
|
-
raise TypeError(obj)
|
|
297
|
-
|
|
298
|
-
return gram.iter_parse(
|
|
299
|
-
src,
|
|
300
|
-
root,
|
|
301
|
-
start=start,
|
|
302
|
-
)
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
def parse(
|
|
306
|
-
obj: Grammar | Rule | Op,
|
|
307
|
-
src: str,
|
|
308
|
-
*,
|
|
309
|
-
root: str | None = None,
|
|
310
|
-
start: int = 0,
|
|
311
|
-
) -> Match | None:
|
|
312
|
-
return longest_match(iter_parse(
|
|
313
|
-
obj,
|
|
314
|
-
src,
|
|
315
|
-
root=root,
|
|
316
|
-
start=start,
|
|
317
|
-
))
|