omextra 0.0.0.dev494__py3-none-any.whl → 0.0.0.dev496__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.
@@ -1,343 +0,0 @@
1
- import typing as ta
2
-
3
- from omlish import check
4
- from omlish import dataclasses as dc
5
- from omlish import lang
6
-
7
- from .base import Match
8
- from .base import Parser
9
- from .base import _Context
10
-
11
-
12
- ##
13
-
14
-
15
- class Literal(Parser, lang.Abstract):
16
- def _match_repr(self) -> str:
17
- return repr(self)
18
-
19
-
20
- class StringLiteral(Literal):
21
- def __init__(self, value: str) -> None:
22
- super().__init__()
23
-
24
- self._value = check.non_empty_str(value)
25
-
26
- @property
27
- def value(self) -> str:
28
- return self._value
29
-
30
- def __repr__(self) -> str:
31
- return f'{self.__class__.__name__}@{id(self):x}({self._value!r})'
32
-
33
- def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
34
- if start < len(ctx._source): # noqa
35
- source = ctx._source[start : start + len(self._value)] # noqa
36
- if source == self._value:
37
- yield Match(self, start, start + len(source), ())
38
-
39
-
40
- class CaseInsensitiveStringLiteral(Literal):
41
- def __init__(self, value: str) -> None:
42
- super().__init__()
43
-
44
- self._value = check.non_empty_str(value).casefold()
45
-
46
- @property
47
- def value(self) -> str:
48
- return self._value
49
-
50
- def __repr__(self) -> str:
51
- return f'{self.__class__.__name__}@{id(self):x}({self._value!r})'
52
-
53
- def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
54
- if start < len(ctx._source): # noqa
55
- source = ctx._source[start : start + len(self._value)].casefold() # noqa
56
- if source == self._value:
57
- yield Match(self, start, start + len(source), ())
58
-
59
-
60
- class RangeLiteral(Literal):
61
- @dc.dataclass(frozen=True)
62
- class Range:
63
- lo: str
64
- hi: str
65
-
66
- def __post_init__(self) -> None:
67
- check.non_empty_str(self.lo)
68
- check.non_empty_str(self.hi)
69
- check.state(self.hi >= self.lo)
70
-
71
- def __init__(self, value: Range) -> None:
72
- super().__init__()
73
-
74
- self._value = check.isinstance(value, RangeLiteral.Range)
75
-
76
- @property
77
- def value(self) -> Range:
78
- return self._value
79
-
80
- def __repr__(self) -> str:
81
- return f'{self.__class__.__name__}@{id(self):x}({self._value!r})'
82
-
83
- def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
84
- try:
85
- source = ctx._source[start] # noqa
86
- except IndexError:
87
- return
88
- # ranges are always case-sensitive
89
- if (value := self._value).lo <= source <= value.hi:
90
- yield Match(self, start, start + 1, ())
91
-
92
-
93
- @ta.overload
94
- def literal(s: str, *, case_sensitive: bool = False) -> StringLiteral:
95
- ...
96
-
97
-
98
- @ta.overload
99
- def literal(lo: str, hi: str) -> RangeLiteral:
100
- ...
101
-
102
-
103
- def literal(*args, case_sensitive=None):
104
- if not args:
105
- raise TypeError
106
- elif len(args) == 1:
107
- s = check.isinstance(check.single(args), str)
108
- if case_sensitive:
109
- return StringLiteral(s)
110
- else:
111
- return CaseInsensitiveStringLiteral(s)
112
- elif len(args) == 2:
113
- check.none(case_sensitive)
114
- return RangeLiteral(RangeLiteral.Range(*map(check.of_isinstance(str), args)))
115
- else:
116
- raise TypeError(args)
117
-
118
-
119
- ##
120
-
121
-
122
- class Concat(Parser):
123
- def __init__(self, *children: Parser) -> None:
124
- super().__init__()
125
-
126
- for c in check.not_empty(children):
127
- check.isinstance(c, Parser)
128
- self._children = children
129
-
130
- @property
131
- def children(self) -> ta.Sequence[Parser]:
132
- return self._children
133
-
134
- def __repr__(self) -> str:
135
- return f'{self.__class__.__name__}@{id(self):x}({", ".join(map(repr, self._children))})'
136
-
137
- def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
138
- i = 0
139
- match_tups: list[tuple[Match, ...]] = [()]
140
- for cp in self._children:
141
- next_match_tups: list[tuple[Match, ...]] = []
142
- for mt in match_tups:
143
- for cm in ctx.iter_parse(cp, mt[-1].end if mt else start):
144
- next_match_tups.append((*mt, cm))
145
- i += 1
146
- if not next_match_tups:
147
- return
148
- match_tups = next_match_tups
149
- if not i:
150
- return
151
- for mt in sorted(match_tups, key=len, reverse=True):
152
- yield Match(self, start, mt[-1].end if mt else start, mt)
153
-
154
-
155
- concat = Concat
156
-
157
-
158
- ##
159
-
160
-
161
- class Repeat(Parser):
162
- @dc.dataclass(frozen=True)
163
- class Times:
164
- min: int = 0
165
- max: int | None = None
166
-
167
- def __post_init__(self) -> None:
168
- if self.max is not None:
169
- check.state(self.max >= self.min)
170
-
171
- def __repr__(self) -> str:
172
- return f'{self.__class__.__name__}({self.min}{f", {self.max!r}" if self.max is not None else ""})'
173
-
174
- def __init__(self, times: Times, child: Parser) -> None:
175
- super().__init__()
176
-
177
- self._times = check.isinstance(times, Repeat.Times)
178
- self._child = check.isinstance(child, Parser)
179
-
180
- @property
181
- def times(self) -> Times:
182
- return self._times
183
-
184
- @property
185
- def child(self) -> Parser:
186
- return self._child
187
-
188
- def __repr__(self) -> str:
189
- return f'{self.__class__.__name__}@{id(self):x}({self._times}, {self._child!r})'
190
-
191
- def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
192
- match_tup_set: set[tuple[Match, ...]] = set()
193
- last_match_tup_set: set[tuple[Match, ...]] = {()}
194
- i = 0
195
- while True:
196
- if self._times.max is not None and i == self._times.max:
197
- break
198
- next_match_tup_set: set[tuple[Match, ...]] = set()
199
- for mt in last_match_tup_set:
200
- for cm in ctx.iter_parse(self._child, mt[-1].end if mt else start):
201
- next_match_tup_set.add((*mt, cm))
202
- if not next_match_tup_set or next_match_tup_set < match_tup_set:
203
- break
204
- i += 1
205
- match_tup_set |= next_match_tup_set
206
- last_match_tup_set = next_match_tup_set
207
- if i < self._times.min:
208
- return
209
- for mt in sorted(match_tup_set or [()], key=len, reverse=True):
210
- yield Match(self, start, mt[-1].end if mt else start, mt) # noqa
211
-
212
-
213
- class Option(Repeat):
214
- def __init__(self, child: Parser) -> None:
215
- super().__init__(Repeat.Times(0, 1), child)
216
-
217
- def __repr__(self) -> str:
218
- return f'{self.__class__.__name__}@{id(self):x}({self._child!r})'
219
-
220
-
221
- option = Option
222
-
223
-
224
- @ta.overload
225
- def repeat(child: Parser) -> Repeat: # noqa
226
- ...
227
-
228
-
229
- @ta.overload
230
- def repeat(times: Repeat.Times, child: Parser) -> Repeat: # noqa
231
- ...
232
-
233
-
234
- @ta.overload
235
- def repeat(min: int, child: Parser) -> Repeat: # noqa
236
- ...
237
-
238
-
239
- @ta.overload
240
- def repeat(min: int, max: int | None, child: Parser) -> Repeat: # noqa
241
- ...
242
-
243
-
244
- def repeat(*args):
245
- min: int # noqa
246
- max: int | None # noqa
247
-
248
- if len(args) < 2:
249
- [child] = args
250
- min, max = 0, None # noqa
251
-
252
- elif len(args) > 2:
253
- min, max, child = args # noqa
254
-
255
- else:
256
- ti, child = args # noqa
257
-
258
- if isinstance(ti, Repeat.Times):
259
- min, max = ti.min, ti.max # noqa
260
-
261
- else:
262
- min, max = ti, None # noqa
263
-
264
- if (min, max) == (0, 1):
265
- return Option(check.isinstance(child, Parser))
266
-
267
- else:
268
- return Repeat(
269
- Repeat.Times(
270
- check.isinstance(min, int),
271
- check.isinstance(max, (int, None)),
272
- ),
273
- check.isinstance(child, Parser),
274
- )
275
-
276
-
277
- ##
278
-
279
-
280
- class Either(Parser):
281
- def __init__(self, *children: Parser, first_match: bool = False) -> None:
282
- super().__init__()
283
-
284
- for c in check.not_empty(children):
285
- check.isinstance(c, Parser)
286
- self._children = children
287
- self._first_match = first_match
288
-
289
- @property
290
- def children(self) -> ta.Sequence[Parser]:
291
- return self._children
292
-
293
- @property
294
- def first_match(self) -> bool:
295
- return self._first_match
296
-
297
- def __repr__(self) -> str:
298
- return (
299
- f'{self.__class__.__name__}@{id(self):x}('
300
- f'{", ".join(map(repr, self._children))}'
301
- f'{", first_match=True" if self._first_match else ""})'
302
- )
303
-
304
- def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
305
- for cp in self._children:
306
- found = False
307
- for cm in ctx.iter_parse(cp, start):
308
- found = True
309
- yield Match(self, start, cm.end, (cm,))
310
- if found and self._first_match:
311
- return
312
-
313
-
314
- either = Either
315
-
316
-
317
- ##
318
-
319
-
320
- class RuleRef(Parser):
321
- def __init__(self, name: str) -> None:
322
- super().__init__()
323
-
324
- self._name = check.non_empty_str(name)
325
- self._name_f = name.casefold()
326
-
327
- @property
328
- def name(self) -> str:
329
- return self._name
330
-
331
- def __repr__(self) -> str:
332
- return f'{self.__class__.__name__}@{id(self):x}({self._name!r})'
333
-
334
- def _match_repr(self) -> str:
335
- return repr(self)
336
-
337
- def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
338
- cp = ctx._grammar._rules_by_name_f[self._name_f].parser # noqa
339
- for cm in ctx.iter_parse(cp, start):
340
- yield Match(self, cm.start, cm.end, (cm,))
341
-
342
-
343
- rule = RuleRef