kaqing 2.0.184__py3-none-any.whl → 2.0.214__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.
Potentially problematic release.
This version of kaqing might be problematic. Click here for more details.
- adam/app_session.py +1 -1
- adam/batch.py +15 -15
- adam/commands/app/app.py +2 -2
- adam/commands/app/show_app_actions.py +1 -1
- adam/commands/{show → app}/show_login.py +1 -1
- adam/commands/app/utils_app.py +9 -1
- adam/commands/audit/audit.py +6 -20
- adam/commands/audit/audit_repair_tables.py +1 -1
- adam/commands/audit/audit_run.py +1 -1
- adam/commands/audit/completions_l.py +15 -0
- adam/commands/audit/show_last10.py +0 -1
- adam/commands/bash/bash.py +1 -1
- adam/commands/bash/utils_bash.py +1 -1
- adam/commands/cassandra/download_cassandra_log.py +45 -0
- adam/commands/cassandra/restart_cluster.py +47 -0
- adam/commands/cassandra/restart_node.py +51 -0
- adam/commands/cassandra/restart_nodes.py +47 -0
- adam/commands/{rollout.py → cassandra/rollout.py} +1 -1
- adam/commands/{show → cassandra}/show_cassandra_repairs.py +5 -3
- adam/commands/{show → cassandra}/show_cassandra_status.py +22 -15
- adam/commands/cassandra/show_processes.py +50 -0
- adam/commands/{show → cassandra}/show_storage.py +10 -8
- adam/commands/cli/__init__.py +0 -0
- adam/commands/{cli_commands.py → cli/cli_commands.py} +6 -1
- adam/commands/{clipboard_copy.py → cli/clipboard_copy.py} +2 -2
- adam/commands/{show/show_commands.py → cli/show_cli_commands.py} +2 -2
- adam/commands/command.py +22 -9
- adam/commands/commands_utils.py +14 -6
- adam/commands/config/__init__.py +0 -0
- adam/commands/{show → config}/show_params.py +1 -1
- adam/commands/{alter_tables.py → cql/alter_tables.py} +1 -1
- adam/commands/cql/completions_c.py +29 -0
- adam/commands/cql/cqlsh.py +2 -6
- adam/commands/cql/utils_cql.py +26 -17
- adam/commands/debug/__init__.py +0 -0
- adam/commands/debug/debug.py +22 -0
- adam/commands/debug/debug_completes.py +35 -0
- adam/commands/debug/debug_timings.py +35 -0
- adam/commands/debug/show_offloaded_completes.py +45 -0
- adam/commands/devices/device.py +30 -4
- adam/commands/devices/device_app.py +1 -1
- adam/commands/devices/device_export.py +5 -2
- adam/commands/devices/device_postgres.py +13 -3
- adam/commands/devices/devices.py +1 -1
- adam/commands/diag/__init__.py +0 -0
- adam/commands/{check.py → diag/check.py} +1 -1
- adam/commands/diag/generate_report.py +52 -0
- adam/commands/export/completions_x.py +11 -0
- adam/commands/export/download_export_session.py +2 -1
- adam/commands/export/export.py +0 -16
- adam/commands/export/export_databases.py +16 -10
- adam/commands/export/export_select.py +8 -33
- adam/commands/export/export_sessions.py +12 -11
- adam/commands/export/export_use.py +3 -3
- adam/commands/export/export_x_select.py +48 -0
- adam/commands/export/exporter.py +140 -53
- adam/commands/export/import_files.py +2 -2
- adam/commands/export/import_session.py +0 -4
- adam/commands/export/importer.py +11 -11
- adam/commands/export/importer_athena.py +15 -35
- adam/commands/export/importer_sqlite.py +19 -8
- adam/commands/export/show_column_counts.py +10 -10
- adam/commands/export/show_export_databases.py +2 -1
- adam/commands/export/show_export_session.py +1 -1
- adam/commands/export/show_export_sessions.py +1 -1
- adam/commands/export/utils_export.py +38 -15
- adam/commands/fs/__init__.py +0 -0
- adam/commands/{cat.py → fs/cat.py} +2 -2
- adam/commands/fs/cat_local.py +42 -0
- adam/commands/{cd.py → fs/cd.py} +2 -2
- adam/commands/{download_file.py → fs/download_file.py} +5 -5
- adam/commands/{find_files.py → fs/find_files.py} +4 -4
- adam/commands/{find_processes.py → fs/find_processes.py} +3 -3
- adam/commands/{head.py → fs/head.py} +2 -2
- adam/commands/{ls.py → fs/ls.py} +2 -2
- adam/commands/fs/ls_local.py +40 -0
- adam/commands/fs/rm.py +18 -0
- adam/commands/fs/rm_downloads.py +39 -0
- adam/commands/fs/rm_logs.py +38 -0
- adam/commands/{show → fs}/show_adam.py +1 -1
- adam/commands/intermediate_command.py +3 -0
- adam/commands/medusa/medusa_restore.py +2 -16
- adam/commands/medusa/utils_medusa.py +15 -0
- adam/commands/nodetool/__init__.py +0 -0
- adam/commands/{nodetool.py → nodetool/nodetool.py} +3 -8
- adam/commands/postgres/completions_p.py +22 -0
- adam/commands/postgres/postgres.py +7 -14
- adam/commands/postgres/postgres_databases.py +3 -3
- adam/commands/postgres/postgres_ls.py +1 -1
- adam/commands/postgres/utils_postgres.py +12 -2
- adam/commands/preview_table.py +1 -1
- adam/commands/reaper/reaper_schedule_activate.py +6 -2
- adam/commands/reaper/reaper_schedule_start.py +1 -2
- adam/commands/reaper/reaper_schedule_stop.py +1 -2
- adam/commands/reaper/utils_reaper.py +10 -1
- adam/commands/repair/repair_scan.py +0 -2
- adam/commands/repair/repair_stop.py +0 -1
- adam/commands/{show/show.py → show.py} +12 -11
- adam/config.py +4 -5
- adam/embedded_params.py +1 -1
- adam/repl.py +22 -9
- adam/repl_commands.py +50 -42
- adam/repl_session.py +9 -1
- adam/repl_state.py +16 -1
- adam/sql/async_executor.py +62 -0
- adam/sql/lark_completer.py +286 -0
- adam/sql/lark_parser.py +604 -0
- adam/sql/qingl.lark +1076 -0
- adam/sso/cred_cache.py +2 -5
- adam/utils.py +216 -79
- adam/utils_k8s/app_clusters.py +11 -4
- adam/utils_k8s/app_pods.py +10 -5
- adam/utils_k8s/cassandra_clusters.py +8 -4
- adam/utils_k8s/cassandra_nodes.py +14 -5
- adam/utils_k8s/k8s.py +9 -0
- adam/utils_k8s/kube_context.py +1 -4
- adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +8 -2
- adam/utils_k8s/pods.py +83 -24
- adam/utils_k8s/statefulsets.py +5 -2
- adam/utils_local.py +78 -2
- adam/utils_repl/appendable_completer.py +6 -0
- adam/utils_repl/repl_completer.py +51 -4
- adam/utils_sqlite.py +3 -8
- adam/version.py +1 -1
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
- kaqing-2.0.214.dist-info/RECORD +272 -0
- kaqing-2.0.214.dist-info/top_level.txt +2 -0
- teddy/__init__.py +0 -0
- teddy/lark_parser.py +436 -0
- teddy/lark_parser2.py +618 -0
- adam/commands/cql/cql_completions.py +0 -32
- adam/commands/export/export_select_x.py +0 -54
- adam/commands/logs.py +0 -37
- adam/commands/postgres/psql_completions.py +0 -11
- adam/commands/report.py +0 -61
- adam/commands/restart.py +0 -60
- adam/commands/show/show_processes.py +0 -49
- kaqing-2.0.184.dist-info/RECORD +0 -244
- kaqing-2.0.184.dist-info/top_level.txt +0 -1
- /adam/commands/{login.py → app/login.py} +0 -0
- /adam/commands/{show → cassandra}/__init__.py +0 -0
- /adam/commands/{show → cassandra}/show_cassandra_version.py +0 -0
- /adam/commands/{watch.py → cassandra/watch.py} +0 -0
- /adam/commands/{param_get.py → config/param_get.py} +0 -0
- /adam/commands/{param_set.py → config/param_set.py} +0 -0
- /adam/commands/{issues.py → diag/issues.py} +0 -0
- /adam/commands/{pwd.py → fs/pwd.py} +0 -0
- /adam/commands/{shell.py → fs/shell.py} +0 -0
- /adam/commands/{show → fs}/show_host.py +0 -0
- /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
- {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/entry_points.txt +0 -0
teddy/lark_parser.py
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
from copy import copy
|
|
2
|
+
import re
|
|
3
|
+
from typing import Union, cast
|
|
4
|
+
from lark import Lark, Token, Tree
|
|
5
|
+
from lark.lexer import TerminalDef
|
|
6
|
+
from lark.grammar import NonTerminal, Terminal
|
|
7
|
+
|
|
8
|
+
def log(msg: str = None, debug: bool = False, depth: int = 0):
|
|
9
|
+
if not msg:
|
|
10
|
+
print()
|
|
11
|
+
return
|
|
12
|
+
|
|
13
|
+
if debug:
|
|
14
|
+
print(depth * ' ' + msg)
|
|
15
|
+
|
|
16
|
+
class GNode:
|
|
17
|
+
def __init__(self, name: str, token: Token = None, choices: list[int] = []):
|
|
18
|
+
self.name = name
|
|
19
|
+
self.token = token
|
|
20
|
+
self.choices = choices
|
|
21
|
+
|
|
22
|
+
def __eq__(self, other: 'GNode'):
|
|
23
|
+
return self.__repr__() == other.__repr__()
|
|
24
|
+
|
|
25
|
+
def __hash__(self):
|
|
26
|
+
return hash(self.__repr__())
|
|
27
|
+
|
|
28
|
+
def __repr__(self):
|
|
29
|
+
n = self.name if self.name else f'{self.token}'
|
|
30
|
+
if self.choices:
|
|
31
|
+
n = f'{n}-{"-".join([f"{c}" for c in self.choices])}'
|
|
32
|
+
|
|
33
|
+
return n
|
|
34
|
+
|
|
35
|
+
def pname(self):
|
|
36
|
+
return self.name if self.name else f'{self.token}'
|
|
37
|
+
|
|
38
|
+
def choice(self, depth: int):
|
|
39
|
+
if depth < len(self.choices):
|
|
40
|
+
return self.choices[depth]
|
|
41
|
+
|
|
42
|
+
return -1
|
|
43
|
+
|
|
44
|
+
def drop_last_choice(self):
|
|
45
|
+
new_node = copy(self)
|
|
46
|
+
new_node.choices = self.choices[:-1]
|
|
47
|
+
|
|
48
|
+
return new_node
|
|
49
|
+
|
|
50
|
+
def parse(s: str):
|
|
51
|
+
name_n_choices = s.split('-')
|
|
52
|
+
choices = []
|
|
53
|
+
if len(name_n_choices) > 1:
|
|
54
|
+
choices = {int(k) for k in name_n_choices[1:]}
|
|
55
|
+
|
|
56
|
+
return GNode(name_n_choices[0], choices=choices)
|
|
57
|
+
|
|
58
|
+
def add_choice(self, choice: int):
|
|
59
|
+
self.choices.append(choice)
|
|
60
|
+
|
|
61
|
+
class GPath:
|
|
62
|
+
def __init__(self, nodes: list[GNode], complete: bool):
|
|
63
|
+
self.nodes = nodes
|
|
64
|
+
self.complete = complete
|
|
65
|
+
|
|
66
|
+
def __eq__(self, other: 'GPath'):
|
|
67
|
+
return self.__repr__() == other.__repr__()
|
|
68
|
+
|
|
69
|
+
def __hash__(self):
|
|
70
|
+
return hash(self.__repr__())
|
|
71
|
+
|
|
72
|
+
def __repr__(self):
|
|
73
|
+
r = '.'.join([f'{p}' for p in self.nodes])
|
|
74
|
+
|
|
75
|
+
return r
|
|
76
|
+
|
|
77
|
+
def token(self):
|
|
78
|
+
return self.nodes[-1] if self.nodes else GNode(None, choices={})
|
|
79
|
+
|
|
80
|
+
def append(self, node):
|
|
81
|
+
new_path = copy(self)
|
|
82
|
+
nodes = []
|
|
83
|
+
for n in self.nodes:
|
|
84
|
+
n1 = copy(n)
|
|
85
|
+
ss = []
|
|
86
|
+
for k in n.choices:
|
|
87
|
+
ss.append(k)
|
|
88
|
+
n1.choices = ss
|
|
89
|
+
nodes.append(n1)
|
|
90
|
+
nodes.append(node)
|
|
91
|
+
new_path.nodes = nodes
|
|
92
|
+
|
|
93
|
+
return new_path
|
|
94
|
+
|
|
95
|
+
def drop_last(self):
|
|
96
|
+
new_path = copy(self)
|
|
97
|
+
nodes = []
|
|
98
|
+
for n in self.nodes[:-1]:
|
|
99
|
+
nodes.append(n)
|
|
100
|
+
|
|
101
|
+
new_path.nodes = nodes
|
|
102
|
+
|
|
103
|
+
return new_path
|
|
104
|
+
|
|
105
|
+
def clone(self):
|
|
106
|
+
new_path = copy(self)
|
|
107
|
+
nodes = []
|
|
108
|
+
for n in self.nodes:
|
|
109
|
+
n1 = copy(n)
|
|
110
|
+
ss = []
|
|
111
|
+
for k in n.choices:
|
|
112
|
+
ss.append(k)
|
|
113
|
+
n1.choices = ss
|
|
114
|
+
nodes.append(n1)
|
|
115
|
+
new_path.nodes = nodes
|
|
116
|
+
|
|
117
|
+
return new_path
|
|
118
|
+
|
|
119
|
+
def terminal(self):
|
|
120
|
+
last_node = self.nodes[-1]
|
|
121
|
+
return last_node.pname()
|
|
122
|
+
|
|
123
|
+
def terminals(paths: set['GPath']):
|
|
124
|
+
return ','.join(p.terminal() for p in list(paths))
|
|
125
|
+
|
|
126
|
+
def with_new_choice(self, choice: int):
|
|
127
|
+
new_path = self.clone()
|
|
128
|
+
new_path.nodes[-1].add_choice(choice)
|
|
129
|
+
|
|
130
|
+
return new_path
|
|
131
|
+
|
|
132
|
+
def with_next_choice(self):
|
|
133
|
+
new_path = self.clone()
|
|
134
|
+
new_path.nodes[-1].choices[-1] += 1
|
|
135
|
+
|
|
136
|
+
return new_path
|
|
137
|
+
|
|
138
|
+
def drop_last_choice(self):
|
|
139
|
+
new_path = self.clone()
|
|
140
|
+
new_path.nodes[-1] = new_path.nodes[-1].drop_last_choice()
|
|
141
|
+
|
|
142
|
+
return new_path
|
|
143
|
+
|
|
144
|
+
class LarkParser:
|
|
145
|
+
show_returns = False
|
|
146
|
+
|
|
147
|
+
def __init__(self, grammar: str = None):
|
|
148
|
+
if not grammar:
|
|
149
|
+
grammar = """
|
|
150
|
+
start: expression
|
|
151
|
+
expression: term (("+" | "-") term)*
|
|
152
|
+
term: factor (("*" | "/") factor)*
|
|
153
|
+
factor: NUMBER | "(" expression ")"
|
|
154
|
+
NUMBER: /[0-9]+/
|
|
155
|
+
%ignore " "
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
parser = Lark(grammar, start='start')
|
|
159
|
+
self.parser = parser
|
|
160
|
+
|
|
161
|
+
self.rules = {rule_def[0]: rule_def[2] for rule_def in parser.grammar.rule_defs}
|
|
162
|
+
self.terminals = {rule_def[0]: rule_def[1] for rule_def in parser.grammar.term_defs}
|
|
163
|
+
self.rules_by_name1 = {rule_def[0]: rule_def[1] for rule_def in parser.grammar.rule_defs}
|
|
164
|
+
self.rules_by_name2 = {rule_def[0]: rule_def[3] for rule_def in parser.grammar.rule_defs}
|
|
165
|
+
|
|
166
|
+
self.trees: dict[str, Tree] = {}
|
|
167
|
+
|
|
168
|
+
def find_next_terminals(self, path: GPath, debug=False):
|
|
169
|
+
if path == 'start':
|
|
170
|
+
return self.visit_current(LarkParser.build_path(path), debug=debug)
|
|
171
|
+
|
|
172
|
+
if isinstance(path, set):
|
|
173
|
+
paths = set()
|
|
174
|
+
|
|
175
|
+
for p in list(path):
|
|
176
|
+
paths |= self.visit_next(p, debug=debug)
|
|
177
|
+
|
|
178
|
+
return paths
|
|
179
|
+
elif isinstance(path, str):
|
|
180
|
+
path = LarkParser.build_path(path)
|
|
181
|
+
|
|
182
|
+
if debug: print(f'find_next_terminals({path}, {path.token().token})')
|
|
183
|
+
|
|
184
|
+
return self.visit_next(path, debug=debug)
|
|
185
|
+
|
|
186
|
+
def visit_current(self, path: GPath, tree: Tree = None, debug=False):
|
|
187
|
+
paths: set[GPath] = set()
|
|
188
|
+
|
|
189
|
+
if debug: print(f'visit_expansion({path}, {path.token().token}), {path.nodes[-1].choices}')
|
|
190
|
+
if not tree:
|
|
191
|
+
tree, _ = self.tree_by_choices(path, debug=debug)
|
|
192
|
+
|
|
193
|
+
if isinstance(tree, Token):
|
|
194
|
+
if debug: print('token', tree)
|
|
195
|
+
if path.nodes[-1].token:
|
|
196
|
+
path = path.drop_last()
|
|
197
|
+
|
|
198
|
+
p = path.append(GNode(name=self.token_name_from_raw(f'{tree}'), token=tree, choices=[]))
|
|
199
|
+
if LarkParser.show_returns: print('<- ', tree.value, '\t\t', p)
|
|
200
|
+
paths.add(p)
|
|
201
|
+
elif isinstance(tree, Terminal):
|
|
202
|
+
if debug: print('terminal', tree.name)
|
|
203
|
+
p = path.append(GNode(tree.name, choices=[]))
|
|
204
|
+
if LarkParser.show_returns: print('<- ', tree.name, '\t\t', p)
|
|
205
|
+
paths.add(p)
|
|
206
|
+
elif isinstance(tree, NonTerminal):
|
|
207
|
+
if debug: print('non-termial', tree.name, tree)
|
|
208
|
+
paths |= self.visit_current(path.append(GNode(tree.name, choices=[])), debug=debug)
|
|
209
|
+
elif isinstance(tree, tuple):
|
|
210
|
+
paths |= self.visit_current(path, tree=tree[0], debug=debug)
|
|
211
|
+
elif not tree:
|
|
212
|
+
raise Exception(f'null tree at {path}')
|
|
213
|
+
elif tree.data == 'expr':
|
|
214
|
+
paths |= self.visit_current(path.with_new_choice(0), tree=tree.children[0], debug=debug)
|
|
215
|
+
|
|
216
|
+
if cast(Token, tree.children[1]).value in ['*', '?']:
|
|
217
|
+
paths |= self.visit_next(path, debug=debug)
|
|
218
|
+
elif tree.data == 'value':
|
|
219
|
+
# print('value')
|
|
220
|
+
for child in tree.children:
|
|
221
|
+
paths |= self.visit_current(path, tree=child, debug=debug)
|
|
222
|
+
elif tree.data == 'range':
|
|
223
|
+
# print('range')
|
|
224
|
+
token0: Token = tree.children[0]
|
|
225
|
+
token1: Token = tree.children[1]
|
|
226
|
+
if token0.value == '"0"' and token1.value == '"9"':
|
|
227
|
+
p = path.append(GNode(name=self.token_name_from_raw(f'{token0}'), token=token0, choices=[]))
|
|
228
|
+
if LarkParser.show_returns: print('<- ', 0, '\t\t', p)
|
|
229
|
+
paths.add(p)
|
|
230
|
+
else:
|
|
231
|
+
raise Exception('not implented')
|
|
232
|
+
for i in range(ord(token0.value.strip('"')), ord(token1.value.strip('"')) + 1):
|
|
233
|
+
ch = chr(i)
|
|
234
|
+
p = path.append(GNode(name=self.token_name_from_raw(f'{token0}'), token=token0, choices=[]))
|
|
235
|
+
# p = path.append(GNode(name=self.token_name_from_raw(f'{tree}'), token=tree, choices=[]))
|
|
236
|
+
if LarkParser.show_returns: print('<- ', ch, '\t\t', p)
|
|
237
|
+
paths.add(p)
|
|
238
|
+
elif tree.data == 'literal':
|
|
239
|
+
# print('literal')
|
|
240
|
+
for child in tree.children:
|
|
241
|
+
paths |= self.visit_current(path, tree=child, debug=debug)
|
|
242
|
+
elif tree.data == 'expansions':
|
|
243
|
+
for i, child in enumerate(tree.children):
|
|
244
|
+
paths |= self.visit_current(path.with_new_choice(i), tree=child, debug=debug)
|
|
245
|
+
elif tree.data == 'expansion':
|
|
246
|
+
paths |= self.visit_current(path.with_new_choice(0), tree=tree.children[0], debug=debug)
|
|
247
|
+
|
|
248
|
+
return paths
|
|
249
|
+
|
|
250
|
+
def visit_next(self, path: GPath, debug=False):
|
|
251
|
+
paths: set[GPath] = set()
|
|
252
|
+
|
|
253
|
+
if not path.nodes:
|
|
254
|
+
return paths
|
|
255
|
+
|
|
256
|
+
path = self.strip_terminal_nodes(path)
|
|
257
|
+
node = path.nodes[-1]
|
|
258
|
+
|
|
259
|
+
me: Tree
|
|
260
|
+
parent: Tree
|
|
261
|
+
me, parent = self.tree_by_choices(path)
|
|
262
|
+
|
|
263
|
+
check_parent = True
|
|
264
|
+
if isinstance(me, Tree) and me.data == 'expr' and me.children[1] == '*':
|
|
265
|
+
if debug: print(' add expr repeat ', path)
|
|
266
|
+
paths |= self.visit_current(path.with_new_choice(0), debug=debug)
|
|
267
|
+
|
|
268
|
+
if isinstance(parent, Tree) and parent.data == 'expansion' and (node.choices[-1] + 1) < len(parent.children):
|
|
269
|
+
np = path.with_next_choice()
|
|
270
|
+
if debug: print(' move to next sibling ', np)
|
|
271
|
+
paths |= self.visit_current(np, debug=debug)
|
|
272
|
+
check_parent = False
|
|
273
|
+
|
|
274
|
+
if check_parent:
|
|
275
|
+
if len(node.choices) > 0:
|
|
276
|
+
p = path.drop_last_choice()
|
|
277
|
+
if debug: print(' move up to parent tree', p)
|
|
278
|
+
paths |= self.visit_next(p, debug=debug)
|
|
279
|
+
else:
|
|
280
|
+
path = path.drop_last()
|
|
281
|
+
if debug: print(' move up to parent node', path)
|
|
282
|
+
paths |= self.visit_next(path, debug=debug)
|
|
283
|
+
|
|
284
|
+
return paths
|
|
285
|
+
|
|
286
|
+
def tree_by_choices(self, path: GPath, debug=False):
|
|
287
|
+
debug = False
|
|
288
|
+
|
|
289
|
+
c = f'{path.nodes[-1]}'
|
|
290
|
+
p = f'{path.nodes[-1].drop_last_choice()}'
|
|
291
|
+
if c not in self.trees:
|
|
292
|
+
for key, value in self.trees_by_choices(path, debug=debug).items():
|
|
293
|
+
if not key:
|
|
294
|
+
self.trees[f'{path.token().name}'] = value
|
|
295
|
+
else:
|
|
296
|
+
self.trees[f'{path.token().name}-{key}'] = value
|
|
297
|
+
|
|
298
|
+
return self.trees[c], self.trees[p]
|
|
299
|
+
|
|
300
|
+
def trees_by_choices(self, path_or_tree: Union[GPath, Tree], choices: list[int] = [], depth: int = 0, debug=False):
|
|
301
|
+
if debug: print(f'trees_by_choices({path_or_tree}, {choices})')
|
|
302
|
+
|
|
303
|
+
if isinstance(path_or_tree, GPath):
|
|
304
|
+
n = self.find_last_rule(path_or_tree)
|
|
305
|
+
tree = self.rules[n.name]
|
|
306
|
+
else:
|
|
307
|
+
tree = path_or_tree
|
|
308
|
+
|
|
309
|
+
trees: dict[str, Tree] = {}
|
|
310
|
+
|
|
311
|
+
if isinstance(tree, Token):
|
|
312
|
+
if debug: log('tree', debug, depth)
|
|
313
|
+
pass
|
|
314
|
+
elif isinstance(tree, Terminal):
|
|
315
|
+
if debug: log('terminal', debug, depth)
|
|
316
|
+
|
|
317
|
+
choices_str = '-'.join([f"{c}" for c in choices])
|
|
318
|
+
trees[choices_str] = tree
|
|
319
|
+
|
|
320
|
+
pass
|
|
321
|
+
elif isinstance(tree, NonTerminal):
|
|
322
|
+
if debug: log('non-terminal', debug, depth)
|
|
323
|
+
pass
|
|
324
|
+
elif isinstance(tree, tuple):
|
|
325
|
+
if debug: log('tuple', debug, depth)
|
|
326
|
+
trees |= self.trees_by_choices(tree[0], choices, depth=depth, debug=debug)
|
|
327
|
+
elif tree.data == 'expr':
|
|
328
|
+
if debug: log('expr', debug, depth)
|
|
329
|
+
choices_str = '-'.join([f"{c}" for c in choices])
|
|
330
|
+
trees[choices_str] = tree
|
|
331
|
+
|
|
332
|
+
for child in tree.children[:1]:
|
|
333
|
+
trees |= self.trees_by_choices(child, choices + [0], depth=depth+1, debug=debug)
|
|
334
|
+
elif tree.data == 'value':
|
|
335
|
+
if debug: log('value', debug, depth)
|
|
336
|
+
|
|
337
|
+
choices_str = '-'.join([f"{c}" for c in choices])
|
|
338
|
+
trees[choices_str] = tree
|
|
339
|
+
|
|
340
|
+
for child in tree.children:
|
|
341
|
+
trees |= self.trees_by_choices(child, choices, depth=depth+1, debug=debug)
|
|
342
|
+
elif tree.data == 'literal':
|
|
343
|
+
if debug: log('literal', debug, depth)
|
|
344
|
+
|
|
345
|
+
choices_str = '-'.join([f"{c}" for c in choices])
|
|
346
|
+
trees[choices_str] = tree
|
|
347
|
+
|
|
348
|
+
for child in tree.children:
|
|
349
|
+
trees |= self.trees_by_choices(child, choices, depth=depth+1, debug=debug)
|
|
350
|
+
elif tree.data == 'expansions':
|
|
351
|
+
if debug: log('expansions', debug, depth)
|
|
352
|
+
|
|
353
|
+
choices_str = '-'.join([f"{c}" for c in choices])
|
|
354
|
+
trees[choices_str] = tree
|
|
355
|
+
for i, child in enumerate(tree.children):
|
|
356
|
+
trees |= self.trees_by_choices(child, choices + [i], depth=depth+1, debug=debug)
|
|
357
|
+
elif tree.data == 'expansion':
|
|
358
|
+
if debug: log('expansion', debug, depth)
|
|
359
|
+
|
|
360
|
+
choices_str = '-'.join([f"{c}" for c in choices])
|
|
361
|
+
trees[choices_str] = tree
|
|
362
|
+
for i, child in enumerate(tree.children):
|
|
363
|
+
trees |= self.trees_by_choices(child, choices + [i], depth=depth+1, debug=debug)
|
|
364
|
+
else:
|
|
365
|
+
if debug: log('else', debug, depth)
|
|
366
|
+
|
|
367
|
+
return trees
|
|
368
|
+
|
|
369
|
+
def strip_terminal_nodes(self, path: GPath):
|
|
370
|
+
while path.nodes[-1].name not in self.rules:
|
|
371
|
+
path = path.drop_last()
|
|
372
|
+
|
|
373
|
+
return path
|
|
374
|
+
|
|
375
|
+
def find_last_rule(self, path: GPath):
|
|
376
|
+
for n in reversed(path.nodes):
|
|
377
|
+
if n.name in self.rules:
|
|
378
|
+
return n
|
|
379
|
+
|
|
380
|
+
return None
|
|
381
|
+
|
|
382
|
+
def build_path(p: str):
|
|
383
|
+
nodes = []
|
|
384
|
+
for n in p.split('.'):
|
|
385
|
+
name_n_choices = n.split('-')
|
|
386
|
+
nodes.append(GNode(name_n_choices[0], choices=[int(c) for c in name_n_choices[1:]]))
|
|
387
|
+
|
|
388
|
+
return GPath(nodes, False)
|
|
389
|
+
|
|
390
|
+
def token_name(self, token):
|
|
391
|
+
td: TerminalDef = None
|
|
392
|
+
for t in reversed(self.parser.terminals):
|
|
393
|
+
td = t
|
|
394
|
+
# print(td)
|
|
395
|
+
if td.pattern.raw == '/./':
|
|
396
|
+
if token == '.':
|
|
397
|
+
return td.name
|
|
398
|
+
elif re.fullmatch(td.pattern.to_regexp(), token):
|
|
399
|
+
return td.name
|
|
400
|
+
|
|
401
|
+
raise Exception('cannot resolve string to a token')
|
|
402
|
+
|
|
403
|
+
def token_name_from_raw(self, raw_token):
|
|
404
|
+
td: TerminalDef = None
|
|
405
|
+
for t in reversed(self.parser.terminals):
|
|
406
|
+
if t.pattern.raw == raw_token:
|
|
407
|
+
td = t
|
|
408
|
+
return td.name
|
|
409
|
+
|
|
410
|
+
return self.token_name(raw_token.strip('"'))
|
|
411
|
+
|
|
412
|
+
def parse(self, s: str, debug=False):
|
|
413
|
+
ps = 'start'
|
|
414
|
+
ps = self.find_next_terminals(ps, debug=debug)
|
|
415
|
+
|
|
416
|
+
for token in self.parser.lex(s):
|
|
417
|
+
token_name = self.token_name(token)
|
|
418
|
+
|
|
419
|
+
ps = self.choose(ps, token_name)
|
|
420
|
+
ps = self.find_next_terminals(ps, debug=debug)
|
|
421
|
+
|
|
422
|
+
terminals = {p.terminal().strip('"') for p in ps}
|
|
423
|
+
|
|
424
|
+
# print(terminals)
|
|
425
|
+
|
|
426
|
+
return terminals
|
|
427
|
+
|
|
428
|
+
def choose(self, paths: list[GPath], token: str):
|
|
429
|
+
if LarkParser.show_returns: print(f'\n{token}\t-----------------------------')
|
|
430
|
+
|
|
431
|
+
ps = set()
|
|
432
|
+
for p in paths:
|
|
433
|
+
if f'{p.token()}' == token:
|
|
434
|
+
ps.add(p)
|
|
435
|
+
|
|
436
|
+
return ps
|