deepfos 1.1.60__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.
- deepfos/__init__.py +6 -0
- deepfos/_version.py +21 -0
- deepfos/algo/__init__.py +0 -0
- deepfos/algo/graph.py +171 -0
- deepfos/algo/segtree.py +31 -0
- deepfos/api/V1_1/__init__.py +0 -0
- deepfos/api/V1_1/business_model.py +119 -0
- deepfos/api/V1_1/dimension.py +599 -0
- deepfos/api/V1_1/models/__init__.py +0 -0
- deepfos/api/V1_1/models/business_model.py +1033 -0
- deepfos/api/V1_1/models/dimension.py +2768 -0
- deepfos/api/V1_2/__init__.py +0 -0
- deepfos/api/V1_2/dimension.py +285 -0
- deepfos/api/V1_2/models/__init__.py +0 -0
- deepfos/api/V1_2/models/dimension.py +2923 -0
- deepfos/api/__init__.py +0 -0
- deepfos/api/account.py +167 -0
- deepfos/api/accounting_engines.py +147 -0
- deepfos/api/app.py +626 -0
- deepfos/api/approval_process.py +198 -0
- deepfos/api/base.py +983 -0
- deepfos/api/business_model.py +160 -0
- deepfos/api/consolidation.py +129 -0
- deepfos/api/consolidation_process.py +106 -0
- deepfos/api/datatable.py +341 -0
- deepfos/api/deep_pipeline.py +61 -0
- deepfos/api/deepconnector.py +36 -0
- deepfos/api/deepfos_task.py +92 -0
- deepfos/api/deepmodel.py +188 -0
- deepfos/api/dimension.py +486 -0
- deepfos/api/financial_model.py +319 -0
- deepfos/api/journal_model.py +119 -0
- deepfos/api/journal_template.py +132 -0
- deepfos/api/memory_financial_model.py +98 -0
- deepfos/api/models/__init__.py +3 -0
- deepfos/api/models/account.py +483 -0
- deepfos/api/models/accounting_engines.py +756 -0
- deepfos/api/models/app.py +1338 -0
- deepfos/api/models/approval_process.py +1043 -0
- deepfos/api/models/base.py +234 -0
- deepfos/api/models/business_model.py +805 -0
- deepfos/api/models/consolidation.py +711 -0
- deepfos/api/models/consolidation_process.py +248 -0
- deepfos/api/models/datatable_mysql.py +427 -0
- deepfos/api/models/deep_pipeline.py +55 -0
- deepfos/api/models/deepconnector.py +28 -0
- deepfos/api/models/deepfos_task.py +386 -0
- deepfos/api/models/deepmodel.py +308 -0
- deepfos/api/models/dimension.py +1576 -0
- deepfos/api/models/financial_model.py +1796 -0
- deepfos/api/models/journal_model.py +341 -0
- deepfos/api/models/journal_template.py +854 -0
- deepfos/api/models/memory_financial_model.py +478 -0
- deepfos/api/models/platform.py +178 -0
- deepfos/api/models/python.py +221 -0
- deepfos/api/models/reconciliation_engine.py +411 -0
- deepfos/api/models/reconciliation_report.py +161 -0
- deepfos/api/models/role_strategy.py +884 -0
- deepfos/api/models/smartlist.py +237 -0
- deepfos/api/models/space.py +1137 -0
- deepfos/api/models/system.py +1065 -0
- deepfos/api/models/variable.py +463 -0
- deepfos/api/models/workflow.py +946 -0
- deepfos/api/platform.py +199 -0
- deepfos/api/python.py +90 -0
- deepfos/api/reconciliation_engine.py +181 -0
- deepfos/api/reconciliation_report.py +64 -0
- deepfos/api/role_strategy.py +234 -0
- deepfos/api/smartlist.py +69 -0
- deepfos/api/space.py +582 -0
- deepfos/api/system.py +372 -0
- deepfos/api/variable.py +154 -0
- deepfos/api/workflow.py +264 -0
- deepfos/boost/__init__.py +6 -0
- deepfos/boost/py_jstream.py +89 -0
- deepfos/boost/py_pandas.py +20 -0
- deepfos/cache.py +121 -0
- deepfos/config.py +6 -0
- deepfos/core/__init__.py +27 -0
- deepfos/core/cube/__init__.py +10 -0
- deepfos/core/cube/_base.py +462 -0
- deepfos/core/cube/constants.py +21 -0
- deepfos/core/cube/cube.py +408 -0
- deepfos/core/cube/formula.py +707 -0
- deepfos/core/cube/syscube.py +532 -0
- deepfos/core/cube/typing.py +7 -0
- deepfos/core/cube/utils.py +238 -0
- deepfos/core/dimension/__init__.py +11 -0
- deepfos/core/dimension/_base.py +506 -0
- deepfos/core/dimension/dimcreator.py +184 -0
- deepfos/core/dimension/dimension.py +472 -0
- deepfos/core/dimension/dimexpr.py +271 -0
- deepfos/core/dimension/dimmember.py +155 -0
- deepfos/core/dimension/eledimension.py +22 -0
- deepfos/core/dimension/filters.py +99 -0
- deepfos/core/dimension/sysdimension.py +168 -0
- deepfos/core/logictable/__init__.py +5 -0
- deepfos/core/logictable/_cache.py +141 -0
- deepfos/core/logictable/_operator.py +663 -0
- deepfos/core/logictable/nodemixin.py +673 -0
- deepfos/core/logictable/sqlcondition.py +609 -0
- deepfos/core/logictable/tablemodel.py +497 -0
- deepfos/db/__init__.py +36 -0
- deepfos/db/cipher.py +660 -0
- deepfos/db/clickhouse.py +191 -0
- deepfos/db/connector.py +195 -0
- deepfos/db/daclickhouse.py +171 -0
- deepfos/db/dameng.py +101 -0
- deepfos/db/damysql.py +189 -0
- deepfos/db/dbkits.py +358 -0
- deepfos/db/deepengine.py +99 -0
- deepfos/db/deepmodel.py +82 -0
- deepfos/db/deepmodel_kingbase.py +83 -0
- deepfos/db/edb.py +214 -0
- deepfos/db/gauss.py +83 -0
- deepfos/db/kingbase.py +83 -0
- deepfos/db/mysql.py +184 -0
- deepfos/db/oracle.py +131 -0
- deepfos/db/postgresql.py +192 -0
- deepfos/db/sqlserver.py +99 -0
- deepfos/db/utils.py +135 -0
- deepfos/element/__init__.py +89 -0
- deepfos/element/accounting.py +348 -0
- deepfos/element/apvlprocess.py +215 -0
- deepfos/element/base.py +398 -0
- deepfos/element/bizmodel.py +1269 -0
- deepfos/element/datatable.py +2467 -0
- deepfos/element/deep_pipeline.py +186 -0
- deepfos/element/deepconnector.py +59 -0
- deepfos/element/deepmodel.py +1806 -0
- deepfos/element/dimension.py +1254 -0
- deepfos/element/fact_table.py +427 -0
- deepfos/element/finmodel.py +1485 -0
- deepfos/element/journal.py +840 -0
- deepfos/element/journal_template.py +943 -0
- deepfos/element/pyscript.py +412 -0
- deepfos/element/reconciliation.py +553 -0
- deepfos/element/rolestrategy.py +243 -0
- deepfos/element/smartlist.py +457 -0
- deepfos/element/variable.py +756 -0
- deepfos/element/workflow.py +560 -0
- deepfos/exceptions/__init__.py +239 -0
- deepfos/exceptions/hook.py +86 -0
- deepfos/lazy.py +104 -0
- deepfos/lazy_import.py +84 -0
- deepfos/lib/__init__.py +0 -0
- deepfos/lib/_javaobj.py +366 -0
- deepfos/lib/asynchronous.py +879 -0
- deepfos/lib/concurrency.py +107 -0
- deepfos/lib/constant.py +39 -0
- deepfos/lib/decorator.py +310 -0
- deepfos/lib/deepchart.py +778 -0
- deepfos/lib/deepux.py +477 -0
- deepfos/lib/discovery.py +273 -0
- deepfos/lib/edb_lexer.py +789 -0
- deepfos/lib/eureka.py +156 -0
- deepfos/lib/filterparser.py +751 -0
- deepfos/lib/httpcli.py +106 -0
- deepfos/lib/jsonstreamer.py +80 -0
- deepfos/lib/msg.py +394 -0
- deepfos/lib/nacos.py +225 -0
- deepfos/lib/patch.py +92 -0
- deepfos/lib/redis.py +241 -0
- deepfos/lib/serutils.py +181 -0
- deepfos/lib/stopwatch.py +99 -0
- deepfos/lib/subtask.py +572 -0
- deepfos/lib/sysutils.py +703 -0
- deepfos/lib/utils.py +1003 -0
- deepfos/local.py +160 -0
- deepfos/options.py +670 -0
- deepfos/translation.py +237 -0
- deepfos-1.1.60.dist-info/METADATA +33 -0
- deepfos-1.1.60.dist-info/RECORD +175 -0
- deepfos-1.1.60.dist-info/WHEEL +5 -0
- deepfos-1.1.60.dist-info/top_level.txt +1 -0
deepfos/lib/edb_lexer.py
ADDED
|
@@ -0,0 +1,789 @@
|
|
|
1
|
+
import collections
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
import types
|
|
5
|
+
from typing import Optional, Dict, AbstractSet
|
|
6
|
+
|
|
7
|
+
__all__ = ('EdgeQLLexer', 'UnknownTokenError')
|
|
8
|
+
|
|
9
|
+
keyword_types = range(1, 4)
|
|
10
|
+
UNRESERVED_KEYWORD, RESERVED_KEYWORD, TYPE_FUNC_NAME_KEYWORD = keyword_types
|
|
11
|
+
reserved_keywords = (
|
|
12
|
+
"__edgedbsys__",
|
|
13
|
+
"__edgedbtpl__",
|
|
14
|
+
"__source__",
|
|
15
|
+
"__std__",
|
|
16
|
+
"__subject__",
|
|
17
|
+
"__type__",
|
|
18
|
+
"alter",
|
|
19
|
+
"analyze",
|
|
20
|
+
"and",
|
|
21
|
+
"anyarray",
|
|
22
|
+
"anytuple",
|
|
23
|
+
"anytype",
|
|
24
|
+
"begin",
|
|
25
|
+
"by",
|
|
26
|
+
"case",
|
|
27
|
+
"check",
|
|
28
|
+
"commit",
|
|
29
|
+
"configure",
|
|
30
|
+
"create",
|
|
31
|
+
"deallocate",
|
|
32
|
+
"delete",
|
|
33
|
+
"describe",
|
|
34
|
+
"detached",
|
|
35
|
+
"discard",
|
|
36
|
+
"distinct",
|
|
37
|
+
"do",
|
|
38
|
+
"drop",
|
|
39
|
+
"else",
|
|
40
|
+
"end",
|
|
41
|
+
"execute",
|
|
42
|
+
"exists",
|
|
43
|
+
"explain",
|
|
44
|
+
"extending",
|
|
45
|
+
"fetch",
|
|
46
|
+
"filter",
|
|
47
|
+
"for",
|
|
48
|
+
"get",
|
|
49
|
+
"global",
|
|
50
|
+
"grant",
|
|
51
|
+
"group",
|
|
52
|
+
"if",
|
|
53
|
+
"ilike",
|
|
54
|
+
"import",
|
|
55
|
+
"in",
|
|
56
|
+
"insert",
|
|
57
|
+
"introspect",
|
|
58
|
+
"is",
|
|
59
|
+
"like",
|
|
60
|
+
"limit",
|
|
61
|
+
"listen",
|
|
62
|
+
"load",
|
|
63
|
+
"lock",
|
|
64
|
+
"match",
|
|
65
|
+
"module",
|
|
66
|
+
"move",
|
|
67
|
+
"never",
|
|
68
|
+
"not",
|
|
69
|
+
"notify",
|
|
70
|
+
"offset",
|
|
71
|
+
"on",
|
|
72
|
+
"optional",
|
|
73
|
+
"or",
|
|
74
|
+
"over",
|
|
75
|
+
"partition",
|
|
76
|
+
"prepare",
|
|
77
|
+
"raise",
|
|
78
|
+
"refresh",
|
|
79
|
+
"reindex",
|
|
80
|
+
"revoke",
|
|
81
|
+
"rollback",
|
|
82
|
+
"select",
|
|
83
|
+
"set",
|
|
84
|
+
"single",
|
|
85
|
+
"start",
|
|
86
|
+
"typeof",
|
|
87
|
+
"union",
|
|
88
|
+
"update",
|
|
89
|
+
"variadic",
|
|
90
|
+
"when",
|
|
91
|
+
"window",
|
|
92
|
+
"with",
|
|
93
|
+
)
|
|
94
|
+
unreserved_keywords = (
|
|
95
|
+
"abort",
|
|
96
|
+
"abstract",
|
|
97
|
+
"access",
|
|
98
|
+
"after",
|
|
99
|
+
"alias",
|
|
100
|
+
"all",
|
|
101
|
+
"allow",
|
|
102
|
+
"annotation",
|
|
103
|
+
"applied",
|
|
104
|
+
"as",
|
|
105
|
+
"asc",
|
|
106
|
+
"assignment",
|
|
107
|
+
"before",
|
|
108
|
+
"cardinality",
|
|
109
|
+
"cast",
|
|
110
|
+
"config",
|
|
111
|
+
"conflict",
|
|
112
|
+
"constraint",
|
|
113
|
+
"cube",
|
|
114
|
+
"current",
|
|
115
|
+
"database",
|
|
116
|
+
"ddl",
|
|
117
|
+
"declare",
|
|
118
|
+
"default",
|
|
119
|
+
"deferrable",
|
|
120
|
+
"deferred",
|
|
121
|
+
"delegated",
|
|
122
|
+
"deny",
|
|
123
|
+
"desc",
|
|
124
|
+
"empty",
|
|
125
|
+
"except",
|
|
126
|
+
"expression",
|
|
127
|
+
"extension",
|
|
128
|
+
"final",
|
|
129
|
+
"first",
|
|
130
|
+
"from",
|
|
131
|
+
"function",
|
|
132
|
+
"implicit",
|
|
133
|
+
"index",
|
|
134
|
+
"infix",
|
|
135
|
+
"inheritable",
|
|
136
|
+
"instance",
|
|
137
|
+
"into",
|
|
138
|
+
"isolation",
|
|
139
|
+
"json",
|
|
140
|
+
"last",
|
|
141
|
+
"link",
|
|
142
|
+
"migration",
|
|
143
|
+
"multi",
|
|
144
|
+
"named",
|
|
145
|
+
"object",
|
|
146
|
+
"of",
|
|
147
|
+
"only",
|
|
148
|
+
"onto",
|
|
149
|
+
"operator",
|
|
150
|
+
"optionality",
|
|
151
|
+
"order",
|
|
152
|
+
"orphan",
|
|
153
|
+
"overloaded",
|
|
154
|
+
"owned",
|
|
155
|
+
"package",
|
|
156
|
+
"policy",
|
|
157
|
+
"populate",
|
|
158
|
+
"postfix",
|
|
159
|
+
"prefix",
|
|
160
|
+
"property",
|
|
161
|
+
"proposed",
|
|
162
|
+
"pseudo",
|
|
163
|
+
"read",
|
|
164
|
+
"reject",
|
|
165
|
+
"release",
|
|
166
|
+
"rename",
|
|
167
|
+
"required",
|
|
168
|
+
"reset",
|
|
169
|
+
"restrict",
|
|
170
|
+
"role",
|
|
171
|
+
"roles",
|
|
172
|
+
"rollup",
|
|
173
|
+
"savepoint",
|
|
174
|
+
"scalar",
|
|
175
|
+
"schema",
|
|
176
|
+
"sdl",
|
|
177
|
+
"serializable",
|
|
178
|
+
"session",
|
|
179
|
+
"source",
|
|
180
|
+
"superuser",
|
|
181
|
+
"system",
|
|
182
|
+
"target",
|
|
183
|
+
"ternary",
|
|
184
|
+
"text",
|
|
185
|
+
"then",
|
|
186
|
+
"to",
|
|
187
|
+
"transaction",
|
|
188
|
+
"type",
|
|
189
|
+
"unless",
|
|
190
|
+
"using",
|
|
191
|
+
"verbose",
|
|
192
|
+
"version",
|
|
193
|
+
"view",
|
|
194
|
+
"write",
|
|
195
|
+
)
|
|
196
|
+
_dunder_re = re.compile(r'(?i)^__[a-z]+__$')
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def tok_name(keyword):
|
|
200
|
+
'''Convert a literal keyword into a token name.'''
|
|
201
|
+
if _dunder_re.match(keyword):
|
|
202
|
+
return f'DUNDER{keyword[2:-2].upper()}'
|
|
203
|
+
else:
|
|
204
|
+
return keyword.upper()
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
edgeql_keywords = {k: (tok_name(k), UNRESERVED_KEYWORD)
|
|
208
|
+
for k in unreserved_keywords}
|
|
209
|
+
edgeql_keywords.update({k: (tok_name(k), RESERVED_KEYWORD)
|
|
210
|
+
for k in reserved_keywords})
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
STATE_KEEP = 0
|
|
214
|
+
STATE_BASE = 1
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
re_dquote = r'\$(?:[A-Za-z_][A-Za-z_0-9]*)?\$'
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class LexError(Exception):
|
|
221
|
+
def __init__(
|
|
222
|
+
self, msg, *, line=None, col=None, filename=None, format=True):
|
|
223
|
+
if format and '{' in msg:
|
|
224
|
+
position = self._format_position(line, col, filename)
|
|
225
|
+
msg = msg.format(
|
|
226
|
+
line=line, col=col, filename=filename, position=position)
|
|
227
|
+
|
|
228
|
+
super().__init__(msg)
|
|
229
|
+
self.line = line
|
|
230
|
+
self.col = col
|
|
231
|
+
self.filename = filename
|
|
232
|
+
|
|
233
|
+
@classmethod
|
|
234
|
+
def _format_position(cls, line, col, filename):
|
|
235
|
+
position = 'at {}:{}'.format(line, col)
|
|
236
|
+
if filename:
|
|
237
|
+
position += ' of ' + str(filename)
|
|
238
|
+
return position
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
Token = collections.namedtuple(
|
|
242
|
+
'Token',
|
|
243
|
+
['value', 'type', 'text', 'start', 'end', 'filename']
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class UnknownTokenError(LexError):
|
|
248
|
+
pass
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class Rule:
|
|
252
|
+
_idx = 0
|
|
253
|
+
_map: Dict[str, "Rule"] = {}
|
|
254
|
+
|
|
255
|
+
def __init__(self, *, token, next_state, regexp):
|
|
256
|
+
cls = self.__class__
|
|
257
|
+
cls._idx += 1
|
|
258
|
+
self.id = 'rule{}'.format(cls._idx)
|
|
259
|
+
cls._map[self.id] = self
|
|
260
|
+
|
|
261
|
+
self.token = token
|
|
262
|
+
self.next_state = next_state
|
|
263
|
+
self.regexp = regexp
|
|
264
|
+
|
|
265
|
+
def __repr__(self):
|
|
266
|
+
return '<{} {} {!r}>'.format(self.id, self.token, self.regexp)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def group(*literals, _re_alpha=re.compile(r'^\w+$'), asbytes=False):
|
|
270
|
+
rx = []
|
|
271
|
+
for lit in literals:
|
|
272
|
+
if r'\b' not in lit:
|
|
273
|
+
lit = re.escape(lit)
|
|
274
|
+
if _re_alpha.match(lit):
|
|
275
|
+
lit = r'\b' + lit + r'\b'
|
|
276
|
+
rx.append(lit)
|
|
277
|
+
result = ' | '.join(rx)
|
|
278
|
+
if asbytes:
|
|
279
|
+
result = result.encode()
|
|
280
|
+
|
|
281
|
+
return result
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class Lexer:
|
|
285
|
+
|
|
286
|
+
NL: Optional[str] = None
|
|
287
|
+
MULTILINE_TOKENS: AbstractSet[str] = frozenset()
|
|
288
|
+
RE_FLAGS = re.X | re.M
|
|
289
|
+
asbytes = False
|
|
290
|
+
_NL = '\n'
|
|
291
|
+
|
|
292
|
+
def __init_subclass__(cls):
|
|
293
|
+
if not hasattr(cls, 'states'):
|
|
294
|
+
return
|
|
295
|
+
|
|
296
|
+
re_states = {}
|
|
297
|
+
for state, rules in cls.states.items():
|
|
298
|
+
res = []
|
|
299
|
+
for rule in rules:
|
|
300
|
+
if cls.asbytes:
|
|
301
|
+
res.append(b'(?P<%b>%b)' % (rule.id.encode(), rule.regexp))
|
|
302
|
+
else:
|
|
303
|
+
res.append('(?P<{}>{})'.format(rule.id, rule.regexp))
|
|
304
|
+
|
|
305
|
+
if cls.asbytes:
|
|
306
|
+
res.append(b'(?P<err>.)')
|
|
307
|
+
else:
|
|
308
|
+
res.append('(?P<err>.)')
|
|
309
|
+
|
|
310
|
+
if cls.asbytes:
|
|
311
|
+
full_re = b' | '.join(res)
|
|
312
|
+
else:
|
|
313
|
+
full_re = ' | '.join(res)
|
|
314
|
+
re_states[state] = re.compile(full_re, cls.RE_FLAGS)
|
|
315
|
+
|
|
316
|
+
cls.re_states = types.MappingProxyType(re_states)
|
|
317
|
+
|
|
318
|
+
def __init__(self):
|
|
319
|
+
self.reset()
|
|
320
|
+
if self.asbytes:
|
|
321
|
+
self._NL = b'\n'
|
|
322
|
+
|
|
323
|
+
def reset(self):
|
|
324
|
+
self.lineno = 1
|
|
325
|
+
self.column = 1
|
|
326
|
+
self._state = self.start_state
|
|
327
|
+
self._states = []
|
|
328
|
+
|
|
329
|
+
def setinputstr(self, inputstr, filename=None):
|
|
330
|
+
self.inputstr = inputstr
|
|
331
|
+
self.filename = filename
|
|
332
|
+
self.start = 0
|
|
333
|
+
self.end = len(inputstr)
|
|
334
|
+
self.reset()
|
|
335
|
+
self._token_stream = None
|
|
336
|
+
|
|
337
|
+
def get_start_token(self):
|
|
338
|
+
"""Return a start token or None if no start token is wanted."""
|
|
339
|
+
return None
|
|
340
|
+
|
|
341
|
+
def get_eof_token(self):
|
|
342
|
+
"""Return an EOF token or None if no EOF token is wanted."""
|
|
343
|
+
return None
|
|
344
|
+
|
|
345
|
+
def token_from_text(self, rule_token, txt):
|
|
346
|
+
"""Given the rule_token with txt create a token.
|
|
347
|
+
|
|
348
|
+
Update the lexer lineno, column, and start.
|
|
349
|
+
"""
|
|
350
|
+
start_pos = self.start
|
|
351
|
+
len_txt = len(txt)
|
|
352
|
+
|
|
353
|
+
if rule_token is self.NL:
|
|
354
|
+
# Newline -- increase line number & set col to 1
|
|
355
|
+
self.lineno += 1
|
|
356
|
+
self.column = 1
|
|
357
|
+
|
|
358
|
+
elif rule_token in self.MULTILINE_TOKENS and self._NL in txt:
|
|
359
|
+
# Advance line & col according to how many new lines
|
|
360
|
+
# are in comments/strings/etc.
|
|
361
|
+
self.lineno += txt.count(self._NL)
|
|
362
|
+
self.column = len(txt.rsplit(self._NL, 1)[1]) + 1
|
|
363
|
+
else:
|
|
364
|
+
self.column += len_txt
|
|
365
|
+
|
|
366
|
+
self.start += len_txt
|
|
367
|
+
end_pos = self.start
|
|
368
|
+
|
|
369
|
+
return Token(txt, type=rule_token, text=txt,
|
|
370
|
+
start=start_pos, end=end_pos,
|
|
371
|
+
filename=self.filename)
|
|
372
|
+
|
|
373
|
+
def lex(self):
|
|
374
|
+
"""Tokenize the src.
|
|
375
|
+
|
|
376
|
+
Generator. Yields tokens (as defined by the rules).
|
|
377
|
+
|
|
378
|
+
May yield special start and EOF tokens.
|
|
379
|
+
May raise UnknownTokenError exception.
|
|
380
|
+
"""
|
|
381
|
+
src = self.inputstr
|
|
382
|
+
|
|
383
|
+
start_tok = self.get_start_token()
|
|
384
|
+
if start_tok is not None:
|
|
385
|
+
yield start_tok
|
|
386
|
+
|
|
387
|
+
while self.start < self.end:
|
|
388
|
+
for match in self.re_states[self._state].finditer(src, self.start):
|
|
389
|
+
rule_id = match.lastgroup
|
|
390
|
+
|
|
391
|
+
txt = match.group(rule_id)
|
|
392
|
+
|
|
393
|
+
if rule_id == 'err':
|
|
394
|
+
# Error group -- no rule has been matched
|
|
395
|
+
self.handle_error(txt)
|
|
396
|
+
|
|
397
|
+
rule = Rule._map[rule_id]
|
|
398
|
+
rule_token = rule.token
|
|
399
|
+
|
|
400
|
+
token = self.token_from_text(rule_token, txt)
|
|
401
|
+
|
|
402
|
+
yield token
|
|
403
|
+
|
|
404
|
+
if rule.next_state and rule.next_state != self._state:
|
|
405
|
+
# Rule dictates that the lexer state should be
|
|
406
|
+
# switched
|
|
407
|
+
self._state = rule.next_state
|
|
408
|
+
break
|
|
409
|
+
|
|
410
|
+
# End of file
|
|
411
|
+
eof_tok = self.get_eof_token()
|
|
412
|
+
if eof_tok is not None:
|
|
413
|
+
yield eof_tok
|
|
414
|
+
|
|
415
|
+
def handle_error(self, txt, *,
|
|
416
|
+
exact_message=False, exc_type=UnknownTokenError):
|
|
417
|
+
if exact_message:
|
|
418
|
+
msg = txt
|
|
419
|
+
else:
|
|
420
|
+
msg = f"Unexpected '{txt}'"
|
|
421
|
+
|
|
422
|
+
raise exc_type(
|
|
423
|
+
msg, line=self.lineno, col=self.column, filename=self.filename
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
def token(self):
|
|
427
|
+
"""Return the next token produced by the
|
|
428
|
+
|
|
429
|
+
The token is an xvalue with the following attributes: type,
|
|
430
|
+
text, start, end, and filename.
|
|
431
|
+
"""
|
|
432
|
+
if self._token_stream is None:
|
|
433
|
+
self._token_stream = self.lex()
|
|
434
|
+
|
|
435
|
+
try:
|
|
436
|
+
return next(self._token_stream)
|
|
437
|
+
except StopIteration:
|
|
438
|
+
return None
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
class UnterminatedStringError(UnknownTokenError):
|
|
442
|
+
pass
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
class PseudoRule(Rule):
|
|
446
|
+
def __init__(self, *, token, regexp, rule_id, next_state=STATE_KEEP):
|
|
447
|
+
self.id = rule_id
|
|
448
|
+
Rule._map[rule_id] = self
|
|
449
|
+
self.token = token
|
|
450
|
+
self.next_state = next_state
|
|
451
|
+
self.regexp = regexp
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
class EdgeQLLexer(Lexer):
|
|
455
|
+
|
|
456
|
+
start_state = STATE_BASE
|
|
457
|
+
|
|
458
|
+
MERGE_TOKENS = {
|
|
459
|
+
('NAMED', 'ONLY'),
|
|
460
|
+
('SET', 'ANNOTATION'),
|
|
461
|
+
('SET', 'TYPE'),
|
|
462
|
+
('EXTENSION', 'PACKAGE'),
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
NL = 'NL'
|
|
466
|
+
MULTILINE_TOKENS = frozenset(('SCONST', 'BCONST', 'RSCONST'))
|
|
467
|
+
RE_FLAGS = re.X | re.M | re.I
|
|
468
|
+
|
|
469
|
+
# Basic keywords
|
|
470
|
+
keyword_rules = [Rule(token=tok[0],
|
|
471
|
+
next_state=STATE_KEEP,
|
|
472
|
+
regexp=group(val))
|
|
473
|
+
for val, tok in edgeql_keywords.items()]
|
|
474
|
+
|
|
475
|
+
common_rules = keyword_rules + [
|
|
476
|
+
Rule(token='WS',
|
|
477
|
+
next_state=STATE_KEEP,
|
|
478
|
+
regexp=r'[^\S\n]+'),
|
|
479
|
+
|
|
480
|
+
Rule(token='NL',
|
|
481
|
+
next_state=STATE_KEEP,
|
|
482
|
+
regexp=r'\n'),
|
|
483
|
+
|
|
484
|
+
Rule(token='COMMENT',
|
|
485
|
+
next_state=STATE_KEEP,
|
|
486
|
+
regexp=r'''\#.*?$'''),
|
|
487
|
+
|
|
488
|
+
Rule(token='ASSIGN',
|
|
489
|
+
next_state=STATE_KEEP,
|
|
490
|
+
regexp=r':='),
|
|
491
|
+
|
|
492
|
+
Rule(token='REMASSIGN',
|
|
493
|
+
next_state=STATE_KEEP,
|
|
494
|
+
regexp=r'-='),
|
|
495
|
+
|
|
496
|
+
Rule(token='ADDASSIGN',
|
|
497
|
+
next_state=STATE_KEEP,
|
|
498
|
+
regexp=r'\+='),
|
|
499
|
+
|
|
500
|
+
Rule(token='ARROW',
|
|
501
|
+
next_state=STATE_KEEP,
|
|
502
|
+
regexp=r'->'),
|
|
503
|
+
|
|
504
|
+
Rule(token='??',
|
|
505
|
+
next_state=STATE_KEEP,
|
|
506
|
+
regexp=r'\?\?'),
|
|
507
|
+
|
|
508
|
+
Rule(token='::',
|
|
509
|
+
next_state=STATE_KEEP,
|
|
510
|
+
regexp=r'::'),
|
|
511
|
+
|
|
512
|
+
# special path operators
|
|
513
|
+
Rule(token='.<',
|
|
514
|
+
next_state=STATE_KEEP,
|
|
515
|
+
regexp=r'\.<'),
|
|
516
|
+
|
|
517
|
+
Rule(token='//',
|
|
518
|
+
next_state=STATE_KEEP,
|
|
519
|
+
regexp=r'//'),
|
|
520
|
+
|
|
521
|
+
Rule(token='++',
|
|
522
|
+
next_state=STATE_KEEP,
|
|
523
|
+
regexp=r'\+\+'),
|
|
524
|
+
|
|
525
|
+
Rule(token='OP',
|
|
526
|
+
next_state=STATE_KEEP,
|
|
527
|
+
regexp=r'''
|
|
528
|
+
(?: >= | <= | != | \?= | \?!=)
|
|
529
|
+
'''),
|
|
530
|
+
|
|
531
|
+
Rule(token='self',
|
|
532
|
+
next_state=STATE_KEEP,
|
|
533
|
+
regexp=r'[,()\[\].@;:+\-*/%^<>=&|]'),
|
|
534
|
+
|
|
535
|
+
Rule(token='NFCONST',
|
|
536
|
+
next_state=STATE_KEEP,
|
|
537
|
+
regexp=r"""
|
|
538
|
+
(?:
|
|
539
|
+
(?: \d+ (?:\.\d+)?
|
|
540
|
+
(?:[eE](?:[+\-])?[0-9]+)
|
|
541
|
+
)
|
|
542
|
+
|
|
|
543
|
+
(?: \d+\.\d+)
|
|
544
|
+
)n
|
|
545
|
+
"""),
|
|
546
|
+
|
|
547
|
+
Rule(token='NICONST',
|
|
548
|
+
next_state=STATE_KEEP,
|
|
549
|
+
regexp=r'((?:[1-9]\d* | 0)n)'),
|
|
550
|
+
|
|
551
|
+
Rule(token='FCONST',
|
|
552
|
+
next_state=STATE_KEEP,
|
|
553
|
+
regexp=r"""
|
|
554
|
+
(?: \d+ (?:\.\d+)?
|
|
555
|
+
(?:[eE](?:[+\-])?[0-9]+)
|
|
556
|
+
)
|
|
557
|
+
|
|
|
558
|
+
(?: \d+\.\d+)
|
|
559
|
+
"""),
|
|
560
|
+
|
|
561
|
+
Rule(token='ICONST',
|
|
562
|
+
next_state=STATE_KEEP,
|
|
563
|
+
regexp=r'([1-9]\d* | 0)(?![0-9])'),
|
|
564
|
+
|
|
565
|
+
Rule(token='BCONST',
|
|
566
|
+
next_state=STATE_KEEP,
|
|
567
|
+
regexp=rf'''
|
|
568
|
+
(?:
|
|
569
|
+
b
|
|
570
|
+
)
|
|
571
|
+
(?P<BQ>
|
|
572
|
+
' | "
|
|
573
|
+
)
|
|
574
|
+
(?:
|
|
575
|
+
(
|
|
576
|
+
\\\\ | \\['"] | \n | .
|
|
577
|
+
# we'll validate escape codes in the parser
|
|
578
|
+
)*?
|
|
579
|
+
)
|
|
580
|
+
(?P=BQ)
|
|
581
|
+
'''),
|
|
582
|
+
|
|
583
|
+
Rule(token='RSCONST',
|
|
584
|
+
next_state=STATE_KEEP,
|
|
585
|
+
regexp=rf'''
|
|
586
|
+
(?:
|
|
587
|
+
r
|
|
588
|
+
)?
|
|
589
|
+
(?P<RQ>
|
|
590
|
+
(?:
|
|
591
|
+
(?<=r) (?: ' | ")
|
|
592
|
+
) | (?:
|
|
593
|
+
(?<!r) (?: {re_dquote})
|
|
594
|
+
)
|
|
595
|
+
)
|
|
596
|
+
(?:
|
|
597
|
+
(
|
|
598
|
+
\n | .
|
|
599
|
+
# we'll validate escape codes in the parser
|
|
600
|
+
)*?
|
|
601
|
+
)
|
|
602
|
+
(?P=RQ)
|
|
603
|
+
'''),
|
|
604
|
+
|
|
605
|
+
Rule(token='LSCONST',
|
|
606
|
+
next_state=STATE_KEEP,
|
|
607
|
+
regexp=rf'''
|
|
608
|
+
(?:
|
|
609
|
+
L
|
|
610
|
+
)?
|
|
611
|
+
(?P<LQ>
|
|
612
|
+
(?:
|
|
613
|
+
(?<=L) (?: ' | ")
|
|
614
|
+
) | (?:
|
|
615
|
+
(?<!L) (?: {re_dquote})
|
|
616
|
+
)
|
|
617
|
+
)
|
|
618
|
+
(?:
|
|
619
|
+
(
|
|
620
|
+
\n | .
|
|
621
|
+
# we'll validate escape codes in the parser
|
|
622
|
+
)*?
|
|
623
|
+
)
|
|
624
|
+
(?P=LQ)
|
|
625
|
+
'''),
|
|
626
|
+
|
|
627
|
+
Rule(token='SCONST',
|
|
628
|
+
next_state=STATE_KEEP,
|
|
629
|
+
regexp=rf'''
|
|
630
|
+
(?P<Q>
|
|
631
|
+
' | "
|
|
632
|
+
)
|
|
633
|
+
(?:
|
|
634
|
+
(
|
|
635
|
+
\\\\ | \\['"] | \n | .
|
|
636
|
+
# we'll validate escape codes in the parser
|
|
637
|
+
)*?
|
|
638
|
+
)
|
|
639
|
+
(?P=Q)
|
|
640
|
+
'''),
|
|
641
|
+
|
|
642
|
+
# this rule will capture malformed strings and allow us to
|
|
643
|
+
# provide better error messages
|
|
644
|
+
Rule(token='BADSCONST',
|
|
645
|
+
next_state=STATE_KEEP,
|
|
646
|
+
regexp=rf'''
|
|
647
|
+
[rb]?
|
|
648
|
+
(['"] | (?: {re_dquote}))
|
|
649
|
+
[^\n]*
|
|
650
|
+
'''),
|
|
651
|
+
|
|
652
|
+
Rule(token='BADIDENT',
|
|
653
|
+
next_state=STATE_KEEP,
|
|
654
|
+
regexp=r'''
|
|
655
|
+
__[^\W\d]\w*__
|
|
656
|
+
|
|
|
657
|
+
`__([^`]|``)*__`(?!`)
|
|
658
|
+
'''),
|
|
659
|
+
|
|
660
|
+
Rule(token='IDENT',
|
|
661
|
+
next_state=STATE_KEEP,
|
|
662
|
+
regexp=r'[^\W\d]\w*'),
|
|
663
|
+
|
|
664
|
+
Rule(token='QIDENT',
|
|
665
|
+
next_state=STATE_KEEP,
|
|
666
|
+
regexp=r'`([^`]|``)*`'),
|
|
667
|
+
|
|
668
|
+
Rule(token='self',
|
|
669
|
+
next_state=STATE_KEEP,
|
|
670
|
+
regexp=r'[\{\}]'),
|
|
671
|
+
|
|
672
|
+
Rule(token='ARGUMENT',
|
|
673
|
+
next_state=STATE_KEEP,
|
|
674
|
+
regexp=r'\$(?:[0-9]+|[^\W\d]\w*|`(?:[^`]|``)*`)'),
|
|
675
|
+
|
|
676
|
+
Rule(token='BADARGUMENT',
|
|
677
|
+
next_state=STATE_KEEP,
|
|
678
|
+
regexp=r'\$[0-9]+[^\W\d]\w*'),
|
|
679
|
+
]
|
|
680
|
+
|
|
681
|
+
states = {
|
|
682
|
+
STATE_BASE:
|
|
683
|
+
common_rules,
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
# add capacity to handle a few tokens composed of 2 elements
|
|
687
|
+
_possible_long_token = {x[0] for x in MERGE_TOKENS}
|
|
688
|
+
_long_token_match = {x[1]: x[0] for x in MERGE_TOKENS}
|
|
689
|
+
|
|
690
|
+
special_rules = [
|
|
691
|
+
PseudoRule(token='UNKNOWN',
|
|
692
|
+
next_state=STATE_KEEP,
|
|
693
|
+
regexp=r'.',
|
|
694
|
+
rule_id='err')
|
|
695
|
+
]
|
|
696
|
+
|
|
697
|
+
def __init__(self, *, strip_whitespace=True, raise_lexerror=True):
|
|
698
|
+
super().__init__()
|
|
699
|
+
self.strip_whitespace = strip_whitespace
|
|
700
|
+
self.raise_lexerror = raise_lexerror
|
|
701
|
+
|
|
702
|
+
def get_eof_token(self):
|
|
703
|
+
"""Return an EOF token or None if no EOF token is wanted."""
|
|
704
|
+
return self.token_from_text('EOF', '')
|
|
705
|
+
|
|
706
|
+
def token_from_text(self, rule_token, txt):
|
|
707
|
+
if rule_token == 'BADSCONST':
|
|
708
|
+
self.handle_error(f"Unterminated string {txt}",
|
|
709
|
+
exact_message=True,
|
|
710
|
+
exc_type=UnterminatedStringError)
|
|
711
|
+
elif rule_token == 'BADIDENT':
|
|
712
|
+
self.handle_error(txt)
|
|
713
|
+
|
|
714
|
+
elif rule_token == 'QIDENT':
|
|
715
|
+
if txt == '``':
|
|
716
|
+
self.handle_error(f'Identifiers cannot be empty',
|
|
717
|
+
exact_message=True)
|
|
718
|
+
elif txt[1] == '@':
|
|
719
|
+
self.handle_error(f'Identifiers cannot start with "@"',
|
|
720
|
+
exact_message=True)
|
|
721
|
+
elif '::' in txt:
|
|
722
|
+
self.handle_error(f'Identifiers cannot contain "::"',
|
|
723
|
+
exact_message=True)
|
|
724
|
+
elif rule_token == 'ARGUMENT':
|
|
725
|
+
if txt == '$``':
|
|
726
|
+
self.handle_error(f'Backtick-quoted variable names '
|
|
727
|
+
f'cannot be empty',
|
|
728
|
+
exact_message=True)
|
|
729
|
+
elif rule_token == 'BADARGUMENT':
|
|
730
|
+
self.handle_error(f"Invalid argument name {txt!r} "
|
|
731
|
+
f"should be either all digits or "
|
|
732
|
+
f"start with letter",
|
|
733
|
+
exact_message=True,
|
|
734
|
+
exc_type=UnterminatedStringError)
|
|
735
|
+
|
|
736
|
+
tok = super().token_from_text(rule_token, txt)
|
|
737
|
+
|
|
738
|
+
if rule_token == 'self':
|
|
739
|
+
tok = tok._replace(type=txt)
|
|
740
|
+
|
|
741
|
+
elif rule_token == 'QIDENT':
|
|
742
|
+
# Drop the quotes and replace the "``" inside with a "`"
|
|
743
|
+
val = txt[1:-1].replace('``', '`')
|
|
744
|
+
tok = tok._replace(type='IDENT', value=val)
|
|
745
|
+
|
|
746
|
+
return tok
|
|
747
|
+
|
|
748
|
+
def lex(self):
|
|
749
|
+
buffer = []
|
|
750
|
+
|
|
751
|
+
for tok in super().lex():
|
|
752
|
+
tok_type = tok.type
|
|
753
|
+
|
|
754
|
+
if self.strip_whitespace and tok_type in {'WS', 'NL', 'COMMENT'}:
|
|
755
|
+
# Strip out whitespace and comments
|
|
756
|
+
continue
|
|
757
|
+
|
|
758
|
+
elif tok_type in self._possible_long_token:
|
|
759
|
+
# Buffer in case this is a merged token
|
|
760
|
+
if not buffer:
|
|
761
|
+
buffer.append(tok)
|
|
762
|
+
else:
|
|
763
|
+
yield from iter(buffer)
|
|
764
|
+
buffer[:] = [tok]
|
|
765
|
+
|
|
766
|
+
elif tok_type in self._long_token_match:
|
|
767
|
+
prev_token = buffer[-1] if buffer else None
|
|
768
|
+
if (prev_token and
|
|
769
|
+
prev_token.type == self._long_token_match[tok_type]):
|
|
770
|
+
tok = prev_token._replace(
|
|
771
|
+
value=prev_token.value + ' ' + tok.value,
|
|
772
|
+
type=prev_token.type + tok_type)
|
|
773
|
+
buffer.pop()
|
|
774
|
+
yield tok
|
|
775
|
+
|
|
776
|
+
else:
|
|
777
|
+
if buffer:
|
|
778
|
+
yield from iter(buffer)
|
|
779
|
+
buffer[:] = []
|
|
780
|
+
yield tok
|
|
781
|
+
|
|
782
|
+
def lex_highlight(self):
|
|
783
|
+
return super().lex()
|
|
784
|
+
|
|
785
|
+
def handle_error(self, txt, *,
|
|
786
|
+
exact_message=False, exc_type=UnknownTokenError):
|
|
787
|
+
if self.raise_lexerror:
|
|
788
|
+
super().handle_error(
|
|
789
|
+
txt, exact_message=exact_message, exc_type=exc_type)
|