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.

Files changed (152) hide show
  1. adam/app_session.py +1 -1
  2. adam/batch.py +15 -15
  3. adam/commands/app/app.py +2 -2
  4. adam/commands/app/show_app_actions.py +1 -1
  5. adam/commands/{show → app}/show_login.py +1 -1
  6. adam/commands/app/utils_app.py +9 -1
  7. adam/commands/audit/audit.py +6 -20
  8. adam/commands/audit/audit_repair_tables.py +1 -1
  9. adam/commands/audit/audit_run.py +1 -1
  10. adam/commands/audit/completions_l.py +15 -0
  11. adam/commands/audit/show_last10.py +0 -1
  12. adam/commands/bash/bash.py +1 -1
  13. adam/commands/bash/utils_bash.py +1 -1
  14. adam/commands/cassandra/download_cassandra_log.py +45 -0
  15. adam/commands/cassandra/restart_cluster.py +47 -0
  16. adam/commands/cassandra/restart_node.py +51 -0
  17. adam/commands/cassandra/restart_nodes.py +47 -0
  18. adam/commands/{rollout.py → cassandra/rollout.py} +1 -1
  19. adam/commands/{show → cassandra}/show_cassandra_repairs.py +5 -3
  20. adam/commands/{show → cassandra}/show_cassandra_status.py +22 -15
  21. adam/commands/cassandra/show_processes.py +50 -0
  22. adam/commands/{show → cassandra}/show_storage.py +10 -8
  23. adam/commands/cli/__init__.py +0 -0
  24. adam/commands/{cli_commands.py → cli/cli_commands.py} +6 -1
  25. adam/commands/{clipboard_copy.py → cli/clipboard_copy.py} +2 -2
  26. adam/commands/{show/show_commands.py → cli/show_cli_commands.py} +2 -2
  27. adam/commands/command.py +22 -9
  28. adam/commands/commands_utils.py +14 -6
  29. adam/commands/config/__init__.py +0 -0
  30. adam/commands/{show → config}/show_params.py +1 -1
  31. adam/commands/{alter_tables.py → cql/alter_tables.py} +1 -1
  32. adam/commands/cql/completions_c.py +29 -0
  33. adam/commands/cql/cqlsh.py +2 -6
  34. adam/commands/cql/utils_cql.py +26 -17
  35. adam/commands/debug/__init__.py +0 -0
  36. adam/commands/debug/debug.py +22 -0
  37. adam/commands/debug/debug_completes.py +35 -0
  38. adam/commands/debug/debug_timings.py +35 -0
  39. adam/commands/debug/show_offloaded_completes.py +45 -0
  40. adam/commands/devices/device.py +30 -4
  41. adam/commands/devices/device_app.py +1 -1
  42. adam/commands/devices/device_export.py +5 -2
  43. adam/commands/devices/device_postgres.py +13 -3
  44. adam/commands/devices/devices.py +1 -1
  45. adam/commands/diag/__init__.py +0 -0
  46. adam/commands/{check.py → diag/check.py} +1 -1
  47. adam/commands/diag/generate_report.py +52 -0
  48. adam/commands/export/completions_x.py +11 -0
  49. adam/commands/export/download_export_session.py +2 -1
  50. adam/commands/export/export.py +0 -16
  51. adam/commands/export/export_databases.py +16 -10
  52. adam/commands/export/export_select.py +8 -33
  53. adam/commands/export/export_sessions.py +12 -11
  54. adam/commands/export/export_use.py +3 -3
  55. adam/commands/export/export_x_select.py +48 -0
  56. adam/commands/export/exporter.py +140 -53
  57. adam/commands/export/import_files.py +2 -2
  58. adam/commands/export/import_session.py +0 -4
  59. adam/commands/export/importer.py +11 -11
  60. adam/commands/export/importer_athena.py +15 -35
  61. adam/commands/export/importer_sqlite.py +19 -8
  62. adam/commands/export/show_column_counts.py +10 -10
  63. adam/commands/export/show_export_databases.py +2 -1
  64. adam/commands/export/show_export_session.py +1 -1
  65. adam/commands/export/show_export_sessions.py +1 -1
  66. adam/commands/export/utils_export.py +38 -15
  67. adam/commands/fs/__init__.py +0 -0
  68. adam/commands/{cat.py → fs/cat.py} +2 -2
  69. adam/commands/fs/cat_local.py +42 -0
  70. adam/commands/{cd.py → fs/cd.py} +2 -2
  71. adam/commands/{download_file.py → fs/download_file.py} +5 -5
  72. adam/commands/{find_files.py → fs/find_files.py} +4 -4
  73. adam/commands/{find_processes.py → fs/find_processes.py} +3 -3
  74. adam/commands/{head.py → fs/head.py} +2 -2
  75. adam/commands/{ls.py → fs/ls.py} +2 -2
  76. adam/commands/fs/ls_local.py +40 -0
  77. adam/commands/fs/rm.py +18 -0
  78. adam/commands/fs/rm_downloads.py +39 -0
  79. adam/commands/fs/rm_logs.py +38 -0
  80. adam/commands/{show → fs}/show_adam.py +1 -1
  81. adam/commands/intermediate_command.py +3 -0
  82. adam/commands/medusa/medusa_restore.py +2 -16
  83. adam/commands/medusa/utils_medusa.py +15 -0
  84. adam/commands/nodetool/__init__.py +0 -0
  85. adam/commands/{nodetool.py → nodetool/nodetool.py} +3 -8
  86. adam/commands/postgres/completions_p.py +22 -0
  87. adam/commands/postgres/postgres.py +7 -14
  88. adam/commands/postgres/postgres_databases.py +3 -3
  89. adam/commands/postgres/postgres_ls.py +1 -1
  90. adam/commands/postgres/utils_postgres.py +12 -2
  91. adam/commands/preview_table.py +1 -1
  92. adam/commands/reaper/reaper_schedule_activate.py +6 -2
  93. adam/commands/reaper/reaper_schedule_start.py +1 -2
  94. adam/commands/reaper/reaper_schedule_stop.py +1 -2
  95. adam/commands/reaper/utils_reaper.py +10 -1
  96. adam/commands/repair/repair_scan.py +0 -2
  97. adam/commands/repair/repair_stop.py +0 -1
  98. adam/commands/{show/show.py → show.py} +12 -11
  99. adam/config.py +4 -5
  100. adam/embedded_params.py +1 -1
  101. adam/repl.py +22 -9
  102. adam/repl_commands.py +50 -42
  103. adam/repl_session.py +9 -1
  104. adam/repl_state.py +16 -1
  105. adam/sql/async_executor.py +62 -0
  106. adam/sql/lark_completer.py +286 -0
  107. adam/sql/lark_parser.py +604 -0
  108. adam/sql/qingl.lark +1076 -0
  109. adam/sso/cred_cache.py +2 -5
  110. adam/utils.py +216 -79
  111. adam/utils_k8s/app_clusters.py +11 -4
  112. adam/utils_k8s/app_pods.py +10 -5
  113. adam/utils_k8s/cassandra_clusters.py +8 -4
  114. adam/utils_k8s/cassandra_nodes.py +14 -5
  115. adam/utils_k8s/k8s.py +9 -0
  116. adam/utils_k8s/kube_context.py +1 -4
  117. adam/{pod_exec_result.py → utils_k8s/pod_exec_result.py} +8 -2
  118. adam/utils_k8s/pods.py +83 -24
  119. adam/utils_k8s/statefulsets.py +5 -2
  120. adam/utils_local.py +78 -2
  121. adam/utils_repl/appendable_completer.py +6 -0
  122. adam/utils_repl/repl_completer.py +51 -4
  123. adam/utils_sqlite.py +3 -8
  124. adam/version.py +1 -1
  125. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/METADATA +1 -1
  126. kaqing-2.0.214.dist-info/RECORD +272 -0
  127. kaqing-2.0.214.dist-info/top_level.txt +2 -0
  128. teddy/__init__.py +0 -0
  129. teddy/lark_parser.py +436 -0
  130. teddy/lark_parser2.py +618 -0
  131. adam/commands/cql/cql_completions.py +0 -32
  132. adam/commands/export/export_select_x.py +0 -54
  133. adam/commands/logs.py +0 -37
  134. adam/commands/postgres/psql_completions.py +0 -11
  135. adam/commands/report.py +0 -61
  136. adam/commands/restart.py +0 -60
  137. adam/commands/show/show_processes.py +0 -49
  138. kaqing-2.0.184.dist-info/RECORD +0 -244
  139. kaqing-2.0.184.dist-info/top_level.txt +0 -1
  140. /adam/commands/{login.py → app/login.py} +0 -0
  141. /adam/commands/{show → cassandra}/__init__.py +0 -0
  142. /adam/commands/{show → cassandra}/show_cassandra_version.py +0 -0
  143. /adam/commands/{watch.py → cassandra/watch.py} +0 -0
  144. /adam/commands/{param_get.py → config/param_get.py} +0 -0
  145. /adam/commands/{param_set.py → config/param_set.py} +0 -0
  146. /adam/commands/{issues.py → diag/issues.py} +0 -0
  147. /adam/commands/{pwd.py → fs/pwd.py} +0 -0
  148. /adam/commands/{shell.py → fs/shell.py} +0 -0
  149. /adam/commands/{show → fs}/show_host.py +0 -0
  150. /adam/commands/{nodetool_commands.py → nodetool/nodetool_commands.py} +0 -0
  151. {kaqing-2.0.184.dist-info → kaqing-2.0.214.dist-info}/WHEEL +0 -0
  152. {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