dshellInterpreter 0.2.21.7__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.
- Dshell/DISCORD_COMMANDS/__init__.py +7 -0
- Dshell/DISCORD_COMMANDS/dshell_channel.py +612 -0
- Dshell/DISCORD_COMMANDS/dshell_interaction.py +89 -0
- Dshell/DISCORD_COMMANDS/dshell_member.py +274 -0
- Dshell/DISCORD_COMMANDS/dshell_message.py +444 -0
- Dshell/DISCORD_COMMANDS/dshell_pastbin.py +28 -0
- Dshell/DISCORD_COMMANDS/dshell_role.py +128 -0
- Dshell/DISCORD_COMMANDS/utils/__init__.py +8 -0
- Dshell/DISCORD_COMMANDS/utils/utils_global.py +155 -0
- Dshell/DISCORD_COMMANDS/utils/utils_list.py +109 -0
- Dshell/DISCORD_COMMANDS/utils/utils_member.py +30 -0
- Dshell/DISCORD_COMMANDS/utils/utils_message.py +78 -0
- Dshell/DISCORD_COMMANDS/utils/utils_permissions.py +94 -0
- Dshell/DISCORD_COMMANDS/utils/utils_string.py +157 -0
- Dshell/DISCORD_COMMANDS/utils/utils_thread.py +35 -0
- Dshell/_DshellInterpreteur/__init__.py +4 -0
- Dshell/_DshellInterpreteur/cached_messages.py +4 -0
- Dshell/_DshellInterpreteur/dshell_arguments.py +74 -0
- Dshell/_DshellInterpreteur/dshell_interpreter.py +671 -0
- Dshell/_DshellInterpreteur/errors.py +8 -0
- Dshell/_DshellParser/__init__.py +2 -0
- Dshell/_DshellParser/ast_nodes.py +675 -0
- Dshell/_DshellParser/dshell_parser.py +408 -0
- Dshell/_DshellTokenizer/__init__.py +4 -0
- Dshell/_DshellTokenizer/dshell_keywords.py +193 -0
- Dshell/_DshellTokenizer/dshell_token_type.py +58 -0
- Dshell/_DshellTokenizer/dshell_tokenizer.py +146 -0
- Dshell/__init__.py +3 -0
- Dshell/_utils.py +1 -0
- dshellinterpreter-0.2.21.7.dist-info/METADATA +37 -0
- dshellinterpreter-0.2.21.7.dist-info/RECORD +34 -0
- dshellinterpreter-0.2.21.7.dist-info/WHEEL +5 -0
- dshellinterpreter-0.2.21.7.dist-info/licenses/LICENSE +21 -0
- dshellinterpreter-0.2.21.7.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
"parse",
|
|
3
|
+
"parser_inline",
|
|
4
|
+
"to_postfix",
|
|
5
|
+
"print_ast",
|
|
6
|
+
"ast_to_dict",
|
|
7
|
+
]
|
|
8
|
+
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
11
|
+
from .ast_nodes import *
|
|
12
|
+
from .._DshellTokenizer import dshell_operators
|
|
13
|
+
from .._DshellTokenizer.dshell_token_type import DshellTokenType as DTT
|
|
14
|
+
from .._DshellTokenizer.dshell_token_type import Token
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[ASTNode], int]:
|
|
18
|
+
"""
|
|
19
|
+
Parse the list of tokens and return a list of AST nodes.
|
|
20
|
+
:param token_lines: table of tokens
|
|
21
|
+
:param start_node: the node where to start the parsing
|
|
22
|
+
"""
|
|
23
|
+
pointeur = 0 # pointeur sur les listes de tokens pour savoir ou parser
|
|
24
|
+
blocks = [start_node] # liste d'imbrication des blocks pour gérer l'imbrication
|
|
25
|
+
len_token_lines = len(token_lines)
|
|
26
|
+
|
|
27
|
+
while pointeur < len_token_lines:
|
|
28
|
+
|
|
29
|
+
tokens_by_line = token_lines[pointeur] # on récupère la liste de token par rapport au pointeur
|
|
30
|
+
first_token_line = tokens_by_line[0] # on récupère le premier token de la ligne
|
|
31
|
+
last_block = blocks[-1]
|
|
32
|
+
|
|
33
|
+
if first_token_line.type == DTT.COMMAND: # si le token est une comande
|
|
34
|
+
body = tokens_by_line[1:] # on récupère ses arguments
|
|
35
|
+
last_block.body.append(CommandNode(first_token_line.value,
|
|
36
|
+
ArgsCommandNode(body))) # on ajoute la commande au body du dernier bloc
|
|
37
|
+
|
|
38
|
+
############################## DSHELL KEYWORDS ##############################
|
|
39
|
+
|
|
40
|
+
elif first_token_line.type == DTT.KEYWORD: # si c'est un mot clé
|
|
41
|
+
|
|
42
|
+
if first_token_line.value == 'if': # si c'est une condition
|
|
43
|
+
if len(tokens_by_line) <= 1:
|
|
44
|
+
raise SyntaxError(f'[IF] Take one or more arguments on line {first_token_line.position} !')
|
|
45
|
+
|
|
46
|
+
if_node = IfNode(condition=tokens_by_line[1:],
|
|
47
|
+
body=[]) # on crée la node avec les arguments de condition du if
|
|
48
|
+
last_block.body.append(if_node)
|
|
49
|
+
_, p = parse(token_lines[pointeur + 1:],
|
|
50
|
+
if_node) # on parse le reste du code avec la node if_node comme commancement du nouveau parsing
|
|
51
|
+
pointeur += p + 1 # essentielle pour ne pas parser les lignes déjà faite
|
|
52
|
+
|
|
53
|
+
elif first_token_line.value == '#if':
|
|
54
|
+
if not isinstance(last_block, (IfNode, ElseNode, ElifNode)):
|
|
55
|
+
raise SyntaxError(f'[#IF] No conditional bloc open on line {first_token_line.position} !')
|
|
56
|
+
|
|
57
|
+
if isinstance(last_block, (ElifNode, ElseNode)):
|
|
58
|
+
|
|
59
|
+
while isinstance(last_block, (ElifNode, ElseNode)):
|
|
60
|
+
blocks.pop()
|
|
61
|
+
last_block = blocks[-1]
|
|
62
|
+
blocks.pop()
|
|
63
|
+
return blocks, pointeur
|
|
64
|
+
|
|
65
|
+
elif first_token_line.value == 'elif':
|
|
66
|
+
if not isinstance(last_block, (IfNode, ElifNode)):
|
|
67
|
+
raise SyntaxError(f'[ELIF] No conditional bloc open on line {first_token_line.position} !')
|
|
68
|
+
if len(tokens_by_line) <= 1:
|
|
69
|
+
raise SyntaxError(f'[ELIF] Take one or more arguments on line {first_token_line.position} !')
|
|
70
|
+
elif_node = ElifNode(condition=tokens_by_line[1:], body=[],
|
|
71
|
+
parent=last_block if isinstance(last_block, IfNode) else last_block.parent)
|
|
72
|
+
|
|
73
|
+
if isinstance(last_block, ElifNode):
|
|
74
|
+
last_block.parent.elif_nodes.append(elif_node)
|
|
75
|
+
else:
|
|
76
|
+
if last_block.elif_nodes is None:
|
|
77
|
+
last_block.elif_nodes = [elif_node]
|
|
78
|
+
else:
|
|
79
|
+
last_block.elif_nodes.append(elif_node)
|
|
80
|
+
blocks.append(elif_node)
|
|
81
|
+
|
|
82
|
+
elif first_token_line.value == 'else':
|
|
83
|
+
if not isinstance(last_block, (IfNode, ElifNode)):
|
|
84
|
+
raise SyntaxError(f'[ELSE] No conditional bloc open on line {first_token_line.position} !')
|
|
85
|
+
|
|
86
|
+
if isinstance(last_block, ElseNode) and last_block.else_body is not None:
|
|
87
|
+
raise SyntaxError(f'[ELSE] already define !')
|
|
88
|
+
|
|
89
|
+
else_node = ElseNode(body=[])
|
|
90
|
+
if isinstance(last_block, ElifNode): # si le dernier bloc est un elif
|
|
91
|
+
last_block.parent.else_body = else_node # on ajoute le bloc else à son parent (qui est le dernier if)
|
|
92
|
+
else:
|
|
93
|
+
last_block.else_body = else_node # une fois le parsing fini, on l'ajoute au dernier bloc
|
|
94
|
+
blocks.append(else_node)
|
|
95
|
+
|
|
96
|
+
elif first_token_line.value == 'loop':
|
|
97
|
+
if len(tokens_by_line) <= 2:
|
|
98
|
+
raise SyntaxError(f'[LOOP] Take two arguments on line {first_token_line.position} !')
|
|
99
|
+
if tokens_by_line[1].type != DTT.IDENT:
|
|
100
|
+
raise TypeError(f'[LOOP] the variable given must be a ident, '
|
|
101
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
102
|
+
if tokens_by_line[2].type not in (DTT.IDENT, DTT.STR, DTT.INT, DTT.FLOAT, DTT.LIST, DTT.EVAL_GROUP):
|
|
103
|
+
raise TypeError(f'[LOOP] the iterator must be a ident, string, integer, float or list, '
|
|
104
|
+
f'not {tokens_by_line[2].type} in line {tokens_by_line[2].position}')
|
|
105
|
+
|
|
106
|
+
loop_node = LoopNode(VarNode(tokens_by_line[1], to_postfix(tokens_by_line[2:])), body=[])
|
|
107
|
+
last_block.body.append(loop_node)
|
|
108
|
+
_, p = parse(token_lines[pointeur + 1:],
|
|
109
|
+
loop_node) # on parse tous ce qu'il y a après l'instruction loop
|
|
110
|
+
pointeur += p + 1
|
|
111
|
+
|
|
112
|
+
elif first_token_line.value == '#loop': # si rencontré
|
|
113
|
+
if not isinstance(last_block, LoopNode):
|
|
114
|
+
raise SyntaxError(f'[#LOOP] No loop open on line {first_token_line.position} !')
|
|
115
|
+
|
|
116
|
+
blocks.pop()
|
|
117
|
+
return blocks, pointeur # on renvoie les informations parsé à la dernière loop ouverte
|
|
118
|
+
|
|
119
|
+
elif first_token_line.value == 'var':
|
|
120
|
+
if len(tokens_by_line) <= 2:
|
|
121
|
+
raise SyntaxError(f'[VAR] Take two arguments on line {first_token_line.position} !')
|
|
122
|
+
if tokens_by_line[1].type != DTT.IDENT:
|
|
123
|
+
raise TypeError(f'[VAR] the variable given must be a ident, '
|
|
124
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
125
|
+
|
|
126
|
+
var_node = VarNode(name=tokens_by_line[1], body=[])
|
|
127
|
+
last_block.body.append(var_node)
|
|
128
|
+
result, status = parser_inline(tokens_by_line[
|
|
129
|
+
2:]) # on fait en sorte de mettre les tokens de la ligne séparé par des retour à la ligne à chaque condition/else
|
|
130
|
+
if status:
|
|
131
|
+
parse(result, var_node) # on parse le tout dans la variable
|
|
132
|
+
else:
|
|
133
|
+
# var_node.body = parse(result, StartNode([]))[0][0].body
|
|
134
|
+
var_node.body = result[0]
|
|
135
|
+
|
|
136
|
+
elif first_token_line.value == 'sleep':
|
|
137
|
+
if len(tokens_by_line) <= 1:
|
|
138
|
+
raise SyntaxError(f'[SLEEP] Take one arguments on line {first_token_line.position} !')
|
|
139
|
+
if tokens_by_line[1].type != DTT.INT:
|
|
140
|
+
raise TypeError(f'[SLEEP] the variable given must be an integer, '
|
|
141
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
142
|
+
|
|
143
|
+
sleep_node = SleepNode(tokens_by_line[1:])
|
|
144
|
+
last_block.body.append(sleep_node)
|
|
145
|
+
|
|
146
|
+
elif first_token_line.value == 'param':
|
|
147
|
+
|
|
148
|
+
param_node = ParamNode(body=[])
|
|
149
|
+
last_block.body.append(param_node)
|
|
150
|
+
_, p = parse(token_lines[pointeur + 1:], param_node)
|
|
151
|
+
pointeur += p + 1 # on avance le pointeur de la ligne suivante
|
|
152
|
+
|
|
153
|
+
elif first_token_line.value == '#param':
|
|
154
|
+
if not isinstance(last_block, ParamNode):
|
|
155
|
+
raise SyntaxError(f'[#PARAM] No parameters open on line {first_token_line.position} !')
|
|
156
|
+
|
|
157
|
+
blocks.pop() # on supprime le dernier bloc (le paramètre)
|
|
158
|
+
return blocks, pointeur # on renvoie les informations parsé à la dernière paramètre ouverte
|
|
159
|
+
|
|
160
|
+
elif first_token_line.value == '#end': # node pour arrêter le programme si elle est rencontré
|
|
161
|
+
error_message = True
|
|
162
|
+
if len(tokens_by_line) > 1:
|
|
163
|
+
if tokens_by_line[1].type != DTT.BOOL:
|
|
164
|
+
raise TypeError(f'[#END] the variable given must be a boolean, not {tokens_by_line[1].type}')
|
|
165
|
+
else:
|
|
166
|
+
error_message = tokens_by_line[1]
|
|
167
|
+
end_node = EndNode(error_message)
|
|
168
|
+
last_block.body.append(end_node)
|
|
169
|
+
|
|
170
|
+
############################## DISCORD KEYWORDS ##############################
|
|
171
|
+
|
|
172
|
+
elif first_token_line.type == DTT.DISCORD_KEYWORD:
|
|
173
|
+
|
|
174
|
+
if first_token_line.value == 'embed':
|
|
175
|
+
if len(tokens_by_line) <= 1:
|
|
176
|
+
raise SyntaxError(f'[EMBED] Take one or more arguments on line {first_token_line.position} !')
|
|
177
|
+
if tokens_by_line[1].type != DTT.IDENT:
|
|
178
|
+
raise TypeError(f'[EMBED] the variable given must be a ident, '
|
|
179
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
180
|
+
|
|
181
|
+
embed_node = EmbedNode(body=[], fields=[])
|
|
182
|
+
var_node = VarNode(tokens_by_line[1], body=[embed_node])
|
|
183
|
+
last_block.body.append(var_node)
|
|
184
|
+
_, p = parse(token_lines[pointeur + 1:], embed_node)
|
|
185
|
+
pointeur += p + 1
|
|
186
|
+
|
|
187
|
+
elif first_token_line.value == '#embed':
|
|
188
|
+
if not isinstance(last_block, EmbedNode):
|
|
189
|
+
raise SyntaxError(f'[#EMBED] No embed open on line {first_token_line.position} !')
|
|
190
|
+
blocks.pop()
|
|
191
|
+
return blocks, pointeur
|
|
192
|
+
|
|
193
|
+
elif first_token_line.value == 'field':
|
|
194
|
+
if len(tokens_by_line) <= 1:
|
|
195
|
+
raise SyntaxError(f'[FIELD] Take one or more arguments on line {first_token_line.position} !')
|
|
196
|
+
if not isinstance(last_block, EmbedNode):
|
|
197
|
+
raise SyntaxError(f'[FIELD] No embed open on line {first_token_line.position} !')
|
|
198
|
+
|
|
199
|
+
last_block.fields.append(FieldEmbedNode(tokens_by_line[1:]))
|
|
200
|
+
|
|
201
|
+
elif first_token_line.value in ('perm', 'permission'):
|
|
202
|
+
if len(tokens_by_line) <= 1:
|
|
203
|
+
raise SyntaxError(f'[PERM] Take one argument on line {first_token_line.position} !')
|
|
204
|
+
if tokens_by_line[1].type != DTT.IDENT:
|
|
205
|
+
raise TypeError(f'[PERM] the variable given must be a ident, '
|
|
206
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
207
|
+
|
|
208
|
+
perm_node = PermissionNode(body=[])
|
|
209
|
+
var_node = VarNode(tokens_by_line[1], body=[perm_node])
|
|
210
|
+
last_block.body.append(var_node)
|
|
211
|
+
_, p = parse(token_lines[pointeur + 1:], perm_node)
|
|
212
|
+
pointeur += p + 1
|
|
213
|
+
|
|
214
|
+
elif first_token_line.value in ('#perm', '#permission'):
|
|
215
|
+
if not isinstance(last_block, PermissionNode):
|
|
216
|
+
raise SyntaxError(f'[#PERM] No permission open on line {first_token_line.position} !')
|
|
217
|
+
blocks.pop()
|
|
218
|
+
return blocks, pointeur
|
|
219
|
+
|
|
220
|
+
elif first_token_line.value == 'ui':
|
|
221
|
+
if len(tokens_by_line) <= 1:
|
|
222
|
+
raise SyntaxError(f'[UI] Take one argument on line {first_token_line.position} !')
|
|
223
|
+
if tokens_by_line[1].type != DTT.IDENT:
|
|
224
|
+
raise TypeError(f'[UI] the variable given must be a ident, '
|
|
225
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
226
|
+
|
|
227
|
+
ui_node = UiNode([])
|
|
228
|
+
var_node = VarNode(tokens_by_line[1], body=[ui_node])
|
|
229
|
+
last_block.body.append(var_node)
|
|
230
|
+
_, p = parse(token_lines[pointeur + 1:], ui_node)
|
|
231
|
+
pointeur += p + 1
|
|
232
|
+
|
|
233
|
+
elif first_token_line.value == '#ui':
|
|
234
|
+
if not isinstance(last_block, UiNode):
|
|
235
|
+
raise SyntaxError(f'[#UI] No UI open on line {first_token_line.position} !')
|
|
236
|
+
blocks.pop()
|
|
237
|
+
return blocks, pointeur
|
|
238
|
+
|
|
239
|
+
elif first_token_line.value == 'button':
|
|
240
|
+
if len(tokens_by_line) <= 1:
|
|
241
|
+
raise SyntaxError(f'[BUTTON] Take one or more arguments on line {first_token_line.position} !')
|
|
242
|
+
if not isinstance(last_block, UiNode):
|
|
243
|
+
raise SyntaxError(f'[BUTTON] No UI open on line {first_token_line.position} !')
|
|
244
|
+
|
|
245
|
+
button_node = UiButtonNode(tokens_by_line[1:])
|
|
246
|
+
last_block.buttons.append(button_node)
|
|
247
|
+
|
|
248
|
+
elif first_token_line.value == 'select':
|
|
249
|
+
if len(tokens_by_line) <= 1:
|
|
250
|
+
raise SyntaxError(f'[SELECT] Take one or more arguments on line {first_token_line.position} !')
|
|
251
|
+
if not isinstance(last_block, UiNode):
|
|
252
|
+
raise SyntaxError(f'[SELECT] No UI open on line {first_token_line.position} !')
|
|
253
|
+
select_node = UiSelectNode(tokens_by_line[1:])
|
|
254
|
+
last_block.selects.append(select_node)
|
|
255
|
+
|
|
256
|
+
############################## AUTRE ##############################
|
|
257
|
+
|
|
258
|
+
elif first_token_line.type == DTT.IDENT:
|
|
259
|
+
if len(tokens_by_line) == 1:
|
|
260
|
+
last_block.body.append(CommandNode(name='sm', body=ArgsCommandNode([first_token_line])))
|
|
261
|
+
|
|
262
|
+
elif first_token_line.type == DTT.STR:
|
|
263
|
+
last_block.body.append(CommandNode(name='sm', body=ArgsCommandNode([first_token_line])))
|
|
264
|
+
|
|
265
|
+
elif first_token_line.type == DTT.EVAL_GROUP:
|
|
266
|
+
parse([first_token_line.value], last_block)
|
|
267
|
+
|
|
268
|
+
else:
|
|
269
|
+
last_block.body += tokens_by_line
|
|
270
|
+
|
|
271
|
+
pointeur += 1
|
|
272
|
+
|
|
273
|
+
return blocks, pointeur
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def ast_to_dict(obj):
|
|
277
|
+
if isinstance(obj, list):
|
|
278
|
+
return [ast_to_dict(item) for item in obj]
|
|
279
|
+
elif hasattr(obj, "to_dict"):
|
|
280
|
+
return obj.to_dict()
|
|
281
|
+
else:
|
|
282
|
+
return obj # fallback for primitives or tokens
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def dict_to_ast(data):
|
|
286
|
+
"""
|
|
287
|
+
Convertit un dictionnaire en une structure AST.
|
|
288
|
+
:param data: le dictionnaire à convertir
|
|
289
|
+
:return: la structure AST correspondante
|
|
290
|
+
"""
|
|
291
|
+
if isinstance(data, list):
|
|
292
|
+
return [dict_to_ast(item) for item in data]
|
|
293
|
+
elif isinstance(data, dict):
|
|
294
|
+
pass
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def parser_inline(tokens: list[Token]) -> tuple[list[list[Token]], bool]:
|
|
298
|
+
"""
|
|
299
|
+
Transforme une ligne avec un if/else inline en structure multilignes
|
|
300
|
+
"""
|
|
301
|
+
result: list[list[Token]] = []
|
|
302
|
+
|
|
303
|
+
try:
|
|
304
|
+
if_index = next(i for i, tok in enumerate(tokens) if tok.value == 'if')
|
|
305
|
+
else_index = next(i for i, tok in enumerate(tokens) if tok.value == 'else')
|
|
306
|
+
except StopIteration:
|
|
307
|
+
return [tokens], False # ligne normale
|
|
308
|
+
|
|
309
|
+
value_tokens = tokens[:if_index]
|
|
310
|
+
condition_tokens = tokens[if_index + 1:else_index]
|
|
311
|
+
else_tokens = tokens[else_index + 1:]
|
|
312
|
+
|
|
313
|
+
# On génère :
|
|
314
|
+
result.append([tokens[if_index]] + condition_tokens) # ligne "if cond"
|
|
315
|
+
result.append(value_tokens) # body du if
|
|
316
|
+
result.append([tokens[else_index]]) # ligne "else"
|
|
317
|
+
result.append(else_tokens) # body du else
|
|
318
|
+
return result, True
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def to_postfix(expression, interpreter=None):
|
|
322
|
+
"""
|
|
323
|
+
Transforme l'expression en notation postfixée (RPN)
|
|
324
|
+
:param expression: l'expression donné par le tokenizer
|
|
325
|
+
:return: l'expression en notation postfixée
|
|
326
|
+
"""
|
|
327
|
+
output = []
|
|
328
|
+
operators: list[Token] = []
|
|
329
|
+
|
|
330
|
+
for token in expression:
|
|
331
|
+
if token.type in (DTT.IDENT, DTT.INT, DTT.FLOAT, DTT.LIST, DTT.STR, DTT.BOOL, DTT.EVAL_GROUP): # Si c'est un ident
|
|
332
|
+
output.append(token)
|
|
333
|
+
elif token.value in dshell_operators:
|
|
334
|
+
while (operators and operators[-1].value in dshell_operators and
|
|
335
|
+
dshell_operators[operators[-1].value][1] >= dshell_operators[token.value][1]):
|
|
336
|
+
output.append(operators.pop())
|
|
337
|
+
operators.append(token)
|
|
338
|
+
else:
|
|
339
|
+
raise ValueError(f"Token inconnu : {token}")
|
|
340
|
+
|
|
341
|
+
while operators:
|
|
342
|
+
output.append(operators.pop())
|
|
343
|
+
|
|
344
|
+
return output
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def print_ast(ast: list[ASTNode], decalage: int = 0):
|
|
348
|
+
for i in ast:
|
|
349
|
+
|
|
350
|
+
if isinstance(i, StartNode):
|
|
351
|
+
print_ast(i.body, decalage)
|
|
352
|
+
|
|
353
|
+
if isinstance(i, LoopNode):
|
|
354
|
+
print(f"{' ' * decalage}LOOP -> {i.variable.name} : {i.variable.body}")
|
|
355
|
+
print_ast(i, decalage + 5)
|
|
356
|
+
|
|
357
|
+
elif isinstance(i, IfNode):
|
|
358
|
+
print(f"{' ' * decalage}IF -> {i.condition}")
|
|
359
|
+
print_ast(i, decalage + 5)
|
|
360
|
+
|
|
361
|
+
if i.elif_nodes is not None:
|
|
362
|
+
for elif_body in i.elif_nodes:
|
|
363
|
+
print(f"{' ' * decalage}ELIF -> {elif_body.condition}")
|
|
364
|
+
print_ast(elif_body, decalage + 5)
|
|
365
|
+
|
|
366
|
+
if i.else_body is not None:
|
|
367
|
+
print(f"{' ' * decalage}ELSE -> ...")
|
|
368
|
+
print_ast(i.else_body, decalage + 5)
|
|
369
|
+
|
|
370
|
+
elif isinstance(i, CommandNode):
|
|
371
|
+
print(f"{' ' * decalage}COMMAND -> {i.name} : {i.body}")
|
|
372
|
+
|
|
373
|
+
elif isinstance(i, VarNode):
|
|
374
|
+
print(f"{' ' * decalage}VAR -> {i.name} : {i.body}")
|
|
375
|
+
|
|
376
|
+
elif isinstance(i, EmbedNode):
|
|
377
|
+
print(f"{' ' * decalage}EMBED :")
|
|
378
|
+
print_ast(i.fields, decalage + 5)
|
|
379
|
+
|
|
380
|
+
elif isinstance(i, FieldEmbedNode):
|
|
381
|
+
for field in i.body:
|
|
382
|
+
print(f"{' ' * decalage}FIELD -> {field.value}")
|
|
383
|
+
|
|
384
|
+
elif isinstance(i, PermissionNode):
|
|
385
|
+
print(f"{' ' * decalage}PERMISSION -> {i.body}")
|
|
386
|
+
|
|
387
|
+
elif isinstance(i, ParamNode):
|
|
388
|
+
print(f"{' ' * decalage}PARAM -> {i.body}")
|
|
389
|
+
|
|
390
|
+
elif isinstance(i, UiNode):
|
|
391
|
+
print(f"{' ' * decalage}UI ->")
|
|
392
|
+
print_ast(i.buttons, decalage + 5)
|
|
393
|
+
print_ast(i.selects, decalage + 5)
|
|
394
|
+
|
|
395
|
+
elif isinstance(i, UiButtonNode):
|
|
396
|
+
print(f"{' ' * decalage}BUTTON -> {i.body}")
|
|
397
|
+
|
|
398
|
+
elif isinstance(i, UiSelectNode):
|
|
399
|
+
print(f"{' ' * decalage}SELECT -> {i.body}")
|
|
400
|
+
|
|
401
|
+
elif isinstance(i, SleepNode):
|
|
402
|
+
print(f"{' ' * decalage}SLEEP -> {i.body}")
|
|
403
|
+
|
|
404
|
+
elif isinstance(i, EndNode):
|
|
405
|
+
print(f"{' ' * decalage}END -> ...")
|
|
406
|
+
|
|
407
|
+
else:
|
|
408
|
+
print(f"{' ' * decalage}UNKNOWN NODE {i}")
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
"dshell_keyword",
|
|
3
|
+
"dshell_discord_keyword",
|
|
4
|
+
"dshell_commands",
|
|
5
|
+
"dshell_mathematical_operators",
|
|
6
|
+
"dshell_logical_operators",
|
|
7
|
+
"dshell_operators",
|
|
8
|
+
"dshell_logical_word_operators"
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
from typing import Callable
|
|
12
|
+
|
|
13
|
+
from ..DISCORD_COMMANDS.dshell_channel import *
|
|
14
|
+
from ..DISCORD_COMMANDS.dshell_member import *
|
|
15
|
+
from ..DISCORD_COMMANDS.dshell_message import *
|
|
16
|
+
from ..DISCORD_COMMANDS.dshell_pastbin import *
|
|
17
|
+
from ..DISCORD_COMMANDS.dshell_role import *
|
|
18
|
+
from ..DISCORD_COMMANDS.dshell_interaction import *
|
|
19
|
+
from ..DISCORD_COMMANDS.utils.utils_global import *
|
|
20
|
+
from ..DISCORD_COMMANDS.utils.utils_list import *
|
|
21
|
+
from ..DISCORD_COMMANDS.utils.utils_member import *
|
|
22
|
+
from ..DISCORD_COMMANDS.utils.utils_string import *
|
|
23
|
+
from ..DISCORD_COMMANDS.utils.utils_permissions import utils_update_permissions
|
|
24
|
+
|
|
25
|
+
dshell_keyword: set[str] = {
|
|
26
|
+
'if', 'else', 'elif', 'loop', '#end', 'var', '#loop', '#if', 'sleep', 'param', '#param'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
dshell_discord_keyword: set[str] = {
|
|
30
|
+
'embed', '#embed', 'field', 'perm', 'permission', '#perm', '#permission', 'ui', '#ui', 'button', 'select'
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async def dshell_debug(ctx, x):
|
|
34
|
+
"""
|
|
35
|
+
Print all x parameter
|
|
36
|
+
:param ctx:
|
|
37
|
+
:param x:
|
|
38
|
+
:return:
|
|
39
|
+
"""
|
|
40
|
+
print(x)
|
|
41
|
+
return x
|
|
42
|
+
|
|
43
|
+
dshell_commands: dict[str, Callable] = {
|
|
44
|
+
|
|
45
|
+
"debug": dshell_debug,
|
|
46
|
+
## global utils
|
|
47
|
+
'random': utils_random,
|
|
48
|
+
|
|
49
|
+
## List utils
|
|
50
|
+
'length': utils_len,
|
|
51
|
+
'len': utils_len,
|
|
52
|
+
'add': utils_list_add,
|
|
53
|
+
'remove': utils_list_remove,
|
|
54
|
+
'clear': utils_list_clear,
|
|
55
|
+
'pop': utils_list_pop,
|
|
56
|
+
'sort': utils_list_sort,
|
|
57
|
+
'reverse': utils_list_reverse,
|
|
58
|
+
'get': utils_list_get_value,
|
|
59
|
+
|
|
60
|
+
## String utils
|
|
61
|
+
'split': utils_split_string,
|
|
62
|
+
'upper': utils_upper_string,
|
|
63
|
+
'lower': utils_lower_string,
|
|
64
|
+
'title': utils_title_string,
|
|
65
|
+
'strip': utils_strip_string,
|
|
66
|
+
'replace': utils_replace_string,
|
|
67
|
+
'regex_findall': utils_regex_findall,
|
|
68
|
+
'regex_sub': utils_regex_sub,
|
|
69
|
+
'regex': utils_regex_search,
|
|
70
|
+
|
|
71
|
+
## Discord utils
|
|
72
|
+
'name': utils_get_name, # get the name from id (channel, role, member)
|
|
73
|
+
'id': utils_get_id, # get the id from name (channel, role, member)
|
|
74
|
+
'roles': utils_get_roles, # get all roles of a member
|
|
75
|
+
|
|
76
|
+
## Member utils
|
|
77
|
+
'has_perms': utils_has_permissions, # check if a member has the specified permissions
|
|
78
|
+
|
|
79
|
+
## Permission utils
|
|
80
|
+
'update_perms': utils_update_permissions, # update permission dict
|
|
81
|
+
|
|
82
|
+
## Pastbin command
|
|
83
|
+
"gp": dshell_get_pastbin, # get pastbin
|
|
84
|
+
|
|
85
|
+
## Discord commands
|
|
86
|
+
"sm": dshell_send_message, # send message
|
|
87
|
+
"spm": dshell_send_private_message, # send private message
|
|
88
|
+
"srm": dshell_respond_message, # respond to a message
|
|
89
|
+
"dm": dshell_delete_message,
|
|
90
|
+
"pm": dshell_purge_message,
|
|
91
|
+
"em": dshell_edit_message, # edit message
|
|
92
|
+
"pinm": dshell_pin_message, # pin message
|
|
93
|
+
"mh": dshell_get_history_messages, # get message history
|
|
94
|
+
"gcm": dshell_get_content_message, # get content of a message
|
|
95
|
+
"gma": dshell_get_author_id_message, # get author id of a message
|
|
96
|
+
"gml": dshell_get_message_link, # get message link
|
|
97
|
+
"gmc": dshell_get_message_category_id, # get message category id
|
|
98
|
+
"gmp": dshell_get_channel_pined_messages, # get channel pined messages
|
|
99
|
+
"gmat": dshell_get_message_attachments, # get message attachments
|
|
100
|
+
"ims": dshell_is_message_system, # is message system
|
|
101
|
+
|
|
102
|
+
"sri": dshell_respond_interaction, # respond to an interaction
|
|
103
|
+
"sdi": dshell_defer_interaction, # defer an interaction
|
|
104
|
+
"dom": dshell_delete_original_message, # delete original interaction message
|
|
105
|
+
|
|
106
|
+
"cc": dshell_create_text_channel, # create channel
|
|
107
|
+
"cvc": dshell_create_voice_channel, # create voice channel
|
|
108
|
+
"cca": dshell_create_category, # create category
|
|
109
|
+
"dca": dshell_delete_category, # delete category
|
|
110
|
+
"dc": dshell_delete_channel, # delete channel
|
|
111
|
+
"dcs": dshell_delete_channels, # delete several channels by name or regex
|
|
112
|
+
|
|
113
|
+
"gc": dshell_get_channel, # get channel
|
|
114
|
+
"gcs": dshell_get_channels, # get channels by name or regex
|
|
115
|
+
"gccs": dshell_get_channels_in_category, # get channels in category
|
|
116
|
+
"gcc": dshell_get_channel_category_id, # get channel category id
|
|
117
|
+
"gcnsfw": dshell_get_channel_nsfw, # get channel nsfw status
|
|
118
|
+
"gcsl": dshell_get_channel_slowmode, # get channel slowmode
|
|
119
|
+
"gct": dshell_get_channel_topic, # get channel topic
|
|
120
|
+
"gcth": dshell_get_channel_threads, # get channel threads
|
|
121
|
+
"gvcm": dshell_get_channel_voice_members, # get voice channel members
|
|
122
|
+
|
|
123
|
+
"ct": dshell_create_thread_message, # create thread
|
|
124
|
+
"dt": dshell_delete_thread, # delete thread
|
|
125
|
+
"gt": dshell_get_thread, # get thread
|
|
126
|
+
"et": dshell_edit_thread, # edit thread
|
|
127
|
+
|
|
128
|
+
"bm": dshell_ban_member, # ban member
|
|
129
|
+
"um": dshell_unban_member, # unban member
|
|
130
|
+
"km": dshell_kick_member, # kick member
|
|
131
|
+
"tm": dshell_timeout_member, # timeout member
|
|
132
|
+
"mm": dshell_move_member, # move member to another channel
|
|
133
|
+
"rm": dshell_rename_member, # rename member
|
|
134
|
+
"cp": dshell_check_permissions, # check permissions
|
|
135
|
+
"gmr": dshell_give_member_roles, # give roles
|
|
136
|
+
"rmr": dshell_remove_member_roles, # remove roles
|
|
137
|
+
|
|
138
|
+
"ec": dshell_edit_text_channel, # edit text channel
|
|
139
|
+
"evc": dshell_edit_voice_channel, # edit voice channel
|
|
140
|
+
"eca": dshell_edit_category, # edit category
|
|
141
|
+
|
|
142
|
+
"cr": dshell_create_role, # create role
|
|
143
|
+
"dr": dshell_delete_roles, # delete role
|
|
144
|
+
"er": dshell_edit_role, # edit role
|
|
145
|
+
|
|
146
|
+
"ar": dshell_add_reactions, # add reactions to a message
|
|
147
|
+
"rr": dshell_remove_reactions, # remove reactions from a message
|
|
148
|
+
"cmr": dshell_clear_message_reactions, # clear reactions from a message
|
|
149
|
+
"cor": dshell_clear_one_reactions , # clear one reaction from a message
|
|
150
|
+
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
dshell_mathematical_operators: dict[str, tuple[Callable, int]] = {
|
|
154
|
+
|
|
155
|
+
r".": (lambda a, b: a.b, 9),
|
|
156
|
+
r"->": (lambda a: a.at, 10), # equivalent to calling .at(key)
|
|
157
|
+
|
|
158
|
+
r"+": (lambda a, b: a + b, 6),
|
|
159
|
+
r"-": (lambda a, b=None: -a if b is None else a - b, 6),
|
|
160
|
+
# warning: ambiguity between unary and binary to be handled in your parser
|
|
161
|
+
r"**": (lambda a, b: a ** b, 8),
|
|
162
|
+
r"*": (lambda a, b: a * b, 7),
|
|
163
|
+
r"%": (lambda a, b: a % b, 7),
|
|
164
|
+
r"//": (lambda a, b: a // b, 7),
|
|
165
|
+
r"/": (lambda a, b: a / b, 7),
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
dshell_logical_word_operators: dict[str, tuple[Callable, int]] = {
|
|
169
|
+
r"and": (lambda a, b: bool(a and b), 2),
|
|
170
|
+
r"or": (lambda a, b: bool(a or b), 1),
|
|
171
|
+
r"not": (lambda a: not a, 3),
|
|
172
|
+
r"in": (lambda a, b: a in b, 4),
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
dshell_logical_operators: dict[str, tuple[Callable, int]] = {
|
|
176
|
+
|
|
177
|
+
r"<": (lambda a, b: a < b, 4),
|
|
178
|
+
r"<=": (lambda a, b: a <= b, 4),
|
|
179
|
+
r"=<": (lambda a, b: a <= b, 4),
|
|
180
|
+
r"=": (lambda a, b: a == b, 4),
|
|
181
|
+
r"!=": (lambda a, b: a != b, 4),
|
|
182
|
+
r"=!": (lambda a, b: a != b, 4),
|
|
183
|
+
r">": (lambda a, b: a > b, 4),
|
|
184
|
+
r">=": (lambda a, b: a >= b, 4),
|
|
185
|
+
r"=>": (lambda a, b: a >= b, 4),
|
|
186
|
+
r"&": (lambda a, b: a & b, 2),
|
|
187
|
+
r"|": (lambda a, b: a | b, 1),
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
dshell_operators: dict[str, tuple[Callable, int]] = dshell_logical_operators.copy()
|
|
192
|
+
dshell_operators.update(dshell_logical_word_operators)
|
|
193
|
+
dshell_operators.update(dshell_mathematical_operators)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from enum import Enum, auto
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
'DshellTokenType',
|
|
6
|
+
'Token',
|
|
7
|
+
'MASK_CHARACTER'
|
|
8
|
+
]
|
|
9
|
+
|
|
10
|
+
MASK_CHARACTER = '§'
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DshellTokenType(Enum):
|
|
14
|
+
INT = auto()
|
|
15
|
+
FLOAT = auto()
|
|
16
|
+
STR = auto()
|
|
17
|
+
BOOL = auto(),
|
|
18
|
+
NONE = auto(),
|
|
19
|
+
LIST = auto()
|
|
20
|
+
DICT = auto()
|
|
21
|
+
MENTION = auto()
|
|
22
|
+
IDENT = auto() # nom de variable, fonction
|
|
23
|
+
KEYWORD = auto() # if, let, end, etc.
|
|
24
|
+
DISCORD_KEYWORD = auto() # embed, #embed...
|
|
25
|
+
COMMAND = auto()
|
|
26
|
+
PARAMETER = auto() # --
|
|
27
|
+
PARAMETERS = auto(), # --*
|
|
28
|
+
STR_PARAMETER = auto(), # --"
|
|
29
|
+
SUB_SEPARATOR = auto(), # ~~
|
|
30
|
+
MATHS_OPERATOR = auto() # ==, +, -, *, etc.
|
|
31
|
+
LOGIC_OPERATOR = auto(),
|
|
32
|
+
LOGIC_WORD_OPERATOR = auto() # and, or, not
|
|
33
|
+
EVAL_GROUP = auto() # `code`
|
|
34
|
+
COMMENT = auto() # lignes commençant par ##
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Token:
|
|
38
|
+
def __init__(self, type_: "DTT", value: Union[str, list], position: tuple[int, int]):
|
|
39
|
+
self.type = type_
|
|
40
|
+
self.value = value
|
|
41
|
+
self.position = position
|
|
42
|
+
|
|
43
|
+
def __repr__(self):
|
|
44
|
+
return f"<{self.type.name} '{self.value}'>"
|
|
45
|
+
|
|
46
|
+
def to_dict(self):
|
|
47
|
+
def serialize_value(value):
|
|
48
|
+
if isinstance(value, list):
|
|
49
|
+
return [serialize_value(v) for v in value]
|
|
50
|
+
elif isinstance(value, Token):
|
|
51
|
+
return value.to_dict()
|
|
52
|
+
return value
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
"type": self.type.name,
|
|
56
|
+
"value": serialize_value(self.value),
|
|
57
|
+
"position": self.position
|
|
58
|
+
}
|