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.
Files changed (34) hide show
  1. Dshell/DISCORD_COMMANDS/__init__.py +7 -0
  2. Dshell/DISCORD_COMMANDS/dshell_channel.py +612 -0
  3. Dshell/DISCORD_COMMANDS/dshell_interaction.py +89 -0
  4. Dshell/DISCORD_COMMANDS/dshell_member.py +274 -0
  5. Dshell/DISCORD_COMMANDS/dshell_message.py +444 -0
  6. Dshell/DISCORD_COMMANDS/dshell_pastbin.py +28 -0
  7. Dshell/DISCORD_COMMANDS/dshell_role.py +128 -0
  8. Dshell/DISCORD_COMMANDS/utils/__init__.py +8 -0
  9. Dshell/DISCORD_COMMANDS/utils/utils_global.py +155 -0
  10. Dshell/DISCORD_COMMANDS/utils/utils_list.py +109 -0
  11. Dshell/DISCORD_COMMANDS/utils/utils_member.py +30 -0
  12. Dshell/DISCORD_COMMANDS/utils/utils_message.py +78 -0
  13. Dshell/DISCORD_COMMANDS/utils/utils_permissions.py +94 -0
  14. Dshell/DISCORD_COMMANDS/utils/utils_string.py +157 -0
  15. Dshell/DISCORD_COMMANDS/utils/utils_thread.py +35 -0
  16. Dshell/_DshellInterpreteur/__init__.py +4 -0
  17. Dshell/_DshellInterpreteur/cached_messages.py +4 -0
  18. Dshell/_DshellInterpreteur/dshell_arguments.py +74 -0
  19. Dshell/_DshellInterpreteur/dshell_interpreter.py +671 -0
  20. Dshell/_DshellInterpreteur/errors.py +8 -0
  21. Dshell/_DshellParser/__init__.py +2 -0
  22. Dshell/_DshellParser/ast_nodes.py +675 -0
  23. Dshell/_DshellParser/dshell_parser.py +408 -0
  24. Dshell/_DshellTokenizer/__init__.py +4 -0
  25. Dshell/_DshellTokenizer/dshell_keywords.py +193 -0
  26. Dshell/_DshellTokenizer/dshell_token_type.py +58 -0
  27. Dshell/_DshellTokenizer/dshell_tokenizer.py +146 -0
  28. Dshell/__init__.py +3 -0
  29. Dshell/_utils.py +1 -0
  30. dshellinterpreter-0.2.21.7.dist-info/METADATA +37 -0
  31. dshellinterpreter-0.2.21.7.dist-info/RECORD +34 -0
  32. dshellinterpreter-0.2.21.7.dist-info/WHEEL +5 -0
  33. dshellinterpreter-0.2.21.7.dist-info/licenses/LICENSE +21 -0
  34. 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,4 @@
1
+ from .dshell_keywords import *
2
+ from .dshell_token_type import DshellTokenType as DTT
3
+ from .dshell_token_type import Token
4
+ from .dshell_tokenizer import DshellTokenizer
@@ -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
+ }