omextra 0.0.0.dev424__py3-none-any.whl → 0.0.0.dev426__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.
Files changed (68) hide show
  1. omextra/.omlish-manifests.json +14 -0
  2. omextra/__about__.py +3 -1
  3. omextra/defs.py +216 -0
  4. omextra/dynamic.py +219 -0
  5. omextra/formats/__init__.py +0 -0
  6. omextra/formats/json/Json.g4 +77 -0
  7. omextra/formats/json/__init__.py +0 -0
  8. omextra/formats/json/_antlr/JsonLexer.py +109 -0
  9. omextra/formats/json/_antlr/JsonListener.py +61 -0
  10. omextra/formats/json/_antlr/JsonParser.py +457 -0
  11. omextra/formats/json/_antlr/JsonVisitor.py +42 -0
  12. omextra/formats/json/_antlr/__init__.py +0 -0
  13. omextra/io/__init__.py +0 -0
  14. omextra/io/trampoline.py +289 -0
  15. omextra/specs/__init__.py +0 -0
  16. omextra/specs/irc/__init__.py +0 -0
  17. omextra/specs/irc/messages/__init__.py +0 -0
  18. omextra/specs/irc/messages/base.py +50 -0
  19. omextra/specs/irc/messages/formats.py +92 -0
  20. omextra/specs/irc/messages/messages.py +775 -0
  21. omextra/specs/irc/messages/parsing.py +99 -0
  22. omextra/specs/irc/numerics/__init__.py +0 -0
  23. omextra/specs/irc/numerics/formats.py +97 -0
  24. omextra/specs/irc/numerics/numerics.py +865 -0
  25. omextra/specs/irc/numerics/types.py +59 -0
  26. omextra/specs/irc/protocol/LICENSE +11 -0
  27. omextra/specs/irc/protocol/__init__.py +61 -0
  28. omextra/specs/irc/protocol/consts.py +6 -0
  29. omextra/specs/irc/protocol/errors.py +30 -0
  30. omextra/specs/irc/protocol/message.py +21 -0
  31. omextra/specs/irc/protocol/nuh.py +55 -0
  32. omextra/specs/irc/protocol/parsing.py +158 -0
  33. omextra/specs/irc/protocol/rendering.py +153 -0
  34. omextra/specs/irc/protocol/tags.py +102 -0
  35. omextra/specs/irc/protocol/utils.py +30 -0
  36. omextra/specs/proto/Protobuf3.g4 +396 -0
  37. omextra/specs/proto/__init__.py +0 -0
  38. omextra/specs/proto/_antlr/Protobuf3Lexer.py +340 -0
  39. omextra/specs/proto/_antlr/Protobuf3Listener.py +448 -0
  40. omextra/specs/proto/_antlr/Protobuf3Parser.py +3909 -0
  41. omextra/specs/proto/_antlr/Protobuf3Visitor.py +257 -0
  42. omextra/specs/proto/_antlr/__init__.py +0 -0
  43. omextra/specs/proto/nodes.py +54 -0
  44. omextra/specs/proto/parsing.py +98 -0
  45. omextra/sql/__init__.py +0 -0
  46. omextra/sql/parsing/Minisql.g4 +292 -0
  47. omextra/sql/parsing/__init__.py +0 -0
  48. omextra/sql/parsing/_antlr/MinisqlLexer.py +322 -0
  49. omextra/sql/parsing/_antlr/MinisqlListener.py +511 -0
  50. omextra/sql/parsing/_antlr/MinisqlParser.py +3763 -0
  51. omextra/sql/parsing/_antlr/MinisqlVisitor.py +292 -0
  52. omextra/sql/parsing/_antlr/__init__.py +0 -0
  53. omextra/sql/parsing/parsing.py +120 -0
  54. omextra/text/__init__.py +0 -0
  55. omextra/text/antlr/__init__.py +0 -0
  56. omextra/text/antlr/cli/__init__.py +0 -0
  57. omextra/text/antlr/cli/__main__.py +11 -0
  58. omextra/text/antlr/cli/cli.py +62 -0
  59. omextra/text/antlr/cli/consts.py +7 -0
  60. omextra/text/antlr/cli/gen.py +193 -0
  61. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/METADATA +2 -3
  62. omextra-0.0.0.dev426.dist-info/RECORD +67 -0
  63. omextra/.manifests.json +0 -1
  64. omextra-0.0.0.dev424.dist-info/RECORD +0 -9
  65. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/WHEEL +0 -0
  66. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/entry_points.txt +0 -0
  67. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/licenses/LICENSE +0 -0
  68. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,292 @@
1
+ # type: ignore
2
+ # ruff: noqa
3
+ # flake8: noqa
4
+ # @omlish-generated
5
+ # Generated from Minisql.g4 by ANTLR 4.13.2
6
+ from omlish.text.antlr._runtime._all import *
7
+ if "." in __name__:
8
+ from .MinisqlParser import MinisqlParser
9
+ else:
10
+ from MinisqlParser import MinisqlParser
11
+
12
+ # This class defines a complete generic visitor for a parse tree produced by MinisqlParser.
13
+
14
+ class MinisqlVisitor(ParseTreeVisitor):
15
+
16
+ # Visit a parse tree produced by MinisqlParser#singleStmt.
17
+ def visitSingleStmt(self, ctx:MinisqlParser.SingleStmtContext):
18
+ return self.visitChildren(ctx)
19
+
20
+
21
+ # Visit a parse tree produced by MinisqlParser#select.
22
+ def visitSelect(self, ctx:MinisqlParser.SelectContext):
23
+ return self.visitChildren(ctx)
24
+
25
+
26
+ # Visit a parse tree produced by MinisqlParser#cteSelect.
27
+ def visitCteSelect(self, ctx:MinisqlParser.CteSelectContext):
28
+ return self.visitChildren(ctx)
29
+
30
+
31
+ # Visit a parse tree produced by MinisqlParser#cte.
32
+ def visitCte(self, ctx:MinisqlParser.CteContext):
33
+ return self.visitChildren(ctx)
34
+
35
+
36
+ # Visit a parse tree produced by MinisqlParser#unionSelect.
37
+ def visitUnionSelect(self, ctx:MinisqlParser.UnionSelectContext):
38
+ return self.visitChildren(ctx)
39
+
40
+
41
+ # Visit a parse tree produced by MinisqlParser#unionItem.
42
+ def visitUnionItem(self, ctx:MinisqlParser.UnionItemContext):
43
+ return self.visitChildren(ctx)
44
+
45
+
46
+ # Visit a parse tree produced by MinisqlParser#primarySelect.
47
+ def visitPrimarySelect(self, ctx:MinisqlParser.PrimarySelectContext):
48
+ return self.visitChildren(ctx)
49
+
50
+
51
+ # Visit a parse tree produced by MinisqlParser#allSelectItem.
52
+ def visitAllSelectItem(self, ctx:MinisqlParser.AllSelectItemContext):
53
+ return self.visitChildren(ctx)
54
+
55
+
56
+ # Visit a parse tree produced by MinisqlParser#exprSelectItem.
57
+ def visitExprSelectItem(self, ctx:MinisqlParser.ExprSelectItemContext):
58
+ return self.visitChildren(ctx)
59
+
60
+
61
+ # Visit a parse tree produced by MinisqlParser#expr.
62
+ def visitExpr(self, ctx:MinisqlParser.ExprContext):
63
+ return self.visitChildren(ctx)
64
+
65
+
66
+ # Visit a parse tree produced by MinisqlParser#unaryBooleanExpr.
67
+ def visitUnaryBooleanExpr(self, ctx:MinisqlParser.UnaryBooleanExprContext):
68
+ return self.visitChildren(ctx)
69
+
70
+
71
+ # Visit a parse tree produced by MinisqlParser#predicatedBooleanExpr.
72
+ def visitPredicatedBooleanExpr(self, ctx:MinisqlParser.PredicatedBooleanExprContext):
73
+ return self.visitChildren(ctx)
74
+
75
+
76
+ # Visit a parse tree produced by MinisqlParser#binaryBooleanExpr.
77
+ def visitBinaryBooleanExpr(self, ctx:MinisqlParser.BinaryBooleanExprContext):
78
+ return self.visitChildren(ctx)
79
+
80
+
81
+ # Visit a parse tree produced by MinisqlParser#castBooleanExpr.
82
+ def visitCastBooleanExpr(self, ctx:MinisqlParser.CastBooleanExprContext):
83
+ return self.visitChildren(ctx)
84
+
85
+
86
+ # Visit a parse tree produced by MinisqlParser#cmpPredicate.
87
+ def visitCmpPredicate(self, ctx:MinisqlParser.CmpPredicateContext):
88
+ return self.visitChildren(ctx)
89
+
90
+
91
+ # Visit a parse tree produced by MinisqlParser#isNullPredicate.
92
+ def visitIsNullPredicate(self, ctx:MinisqlParser.IsNullPredicateContext):
93
+ return self.visitChildren(ctx)
94
+
95
+
96
+ # Visit a parse tree produced by MinisqlParser#inListPredicate.
97
+ def visitInListPredicate(self, ctx:MinisqlParser.InListPredicateContext):
98
+ return self.visitChildren(ctx)
99
+
100
+
101
+ # Visit a parse tree produced by MinisqlParser#inSelectPredicate.
102
+ def visitInSelectPredicate(self, ctx:MinisqlParser.InSelectPredicateContext):
103
+ return self.visitChildren(ctx)
104
+
105
+
106
+ # Visit a parse tree produced by MinisqlParser#likePredicate.
107
+ def visitLikePredicate(self, ctx:MinisqlParser.LikePredicateContext):
108
+ return self.visitChildren(ctx)
109
+
110
+
111
+ # Visit a parse tree produced by MinisqlParser#arithValueExpr.
112
+ def visitArithValueExpr(self, ctx:MinisqlParser.ArithValueExprContext):
113
+ return self.visitChildren(ctx)
114
+
115
+
116
+ # Visit a parse tree produced by MinisqlParser#unaryValueExpr.
117
+ def visitUnaryValueExpr(self, ctx:MinisqlParser.UnaryValueExprContext):
118
+ return self.visitChildren(ctx)
119
+
120
+
121
+ # Visit a parse tree produced by MinisqlParser#primaryValueExpr.
122
+ def visitPrimaryValueExpr(self, ctx:MinisqlParser.PrimaryValueExprContext):
123
+ return self.visitChildren(ctx)
124
+
125
+
126
+ # Visit a parse tree produced by MinisqlParser#functionCallExpr.
127
+ def visitFunctionCallExpr(self, ctx:MinisqlParser.FunctionCallExprContext):
128
+ return self.visitChildren(ctx)
129
+
130
+
131
+ # Visit a parse tree produced by MinisqlParser#starFunctionCallExpr.
132
+ def visitStarFunctionCallExpr(self, ctx:MinisqlParser.StarFunctionCallExprContext):
133
+ return self.visitChildren(ctx)
134
+
135
+
136
+ # Visit a parse tree produced by MinisqlParser#caseExpr.
137
+ def visitCaseExpr(self, ctx:MinisqlParser.CaseExprContext):
138
+ return self.visitChildren(ctx)
139
+
140
+
141
+ # Visit a parse tree produced by MinisqlParser#selectExpr.
142
+ def visitSelectExpr(self, ctx:MinisqlParser.SelectExprContext):
143
+ return self.visitChildren(ctx)
144
+
145
+
146
+ # Visit a parse tree produced by MinisqlParser#parenExpr.
147
+ def visitParenExpr(self, ctx:MinisqlParser.ParenExprContext):
148
+ return self.visitChildren(ctx)
149
+
150
+
151
+ # Visit a parse tree produced by MinisqlParser#simplePrimaryExpr.
152
+ def visitSimplePrimaryExpr(self, ctx:MinisqlParser.SimplePrimaryExprContext):
153
+ return self.visitChildren(ctx)
154
+
155
+
156
+ # Visit a parse tree produced by MinisqlParser#simpleExpr.
157
+ def visitSimpleExpr(self, ctx:MinisqlParser.SimpleExprContext):
158
+ return self.visitChildren(ctx)
159
+
160
+
161
+ # Visit a parse tree produced by MinisqlParser#caseItem.
162
+ def visitCaseItem(self, ctx:MinisqlParser.CaseItemContext):
163
+ return self.visitChildren(ctx)
164
+
165
+
166
+ # Visit a parse tree produced by MinisqlParser#over.
167
+ def visitOver(self, ctx:MinisqlParser.OverContext):
168
+ return self.visitChildren(ctx)
169
+
170
+
171
+ # Visit a parse tree produced by MinisqlParser#sortItem.
172
+ def visitSortItem(self, ctx:MinisqlParser.SortItemContext):
173
+ return self.visitChildren(ctx)
174
+
175
+
176
+ # Visit a parse tree produced by MinisqlParser#aliasedRelation.
177
+ def visitAliasedRelation(self, ctx:MinisqlParser.AliasedRelationContext):
178
+ return self.visitChildren(ctx)
179
+
180
+
181
+ # Visit a parse tree produced by MinisqlParser#joinRelation.
182
+ def visitJoinRelation(self, ctx:MinisqlParser.JoinRelationContext):
183
+ return self.visitChildren(ctx)
184
+
185
+
186
+ # Visit a parse tree produced by MinisqlParser#selectRelation.
187
+ def visitSelectRelation(self, ctx:MinisqlParser.SelectRelationContext):
188
+ return self.visitChildren(ctx)
189
+
190
+
191
+ # Visit a parse tree produced by MinisqlParser#tableRelation.
192
+ def visitTableRelation(self, ctx:MinisqlParser.TableRelationContext):
193
+ return self.visitChildren(ctx)
194
+
195
+
196
+ # Visit a parse tree produced by MinisqlParser#parenRelation.
197
+ def visitParenRelation(self, ctx:MinisqlParser.ParenRelationContext):
198
+ return self.visitChildren(ctx)
199
+
200
+
201
+ # Visit a parse tree produced by MinisqlParser#groupBy.
202
+ def visitGroupBy(self, ctx:MinisqlParser.GroupByContext):
203
+ return self.visitChildren(ctx)
204
+
205
+
206
+ # Visit a parse tree produced by MinisqlParser#qualifiedName.
207
+ def visitQualifiedName(self, ctx:MinisqlParser.QualifiedNameContext):
208
+ return self.visitChildren(ctx)
209
+
210
+
211
+ # Visit a parse tree produced by MinisqlParser#identList.
212
+ def visitIdentList(self, ctx:MinisqlParser.IdentListContext):
213
+ return self.visitChildren(ctx)
214
+
215
+
216
+ # Visit a parse tree produced by MinisqlParser#ident.
217
+ def visitIdent(self, ctx:MinisqlParser.IdentContext):
218
+ return self.visitChildren(ctx)
219
+
220
+
221
+ # Visit a parse tree produced by MinisqlParser#quotedIdent.
222
+ def visitQuotedIdent(self, ctx:MinisqlParser.QuotedIdentContext):
223
+ return self.visitChildren(ctx)
224
+
225
+
226
+ # Visit a parse tree produced by MinisqlParser#integerNumber.
227
+ def visitIntegerNumber(self, ctx:MinisqlParser.IntegerNumberContext):
228
+ return self.visitChildren(ctx)
229
+
230
+
231
+ # Visit a parse tree produced by MinisqlParser#decimalNumber.
232
+ def visitDecimalNumber(self, ctx:MinisqlParser.DecimalNumberContext):
233
+ return self.visitChildren(ctx)
234
+
235
+
236
+ # Visit a parse tree produced by MinisqlParser#floatNumber.
237
+ def visitFloatNumber(self, ctx:MinisqlParser.FloatNumberContext):
238
+ return self.visitChildren(ctx)
239
+
240
+
241
+ # Visit a parse tree produced by MinisqlParser#string.
242
+ def visitString(self, ctx:MinisqlParser.StringContext):
243
+ return self.visitChildren(ctx)
244
+
245
+
246
+ # Visit a parse tree produced by MinisqlParser#null.
247
+ def visitNull(self, ctx:MinisqlParser.NullContext):
248
+ return self.visitChildren(ctx)
249
+
250
+
251
+ # Visit a parse tree produced by MinisqlParser#true.
252
+ def visitTrue(self, ctx:MinisqlParser.TrueContext):
253
+ return self.visitChildren(ctx)
254
+
255
+
256
+ # Visit a parse tree produced by MinisqlParser#false.
257
+ def visitFalse(self, ctx:MinisqlParser.FalseContext):
258
+ return self.visitChildren(ctx)
259
+
260
+
261
+ # Visit a parse tree produced by MinisqlParser#setQuantifier.
262
+ def visitSetQuantifier(self, ctx:MinisqlParser.SetQuantifierContext):
263
+ return self.visitChildren(ctx)
264
+
265
+
266
+ # Visit a parse tree produced by MinisqlParser#joinType.
267
+ def visitJoinType(self, ctx:MinisqlParser.JoinTypeContext):
268
+ return self.visitChildren(ctx)
269
+
270
+
271
+ # Visit a parse tree produced by MinisqlParser#cmpOp.
272
+ def visitCmpOp(self, ctx:MinisqlParser.CmpOpContext):
273
+ return self.visitChildren(ctx)
274
+
275
+
276
+ # Visit a parse tree produced by MinisqlParser#arithOp.
277
+ def visitArithOp(self, ctx:MinisqlParser.ArithOpContext):
278
+ return self.visitChildren(ctx)
279
+
280
+
281
+ # Visit a parse tree produced by MinisqlParser#unaryOp.
282
+ def visitUnaryOp(self, ctx:MinisqlParser.UnaryOpContext):
283
+ return self.visitChildren(ctx)
284
+
285
+
286
+ # Visit a parse tree produced by MinisqlParser#unquotedIdent.
287
+ def visitUnquotedIdent(self, ctx:MinisqlParser.UnquotedIdentContext):
288
+ return self.visitChildren(ctx)
289
+
290
+
291
+
292
+ del MinisqlParser
File without changes
@@ -0,0 +1,120 @@
1
+ # ruff: noqa: N802 N803
2
+ import typing as ta
3
+
4
+ from omlish import check
5
+ from omlish.sql import queries as no
6
+ from omlish.text.antlr import runtime as antlr4
7
+ from omlish.text.antlr.delimit import DelimitingLexer
8
+ from omlish.text.antlr.errors import SilentRaisingErrorListener
9
+
10
+ from ._antlr.MinisqlLexer import MinisqlLexer # type: ignore
11
+ from ._antlr.MinisqlParser import MinisqlParser # type: ignore
12
+ from ._antlr.MinisqlVisitor import MinisqlVisitor # type: ignore
13
+
14
+
15
+ ##
16
+
17
+
18
+ class _ParseVisitor(MinisqlVisitor):
19
+ def visit(self, ctx: antlr4.ParserRuleContext):
20
+ check.isinstance(ctx, antlr4.ParserRuleContext)
21
+ node = ctx.accept(self)
22
+ return node
23
+
24
+ def aggregateResult(self, aggregate, nextResult):
25
+ if aggregate is not None:
26
+ check.none(nextResult)
27
+ return aggregate
28
+ else:
29
+ check.none(aggregate)
30
+ return nextResult
31
+
32
+ #
33
+
34
+ def visitExprSelectItem(self, ctx: MinisqlParser.ExprSelectItemContext):
35
+ value = self.visit(ctx.expr())
36
+ label = self.visit(ctx.ident()) if ctx.ident() is not None else None
37
+ return no.ExprSelectItem(value, label)
38
+
39
+ def visitIntegerNumber(self, ctx: MinisqlParser.IntegerNumberContext):
40
+ return no.Literal(int(ctx.INTEGER_VALUE().getText()))
41
+
42
+ def visitPrimarySelect(self, ctx: MinisqlParser.PrimarySelectContext):
43
+ items = [self.visit(i) for i in ctx.selectItem()]
44
+ relations = [self.visit(r) for r in ctx.relation()]
45
+ where = self.visit(ctx.where) if ctx.where is not None else None
46
+ return no.Select(
47
+ items=items,
48
+ from_=check.single(relations) if relations else None,
49
+ where=where,
50
+ )
51
+
52
+ def visitQuotedIdent(self, ctx: MinisqlParser.QuotedIdentContext):
53
+ name = unquote(ctx.QUOTED_IDENT().getText(), '"')
54
+ return no.Ident(name)
55
+
56
+ def visitUnquotedIdent(self, ctx: MinisqlParser.UnquotedIdentContext):
57
+ return no.Ident(ctx.getText())
58
+
59
+
60
+ ##
61
+
62
+
63
+ def create_parser(buf: str) -> MinisqlParser:
64
+ lexer = MinisqlLexer(antlr4.InputStream(buf))
65
+ lexer.removeErrorListeners()
66
+ lexer.addErrorListener(SilentRaisingErrorListener())
67
+
68
+ stream = antlr4.CommonTokenStream(lexer)
69
+ stream.fill()
70
+
71
+ parser = MinisqlParser(stream)
72
+ parser.removeErrorListeners()
73
+ parser.addErrorListener(SilentRaisingErrorListener())
74
+
75
+ return parser
76
+
77
+
78
+ ##
79
+
80
+
81
+ def parse_stmt(buf: str, **kwargs) -> no.Stmt:
82
+ parser = create_parser(buf, **kwargs)
83
+ node = _ParseVisitor().visit(parser.singleStmt())
84
+ return check.isinstance(node, no.Stmt)
85
+
86
+
87
+ class _DelimitingLexer(DelimitingLexer, MinisqlLexer):
88
+ pass
89
+
90
+
91
+ def split_stmts(buf: str) -> ta.Sequence[str]:
92
+ lexer = _DelimitingLexer(
93
+ antlr4.InputStream(buf),
94
+ delimiter_token=MinisqlParser.DELIMITER,
95
+ delimiters=[';'],
96
+ )
97
+ lexer.removeErrorListeners()
98
+ lexer.addErrorListener(SilentRaisingErrorListener())
99
+
100
+ lst, part = lexer.split()
101
+ if part.strip():
102
+ raise ValueError(part)
103
+
104
+ return [s for s, _ in lst]
105
+
106
+
107
+ def parse_stmts(buf: str, **kwargs) -> ta.Sequence[no.Stmt]:
108
+ return [parse_stmt(sb, **kwargs) for sb in split_stmts(buf)]
109
+
110
+
111
+ ##
112
+
113
+
114
+ def quote(val: str, q: str) -> str:
115
+ return q + val.replace(q, q * 2) + q
116
+
117
+
118
+ def unquote(val: str, q: str) -> str:
119
+ check.arg(val.startswith(q) and val.endswith(q))
120
+ return val[1:-1].replace(q * 2, q)
File without changes
File without changes
File without changes
@@ -0,0 +1,11 @@
1
+ # @omlish-manifest
2
+ _CLI_MODULE = {'!omdev.cli.types.CliModule': {
3
+ 'name': 'antlr',
4
+ 'module': __name__,
5
+ }}
6
+
7
+
8
+ if __name__ == '__main__':
9
+ from .cli import _main # noqa
10
+
11
+ _main()
@@ -0,0 +1,62 @@
1
+ import logging
2
+ import re
3
+ import subprocess
4
+ import sys
5
+
6
+ from omlish.argparse import all as ap
7
+ from omlish.logs import all as logs
8
+
9
+ from .consts import ANTLR_RUNTIME_PACKAGE
10
+ from .gen import GenPy
11
+ from .gen import get_jar_path
12
+
13
+
14
+ log = logging.getLogger(__name__)
15
+
16
+
17
+ ##
18
+
19
+
20
+ class Cli(ap.Cli):
21
+ @ap.cmd()
22
+ def jar(self) -> None:
23
+ print(get_jar_path())
24
+
25
+ @ap.cmd()
26
+ def latest(self) -> None:
27
+ o, _ = subprocess.Popen(
28
+ [
29
+ sys.executable,
30
+ '-m', 'pip',
31
+ 'index', 'versions',
32
+ ANTLR_RUNTIME_PACKAGE,
33
+ ],
34
+ stdout=subprocess.PIPE,
35
+ ).communicate()
36
+ tl = o.decode().splitlines()[0]
37
+ m = re.fullmatch(rf'{ANTLR_RUNTIME_PACKAGE} \((?P<version>[^)]+)\)', tl)
38
+ if m is None:
39
+ raise ValueError(f'Failed to parse version: {tl}')
40
+ v = m.groupdict()['version']
41
+ print(v)
42
+
43
+ #
44
+
45
+ @ap.cmd(
46
+ ap.arg('roots', nargs='+'),
47
+ )
48
+ def gen(self) -> None:
49
+ gp = GenPy(
50
+ self.args.roots,
51
+ )
52
+ gp.run()
53
+
54
+
55
+ def _main() -> None:
56
+ logs.configure_standard_logging(logging.INFO)
57
+ cli = Cli()
58
+ cli()
59
+
60
+
61
+ if __name__ == '__main__':
62
+ _main()
@@ -0,0 +1,7 @@
1
+ ANTLR_VERSION = '4.13.2'
2
+ ANTLR_JAR_NAME = f'antlr-{ANTLR_VERSION}-complete.jar'
3
+ ANTLR_JAR_URL = f'https://www.antlr.org/download/{ANTLR_JAR_NAME}'
4
+ ANTLR_RUNTIME_PACKAGE = 'antlr4-python3-runtime'
5
+ ANTLR_GITHUB_REPO = 'antlr/antlr4'
6
+
7
+ ANTLR_RUNTIME_VENDOR = 'omlish.text.antlr._runtime._all'
@@ -0,0 +1,193 @@
1
+ """
2
+ TODO:
3
+ - mtime cmp
4
+ - parallelism
5
+ """
6
+ import logging
7
+ import os.path
8
+ import re
9
+ import shutil
10
+ import subprocess
11
+ import typing as ta
12
+
13
+ from omlish import check
14
+ from omlish import lang
15
+ from omlish.os.paths import is_path_in_dir
16
+
17
+ from .consts import ANTLR_JAR_URL
18
+ from .consts import ANTLR_RUNTIME_VENDOR
19
+
20
+
21
+ if ta.TYPE_CHECKING:
22
+ from omdev.cache import data as dcache
23
+ else:
24
+ dcache = lang.proxy_import('omdev.cache.data')
25
+
26
+
27
+ log = logging.getLogger(__name__)
28
+
29
+
30
+ ##
31
+
32
+
33
+ ANTLR_JAR_CACHE = dcache.UrlSpec(ANTLR_JAR_URL)
34
+
35
+
36
+ @lang.cached_function
37
+ def get_jar_path() -> str:
38
+ return dcache.default().get(ANTLR_JAR_CACHE)
39
+
40
+
41
+ ##
42
+
43
+
44
+ def _find_dirs(*base_paths: str, filter: ta.Callable[[str], bool] = lambda _: True) -> ta.Sequence[str]: # noqa
45
+ return sorted(
46
+ os.path.join(dp, dn)
47
+ for base_path in base_paths
48
+ for dp, dns, fns in os.walk(base_path)
49
+ for dn in dns
50
+ if filter(dn)
51
+ )
52
+
53
+
54
+ def _find_files(*base_paths: str, filter: ta.Callable[[str], bool] = lambda _: True) -> ta.Sequence[str]: # noqa
55
+ return sorted(
56
+ os.path.join(dp, fn)
57
+ for base_path in base_paths
58
+ for dp, dns, fns in os.walk(base_path)
59
+ for fn in fns
60
+ if filter(fn)
61
+ )
62
+
63
+
64
+ class GenPy:
65
+ def __init__(
66
+ self,
67
+ root_dirs: str, # noqa
68
+ *,
69
+ out_subdir: str = '_antlr',
70
+ runtime_import: str = ANTLR_RUNTIME_VENDOR,
71
+ jar_path: str | None = None,
72
+ # parallelism: int | None = None,
73
+ ) -> None:
74
+ super().__init__()
75
+
76
+ check.non_empty_str(out_subdir)
77
+ check.arg(not os.path.isabs(out_subdir) and '.' not in out_subdir and '/' not in out_subdir)
78
+
79
+ self._root_dirs = frozenset(check.non_empty_str(rd) for rd in check.not_isinstance(root_dirs, str))
80
+ self._out_subdir = out_subdir
81
+ self._runtime_import = runtime_import
82
+ self._given_jar_path = jar_path
83
+
84
+ #
85
+
86
+ def _rmtree(self, tgt: str) -> None: # noqa
87
+ if not any(is_path_in_dir(rd, tgt) for rd in self._root_dirs):
88
+ raise RuntimeError(f'Refusing to delete {tgt!r} outside of {self._root_dirs!r}')
89
+ shutil.rmtree(tgt)
90
+
91
+ #
92
+
93
+ @lang.cached_function
94
+ def jar_path(self) -> str:
95
+ if (gjp := self._given_jar_path) is not None:
96
+ return gjp
97
+ return get_jar_path()
98
+
99
+ #
100
+
101
+ def process_g4(self, g4_file: str) -> None:
102
+ ap = os.path.abspath(g4_file)
103
+ check.state(os.path.isfile(ap))
104
+
105
+ od = os.path.join(os.path.dirname(ap), self._out_subdir)
106
+ os.makedirs(od, exist_ok=True)
107
+
108
+ log.info('Compiling grammar %s', g4_file)
109
+
110
+ try:
111
+ subprocess.check_call([
112
+ 'java',
113
+ '-jar', self.jar_path(),
114
+ '-Dlanguage=Python3',
115
+ '-visitor',
116
+ '-o', self._out_subdir,
117
+ os.path.basename(g4_file),
118
+ ], cwd=os.path.dirname(ap))
119
+
120
+ except Exception: # noqa
121
+ log.exception('Exception in grammar %s', g4_file)
122
+ raise
123
+
124
+ def process_py(self, py_file: str) -> None:
125
+ ap = os.path.abspath(py_file)
126
+ with open(ap) as f:
127
+ in_lines = list(f)
128
+
129
+ pfp = py_file.split(os.sep)
130
+ arp = ANTLR_RUNTIME_VENDOR.split('.')
131
+ if (cpl := lang.common_prefix_len(pfp, arp)) > 0:
132
+ pkg_depth = len(os.path.normpath(py_file).split(os.path.sep))
133
+ antlr_imp = '.'.join([*([''] * (pkg_depth - cpl)), *arp[cpl:]])
134
+ else:
135
+ antlr_imp = ANTLR_RUNTIME_VENDOR
136
+
137
+ out_lines = [
138
+ '# type: ignore\n',
139
+ '# ruff: noqa\n',
140
+ '# flake8: noqa\n',
141
+ '# @omlish-generated\n',
142
+ ]
143
+
144
+ for l in in_lines:
145
+ l = re.sub(r'^(from antlr4)(.*)', rf'from {antlr_imp}\2', l)
146
+ out_lines.append(l)
147
+
148
+ with open(ap, 'w') as f:
149
+ f.write(''.join(out_lines))
150
+
151
+ def process_dir(self, dir: str) -> None: # noqa
152
+ log.info('Processing directory %s', dir)
153
+
154
+ ad = os.path.join(dir, self._out_subdir)
155
+ if os.path.exists(ad):
156
+ self._rmtree(ad)
157
+
158
+ for f in os.listdir(dir):
159
+ fp = os.path.join(dir, f)
160
+ if not os.path.isfile(fp) or not f.endswith('.g4'):
161
+ continue
162
+
163
+ self.process_g4(fp)
164
+
165
+ if not os.path.exists(ad):
166
+ return
167
+
168
+ ip = os.path.join(ad, '__init__.py')
169
+ check.state(not os.path.exists(ip))
170
+
171
+ for f in list(os.listdir(ad)):
172
+ fp = os.path.join(ad, f)
173
+ if not os.path.isfile(fp):
174
+ continue
175
+
176
+ if f.split('.')[-1] in ('interp', 'tokens'):
177
+ os.unlink(fp)
178
+
179
+ elif f != '__init__.py' and f.endswith('.py'):
180
+ self.process_py(fp)
181
+
182
+ with open(ip, 'w'):
183
+ pass
184
+
185
+ def run(self) -> None:
186
+ dns = _find_dirs(*self._root_dirs, filter=lambda dn: os.path.basename(dn) == '_antlr')
187
+ for dn in dns:
188
+ self._rmtree(dn)
189
+
190
+ fns = _find_files(*self._root_dirs, filter=lambda fn: fn.endswith('.g4'))
191
+ fds = {os.path.dirname(fn) for fn in fns}
192
+ for dn in sorted(fds):
193
+ self.process_dir(dn)