dshellInterpreter 1.2.7.11__tar.gz → 1.2.8.0__tar.gz
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.
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_ui.py +45 -24
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellInterpreteur/__init__.py +1 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellInterpreteur/dshell_global_variables.py +8 -1
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellInterpreteur/dshell_interpreter.py +6 -12
- dshellinterpreter-1.2.8.0/Dshell/DshellInterpreteur/dshell_scope.py +95 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellParser/ast_nodes.py +23 -1
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellParser/dshell_parser.py +13 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellTokenizer/dshell_keywords.py +1 -1
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellTokenizer/dshell_token_type.py +3 -0
- {dshellinterpreter-1.2.7.11/dshellInterpreter.egg-info → dshellinterpreter-1.2.8.0}/PKG-INFO +1 -1
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0/dshellInterpreter.egg-info}/PKG-INFO +1 -1
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/setup.py +1 -1
- dshellinterpreter-1.2.7.11/Dshell/DshellInterpreteur/dshell_scope.py +0 -159
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/__init__.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_channel.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_embed.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_file.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_interaction.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_member.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_message.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_role.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/__init__.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_embed.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_file.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_global.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_list.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_member.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_message.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_numbers.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_permissions.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_string.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_thread.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_type_validation.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellInterpreteur/cached_messages.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellInterpreteur/dshell_arguments.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellInterpreteur/dshell_iterators.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellInterpreteur/errors.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellInterpreteur/utils_interpreter.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellParser/__init__.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellParser/errors.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellPreProcess/__init__.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellPreProcess/dshell_preprocess.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellTokenizer/__init__.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellTokenizer/dshell_tokenizer.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/__init__.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/full_import.py +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/LICENSE +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/README.md +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/dshellInterpreter.egg-info/SOURCES.txt +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/dshellInterpreter.egg-info/dependency_links.txt +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/dshellInterpreter.egg-info/requires.txt +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/dshellInterpreter.egg-info/top_level.txt +0 -0
- {dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/setup.cfg +0 -0
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_ui.py
RENAMED
|
@@ -8,13 +8,21 @@ from ..full_import import (ButtonStyle,
|
|
|
8
8
|
SelectMenu,
|
|
9
9
|
ComponentType,
|
|
10
10
|
random,
|
|
11
|
-
IntEnum
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
IntEnum,
|
|
12
|
+
deepcopy)
|
|
13
|
+
|
|
14
|
+
from ..DshellParser.ast_nodes import (UiSelectNode,
|
|
15
|
+
UiButtonNode,
|
|
16
|
+
OptionUiSelectNode,
|
|
17
|
+
CodeNode,
|
|
18
|
+
ListNode,
|
|
19
|
+
StrNode,
|
|
20
|
+
IntNode,
|
|
21
|
+
BoolNode)
|
|
14
22
|
|
|
15
23
|
from ..DshellInterpreteur.utils_interpreter import regroupe_commandes
|
|
16
24
|
|
|
17
|
-
from ..DshellInterpreteur.dshell_scope import new_scope,
|
|
25
|
+
from ..DshellInterpreteur.dshell_scope import new_scope, Scope
|
|
18
26
|
|
|
19
27
|
from ..full_import import Any, TYPE_CHECKING, Union, Optional
|
|
20
28
|
|
|
@@ -31,8 +39,6 @@ from .utils.utils_global import utils_refactor_emoji
|
|
|
31
39
|
if TYPE_CHECKING:
|
|
32
40
|
from ..DshellInterpreteur.dshell_interpreter import DshellInterpreteur
|
|
33
41
|
|
|
34
|
-
scope_id = "scope_id"
|
|
35
|
-
|
|
36
42
|
ButtonStyleValues: set = {i.name for i in ButtonStyle}
|
|
37
43
|
SelectSyleValues: dict = {'string': ComponentType.string_select,
|
|
38
44
|
'role': ComponentType.role_select,
|
|
@@ -56,6 +62,25 @@ def check_timeout(timeout: Union[int, IntNode]):
|
|
|
56
62
|
f"and less or equal than[{UITimeout.max_timeout}]")
|
|
57
63
|
return timeout
|
|
58
64
|
|
|
65
|
+
|
|
66
|
+
def build_ui_scope(env: Scope, code_node: CodeNode):
|
|
67
|
+
"""
|
|
68
|
+
Create a new scope to store only variables used in UI.
|
|
69
|
+
:param code_node:
|
|
70
|
+
:return:
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
new_ui_scope = Scope()
|
|
74
|
+
|
|
75
|
+
if not isinstance(code_node, CodeNode) or code_node.global_env_vars is None:
|
|
76
|
+
return new_ui_scope
|
|
77
|
+
|
|
78
|
+
for token in code_node.global_env_vars.env_variables:
|
|
79
|
+
|
|
80
|
+
new_ui_scope.set(token.value, deepcopy(env.get(token.value, None)))
|
|
81
|
+
|
|
82
|
+
return new_ui_scope
|
|
83
|
+
|
|
59
84
|
async def build_ui_button_parameters(ui_button_node: UiButtonNode, interpreter: "DshellInterpreteur"):
|
|
60
85
|
"""
|
|
61
86
|
Builds the parameters for a UI component from the UiNode.
|
|
@@ -201,18 +226,15 @@ async def build_ui(ui_node: Union[UiButtonNode, UiSelectNode], interpreter: "Dsh
|
|
|
201
226
|
:return:
|
|
202
227
|
"""
|
|
203
228
|
|
|
204
|
-
|
|
205
|
-
update_nbr_usage_scope(interpreter.scope_id, -1)
|
|
206
|
-
|
|
207
|
-
view = EasyModifiedViews(timeout=600, call_on_timeout=ui_timeout, disabled_on_timeout=True)
|
|
229
|
+
view = EasyModifiedViews(timeout=600, disabled_on_timeout=True)
|
|
208
230
|
|
|
209
231
|
if isinstance(ui_node, UiButtonNode):
|
|
210
232
|
async for _, args_button, code in build_ui_button_parameters(ui_node, interpreter):
|
|
233
|
+
code: CodeNode
|
|
211
234
|
view.timeout = args_button.pop('timeout', IntNode(UITimeout.default_timeout))
|
|
212
235
|
b = ui.Button(**args_button)
|
|
213
236
|
view.add_items(b)
|
|
214
|
-
view.set_callable(b.custom_id, _callable=ui_button_callback, data={'code': code,
|
|
215
|
-
update_nbr_usage_scope(interpreter.scope_id, 1)
|
|
237
|
+
view.set_callable(b.custom_id, _callable=ui_button_callback, data={'code': code, 'scope': build_ui_scope(interpreter.env, code)})
|
|
216
238
|
|
|
217
239
|
elif isinstance(ui_node, UiSelectNode):
|
|
218
240
|
s = SelectMenu()
|
|
@@ -228,26 +250,25 @@ async def build_ui(ui_node: Union[UiButtonNode, UiSelectNode], interpreter: "Dsh
|
|
|
228
250
|
for option in options:
|
|
229
251
|
menu.add_option(**option)
|
|
230
252
|
|
|
231
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
253
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, "scope": build_ui_scope(interpreter.env, code)})
|
|
232
254
|
|
|
233
255
|
elif select_type == ComponentType.role_select:
|
|
234
256
|
s.add_role_select_menu(**args_select)
|
|
235
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
257
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, "scope": build_ui_scope(interpreter.env, code)})
|
|
236
258
|
|
|
237
259
|
elif select_type == ComponentType.user_select:
|
|
238
260
|
s.add_user_select_menu(**args_select)
|
|
239
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
261
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, "scope": build_ui_scope(interpreter.env, code)})
|
|
240
262
|
|
|
241
263
|
elif select_type == ComponentType.mentionable_select:
|
|
242
264
|
s.add_mentionable_select_menu(**args_select)
|
|
243
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
265
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, "scope": build_ui_scope(interpreter.env, code)})
|
|
244
266
|
|
|
245
267
|
elif select_type == ComponentType.channel_select:
|
|
246
268
|
s.add_channel_select_menu(**args_select)
|
|
247
|
-
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code,
|
|
269
|
+
s.set_callable(args_select["custom_id"], _callable=ui_select_callback, data={'code': code, "scope": build_ui_scope(interpreter.env, code)})
|
|
248
270
|
|
|
249
271
|
view.add_items(s)
|
|
250
|
-
update_nbr_usage_scope(interpreter.scope_id, 1)
|
|
251
272
|
|
|
252
273
|
else:
|
|
253
274
|
raise TypeError(f"UI node must be UiButtonNode or UiSelectNode, not {type(ui_node).__name__} !")
|
|
@@ -276,8 +297,8 @@ async def rebuild_ui(ui_node: Union[UiButtonNode, UiSelectNode], view: EasyModif
|
|
|
276
297
|
ui.disabled = args_button.get('disabled', ui.disabled)
|
|
277
298
|
ui.url = args_button.get('url', ui.url)
|
|
278
299
|
ui.row = args_button.get('row', ui.row)
|
|
279
|
-
new_code = code if code is not None else view.get_callable_data(args_button['custom_id'])['code']
|
|
280
|
-
view.set_callable(args_button['custom_id'], _callable=ui_button_callback, data={'code': new_code,
|
|
300
|
+
new_code: CodeNode = code if code is not None else view.get_callable_data(args_button['custom_id'])['code']
|
|
301
|
+
view.set_callable(args_button['custom_id'], _callable=ui_button_callback, data={'code': new_code, "scope": build_ui_scope(interpreter.env, new_code)})
|
|
281
302
|
|
|
282
303
|
elif isinstance(ui_node, UiSelectNode):
|
|
283
304
|
|
|
@@ -297,8 +318,8 @@ async def rebuild_ui(ui_node: Union[UiButtonNode, UiSelectNode], view: EasyModif
|
|
|
297
318
|
for option in options:
|
|
298
319
|
ui.add_option(**option)
|
|
299
320
|
|
|
300
|
-
new_code = code if code is not None else view.get_callable_data(args_select['custom_id'])['code']
|
|
301
|
-
view.set_callable(args_select['custom_id'], _callable=ui_select_callback, data={'code': new_code,
|
|
321
|
+
new_code: CodeNode = code if code is not None else view.get_callable_data(args_select['custom_id'])['code']
|
|
322
|
+
view.set_callable(args_select['custom_id'], _callable=ui_select_callback, data={'code': new_code, "scope": build_ui_scope(interpreter.env, new_code)})
|
|
302
323
|
|
|
303
324
|
return view
|
|
304
325
|
|
|
@@ -313,7 +334,7 @@ async def ui_button_callback(button: ui.Button, interaction: Interaction, data:
|
|
|
313
334
|
:return:
|
|
314
335
|
"""
|
|
315
336
|
code = data.get('code', None)
|
|
316
|
-
scope: Optional[str] = data.get(
|
|
337
|
+
scope: Optional[str] = data.get("scope", None)
|
|
317
338
|
|
|
318
339
|
if code is not None:
|
|
319
340
|
message = interaction
|
|
@@ -427,7 +448,7 @@ async def ui_select_callback(select: ui.Select, interaction: Interaction, data:
|
|
|
427
448
|
:return:
|
|
428
449
|
"""
|
|
429
450
|
code = data.get('code', None)
|
|
430
|
-
scope: Optional[str] = data.get(
|
|
451
|
+
scope: Optional[str] = data.get("scope", None)
|
|
431
452
|
|
|
432
453
|
message = interaction
|
|
433
454
|
if code is not None:
|
|
@@ -7,4 +7,11 @@ MAX_FILE_SIZE = 1_000_000 # bytes
|
|
|
7
7
|
MAX_SLEEP_TIME_SECONDS = 3_600 # 1 hour
|
|
8
8
|
MIN_SLEEP_TIME_SECONDS = 1
|
|
9
9
|
|
|
10
|
-
MAX_WAIT_MESSAGE_TIMEOUT = 300
|
|
10
|
+
MAX_WAIT_MESSAGE_TIMEOUT = 300
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Nothing:
|
|
14
|
+
"""
|
|
15
|
+
Do nothing.
|
|
16
|
+
Used if None is a usable value.
|
|
17
|
+
"""
|
|
@@ -11,7 +11,7 @@ from .utils_interpreter import get_params, eval_expression, eval_expression_inli
|
|
|
11
11
|
from ..DISCORD_COMMANDS.dshell_embed import build_embed, rebuild_embed
|
|
12
12
|
from ..DISCORD_COMMANDS.dshell_ui import build_ui
|
|
13
13
|
from ..DISCORD_COMMANDS.utils.utils_permissions import build_permission
|
|
14
|
-
from .dshell_scope import Scope, new_scope
|
|
14
|
+
from .dshell_scope import Scope, new_scope
|
|
15
15
|
from .dshell_global_variables import MAX_SLEEP_TIME_SECONDS, MIN_SLEEP_TIME_SECONDS
|
|
16
16
|
from .dshell_iterators import DshellIterator
|
|
17
17
|
|
|
@@ -50,16 +50,7 @@ class DshellInterpreteur:
|
|
|
50
50
|
message = ctx.message if isinstance(ctx, Interaction) else ctx
|
|
51
51
|
|
|
52
52
|
# scope creation
|
|
53
|
-
|
|
54
|
-
if scope:
|
|
55
|
-
self.env = scope
|
|
56
|
-
self.scope_id = vars_env
|
|
57
|
-
else:
|
|
58
|
-
self.scope_id: str = create_scope()
|
|
59
|
-
self.env: Optional[Scope] = get_scope(self.scope_id)
|
|
60
|
-
|
|
61
|
-
if self.env is None:
|
|
62
|
-
raise Exception(f"Scope {self.scope_id} not found in interpreter creation !")
|
|
53
|
+
self.env: Scope = Scope()
|
|
63
54
|
|
|
64
55
|
self.env.update({
|
|
65
56
|
'__ret__': None, # environment variables, '__ret__' is used to store the return value of commands
|
|
@@ -350,7 +341,10 @@ class DshellInterpreteur:
|
|
|
350
341
|
"""
|
|
351
342
|
Clear the interpreter environment.
|
|
352
343
|
"""
|
|
353
|
-
|
|
344
|
+
self.env.clear()
|
|
345
|
+
del self.env
|
|
346
|
+
self.ast.clear()
|
|
347
|
+
del self.ast
|
|
354
348
|
|
|
355
349
|
|
|
356
350
|
async def call_function(function: Callable, args: ArgsCommandNode, interpreter: DshellInterpreteur):
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from contextlib import contextmanager
|
|
2
|
+
from typing import Any, Optional, Dict, Set
|
|
3
|
+
from .dshell_global_variables import Nothing
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Scope:
|
|
7
|
+
"""
|
|
8
|
+
Represents a variable scope with optional parent scope for nested scoping.
|
|
9
|
+
"""
|
|
10
|
+
def __init__(self, parent: Optional["Scope"] = None):
|
|
11
|
+
self.parent: Optional[Scope] = parent
|
|
12
|
+
self.vars: Dict[str, Any] = {}
|
|
13
|
+
|
|
14
|
+
def get(self, name: str, default: Any = Nothing()) -> Any:
|
|
15
|
+
"""
|
|
16
|
+
Get a variable value from this scope or parent scopes.
|
|
17
|
+
:param name: Variable name
|
|
18
|
+
:param default: The default variable to return if nothing was found
|
|
19
|
+
:return: Variable value
|
|
20
|
+
:raises KeyError: If variable not found in any scope
|
|
21
|
+
"""
|
|
22
|
+
if name in self.vars:
|
|
23
|
+
return self.vars[name]
|
|
24
|
+
if self.parent:
|
|
25
|
+
return self.parent.get(name)
|
|
26
|
+
if not isinstance(default, Nothing):
|
|
27
|
+
return default
|
|
28
|
+
del default
|
|
29
|
+
raise KeyError(name)
|
|
30
|
+
|
|
31
|
+
def set(self, name: str, value: Any) -> None:
|
|
32
|
+
"""
|
|
33
|
+
Set a variable in this scope.
|
|
34
|
+
:param name: Variable name
|
|
35
|
+
:param value: Variable value
|
|
36
|
+
"""
|
|
37
|
+
self.vars[name] = value
|
|
38
|
+
|
|
39
|
+
def update(self, mapping: Dict[str, Any]) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Update multiple variables in this scope.
|
|
42
|
+
:param mapping: Dictionary of variable names and values
|
|
43
|
+
"""
|
|
44
|
+
self.vars.update(mapping)
|
|
45
|
+
|
|
46
|
+
def contains(self, name: str) -> bool:
|
|
47
|
+
"""
|
|
48
|
+
Check if a variable exists in this scope or parent scopes.
|
|
49
|
+
:param name: Variable name
|
|
50
|
+
:return: True if variable exists, False otherwise
|
|
51
|
+
"""
|
|
52
|
+
if name in self.vars:
|
|
53
|
+
return True
|
|
54
|
+
if self.parent:
|
|
55
|
+
return self.parent.contains(name)
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
def keys(self) -> Set[str]:
|
|
59
|
+
"""
|
|
60
|
+
Get all variable names from this scope and parent scopes.
|
|
61
|
+
:return: Set of variable names
|
|
62
|
+
"""
|
|
63
|
+
keys = set(self.vars.keys())
|
|
64
|
+
if self.parent:
|
|
65
|
+
keys.update(self.parent.keys())
|
|
66
|
+
return keys
|
|
67
|
+
|
|
68
|
+
def clear(self) -> None:
|
|
69
|
+
"""Clear all variables in this scope (does not affect parent)."""
|
|
70
|
+
self.vars.clear()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@contextmanager
|
|
76
|
+
def new_scope(interpreter, initial_vars: Optional[Dict[str, Any]] = None):
|
|
77
|
+
"""
|
|
78
|
+
Context manager for creating a new scope temporarily.
|
|
79
|
+
:param interpreter: The interpreter instance
|
|
80
|
+
:param initial_vars: Optional initial variables for the new scope
|
|
81
|
+
"""
|
|
82
|
+
parent = interpreter.env
|
|
83
|
+
|
|
84
|
+
new_scope: Scope = Scope(parent=parent)
|
|
85
|
+
|
|
86
|
+
interpreter.env = new_scope
|
|
87
|
+
|
|
88
|
+
if initial_vars:
|
|
89
|
+
interpreter.env.update(initial_vars)
|
|
90
|
+
try:
|
|
91
|
+
yield
|
|
92
|
+
finally:
|
|
93
|
+
interpreter.clear()
|
|
94
|
+
interpreter.env = parent
|
|
95
|
+
|
|
@@ -40,6 +40,7 @@ __all__ = [
|
|
|
40
40
|
'PermissionNode',
|
|
41
41
|
'EvalGroupNode',
|
|
42
42
|
'ParamNode',
|
|
43
|
+
'GlobalNode',
|
|
43
44
|
'CodeNode',
|
|
44
45
|
'EvalNode',
|
|
45
46
|
'ReturnNode',
|
|
@@ -827,16 +828,35 @@ class ParamNode(ASTNode):
|
|
|
827
828
|
"body": [token.to_dict() for token in self.body]
|
|
828
829
|
}
|
|
829
830
|
|
|
831
|
+
|
|
832
|
+
class GlobalNode(ASTNode):
|
|
833
|
+
"""
|
|
834
|
+
Node representing env variables used in code node.
|
|
835
|
+
"""
|
|
836
|
+
def __init__(self, line: int, *args: Token):
|
|
837
|
+
super().__init__(line)
|
|
838
|
+
self.env_variables: tuple[Token, ...] = args
|
|
839
|
+
|
|
840
|
+
def __repr__(self) -> str:
|
|
841
|
+
return StrNode(f"<GLOBAL - {', '.join((str(i) for i in self.env_variables))}")
|
|
842
|
+
|
|
843
|
+
def to_dict(self):
|
|
844
|
+
return {
|
|
845
|
+
"type": "GlobalNode",
|
|
846
|
+
"env_variables": self.env_variables
|
|
847
|
+
}
|
|
848
|
+
|
|
830
849
|
class CodeNode(ASTNode):
|
|
831
850
|
"""
|
|
832
851
|
Node representing a block of code to pass in arguments.
|
|
833
852
|
"""
|
|
834
|
-
def __init__(self, body: list[ASTNode], line: int):
|
|
853
|
+
def __init__(self, body: list[ASTNode], line: int, global_env_vars: Optional[GlobalNode] = None):
|
|
835
854
|
"""
|
|
836
855
|
:param body: list of Node representing the code already parsed
|
|
837
856
|
"""
|
|
838
857
|
super().__init__(line)
|
|
839
858
|
self.body = body
|
|
859
|
+
self.global_env_vars: Optional[GlobalNode] = global_env_vars
|
|
840
860
|
|
|
841
861
|
def __repr__(self):
|
|
842
862
|
return StrNode(f"<CODE> - {self.body}")
|
|
@@ -848,9 +868,11 @@ class CodeNode(ASTNode):
|
|
|
848
868
|
"""
|
|
849
869
|
return {
|
|
850
870
|
"type": "CodeNode",
|
|
871
|
+
"global_env_vars": self.global_env_vars.to_dict(),
|
|
851
872
|
"body": [token.to_dict() for token in self.body]
|
|
852
873
|
}
|
|
853
874
|
|
|
875
|
+
|
|
854
876
|
class EvalNode(ASTNode):
|
|
855
877
|
"""
|
|
856
878
|
Node representing an evaluation in the AST.
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellParser/dshell_parser.py
RENAMED
|
@@ -6,6 +6,7 @@ __all__ = [
|
|
|
6
6
|
"ast_to_dict",
|
|
7
7
|
]
|
|
8
8
|
|
|
9
|
+
from .ast_nodes import GlobalNode
|
|
9
10
|
from ..DshellTokenizer.dshell_token_type import Token
|
|
10
11
|
from ..DshellTokenizer.dshell_token_type import DshellTokenType as DTT
|
|
11
12
|
from ..DshellTokenizer.dshell_token_type import DTT_DATA
|
|
@@ -202,6 +203,18 @@ def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[AST
|
|
|
202
203
|
blocks.pop()
|
|
203
204
|
return blocks, pointer
|
|
204
205
|
|
|
206
|
+
elif first_token_line_value == 'global':
|
|
207
|
+
if not isinstance(last_block, CodeNode):
|
|
208
|
+
raise SyntaxError(f"[GLOBAL] No code open on line {first_token_line.position}")
|
|
209
|
+
|
|
210
|
+
for i in range(1, len_tokens_by_line):
|
|
211
|
+
ident = tokens_by_line[i]
|
|
212
|
+
if ident.type != DTT.IDENT:
|
|
213
|
+
raise ValueError(f"[GLOBAL] '{ident}' value must be a ident on line {first_token_line.position}")
|
|
214
|
+
|
|
215
|
+
global_node = GlobalNode(line, *tokens_by_line[1:])
|
|
216
|
+
last_block.global_env_vars = global_node
|
|
217
|
+
|
|
205
218
|
elif first_token_line_value == 'eval':
|
|
206
219
|
if len_tokens_by_line_since_command_name < 1:
|
|
207
220
|
raise SyntaxError(f"[EVAL] take one or more arguments on line {first_token_line.position}")
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellTokenizer/dshell_keywords.py
RENAMED
|
@@ -17,7 +17,7 @@ from ..DshellInterpreteur.dshell_iterators import IntIterator
|
|
|
17
17
|
dshell_keyword: set[str] = {
|
|
18
18
|
'if', 'else', 'elif', 'loop', '#end', 'var', '#loop', '#if', 'sleep',
|
|
19
19
|
'param', '#param', 'code', '#code', 'eval', 'return', 'break',
|
|
20
|
-
'catch', '#catch', 'raise'
|
|
20
|
+
'catch', '#catch', 'raise', 'global'
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
dshell_discord_keyword: set[str] = {
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="dshellInterpreter",
|
|
8
|
-
version="1.2.
|
|
8
|
+
version="1.2.8.0",
|
|
9
9
|
author="Chronos",
|
|
10
10
|
author_email="vagabonwalybi@gmail.com",
|
|
11
11
|
description="A Discord bot interpreter for creating custom commands and automations.",
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
from contextlib import contextmanager
|
|
2
|
-
from typing import Any, Optional, Dict, Set, Union
|
|
3
|
-
from random import random
|
|
4
|
-
|
|
5
|
-
# manage all scope with one unique ID by scope to separate the interpreter and scopes
|
|
6
|
-
context_scope: dict[str, tuple[int, "Scope"]] = {}
|
|
7
|
-
|
|
8
|
-
def generate_scope_id() -> str:
|
|
9
|
-
"""
|
|
10
|
-
generate a new scope code unused
|
|
11
|
-
:return:
|
|
12
|
-
"""
|
|
13
|
-
while (_id := (str(random()) + str(random()))) in context_scope: pass
|
|
14
|
-
return _id
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def get_scope(_id: str) -> Union["Scope", None]:
|
|
18
|
-
"""
|
|
19
|
-
Get the current scope linked with an ID
|
|
20
|
-
:param _id:
|
|
21
|
-
:return: the scope link with the id, or None if the scope id is not found
|
|
22
|
-
"""
|
|
23
|
-
x = context_scope.get(_id, None)
|
|
24
|
-
return x[1] if x is not None else x
|
|
25
|
-
|
|
26
|
-
def get_usage_scope(_id: str) -> Union[int, None]:
|
|
27
|
-
"""
|
|
28
|
-
Get the usage number for a scope
|
|
29
|
-
:param _id: An integer, or None if the scope id is not found
|
|
30
|
-
:return:
|
|
31
|
-
"""
|
|
32
|
-
x = context_scope.get(_id, None)
|
|
33
|
-
return x[0] if x is not None else x
|
|
34
|
-
|
|
35
|
-
class Scope:
|
|
36
|
-
"""
|
|
37
|
-
Represents a variable scope with optional parent scope for nested scoping.
|
|
38
|
-
"""
|
|
39
|
-
def __init__(self, parent: Optional[str] = None):
|
|
40
|
-
self.parent: Optional[str] = parent
|
|
41
|
-
self.vars: Dict[str, Any] = {}
|
|
42
|
-
|
|
43
|
-
def get(self, name: str) -> Any:
|
|
44
|
-
"""
|
|
45
|
-
Get a variable value from this scope or parent scopes.
|
|
46
|
-
:param name: Variable name
|
|
47
|
-
:return: Variable value
|
|
48
|
-
:raises KeyError: If variable not found in any scope
|
|
49
|
-
"""
|
|
50
|
-
if name in self.vars:
|
|
51
|
-
return self.vars[name]
|
|
52
|
-
if self.parent:
|
|
53
|
-
if self.parent in context_scope:
|
|
54
|
-
return context_scope[self.parent][1].get(name)
|
|
55
|
-
raise Exception(f"Scope {self.parent} not found [get] !")
|
|
56
|
-
raise KeyError(name)
|
|
57
|
-
|
|
58
|
-
def set(self, name: str, value: Any) -> None:
|
|
59
|
-
"""
|
|
60
|
-
Set a variable in this scope.
|
|
61
|
-
:param name: Variable name
|
|
62
|
-
:param value: Variable value
|
|
63
|
-
"""
|
|
64
|
-
self.vars[name] = value
|
|
65
|
-
|
|
66
|
-
def update(self, mapping: Dict[str, Any]) -> None:
|
|
67
|
-
"""
|
|
68
|
-
Update multiple variables in this scope.
|
|
69
|
-
:param mapping: Dictionary of variable names and values
|
|
70
|
-
"""
|
|
71
|
-
self.vars.update(mapping)
|
|
72
|
-
|
|
73
|
-
def contains(self, name: str) -> bool:
|
|
74
|
-
"""
|
|
75
|
-
Check if a variable exists in this scope or parent scopes.
|
|
76
|
-
:param name: Variable name
|
|
77
|
-
:return: True if variable exists, False otherwise
|
|
78
|
-
"""
|
|
79
|
-
if name in self.vars:
|
|
80
|
-
return True
|
|
81
|
-
if self.parent:
|
|
82
|
-
if self.parent in context_scope:
|
|
83
|
-
return context_scope[self.parent][1].contains(name)
|
|
84
|
-
Exception(f"Scope {self.parent} not found [contains] !")
|
|
85
|
-
return False
|
|
86
|
-
|
|
87
|
-
def keys(self) -> Set[str]:
|
|
88
|
-
"""
|
|
89
|
-
Get all variable names from this scope and parent scopes.
|
|
90
|
-
:return: Set of variable names
|
|
91
|
-
"""
|
|
92
|
-
keys = set(self.vars.keys())
|
|
93
|
-
if self.parent:
|
|
94
|
-
if self.parent in context_scope:
|
|
95
|
-
keys.update(context_scope[self.parent][1].keys())
|
|
96
|
-
else:
|
|
97
|
-
Exception(f"Scope {self.parent} not found [keys] !")
|
|
98
|
-
return keys
|
|
99
|
-
|
|
100
|
-
def clear(self) -> None:
|
|
101
|
-
"""Clear all variables in this scope (does not affect parent)."""
|
|
102
|
-
self.vars.clear()
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def create_scope() -> str:
|
|
106
|
-
"""
|
|
107
|
-
Create a new scope and return the scope code
|
|
108
|
-
:return:
|
|
109
|
-
"""
|
|
110
|
-
_id = generate_scope_id()
|
|
111
|
-
scope = Scope()
|
|
112
|
-
context_scope[_id] = (1, scope)
|
|
113
|
-
return _id
|
|
114
|
-
|
|
115
|
-
def update_nbr_usage_scope(scope_id: str, nbr_usage: int):
|
|
116
|
-
"""
|
|
117
|
-
Update the usage number for a scope
|
|
118
|
-
:param nbr_usage:
|
|
119
|
-
:return:
|
|
120
|
-
"""
|
|
121
|
-
if scope_id not in context_scope:
|
|
122
|
-
raise Exception(f"Scope {scope_id} not found [update nbr usage scope] !")
|
|
123
|
-
|
|
124
|
-
new_usage = get_usage_scope(scope_id)+nbr_usage
|
|
125
|
-
|
|
126
|
-
if new_usage <= 0:
|
|
127
|
-
del context_scope[scope_id]
|
|
128
|
-
return
|
|
129
|
-
|
|
130
|
-
new = (new_usage, context_scope[scope_id][1])
|
|
131
|
-
|
|
132
|
-
del context_scope[scope_id]
|
|
133
|
-
context_scope[scope_id] = new
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
@contextmanager
|
|
137
|
-
def new_scope(interpreter, initial_vars: Optional[Dict[str, Any]] = None):
|
|
138
|
-
"""
|
|
139
|
-
Context manager for creating a new scope temporarily.
|
|
140
|
-
:param interpreter: The interpreter instance
|
|
141
|
-
:param initial_vars: Optional initial variables for the new scope
|
|
142
|
-
"""
|
|
143
|
-
parent = interpreter.scope_id
|
|
144
|
-
|
|
145
|
-
new_scope_id: str = generate_scope_id()
|
|
146
|
-
context_scope[new_scope_id] = (1, Scope(parent))
|
|
147
|
-
|
|
148
|
-
interpreter.scope_id = new_scope_id
|
|
149
|
-
interpreter.env = get_scope(new_scope_id)
|
|
150
|
-
|
|
151
|
-
if initial_vars:
|
|
152
|
-
interpreter.env.update(initial_vars)
|
|
153
|
-
try:
|
|
154
|
-
yield
|
|
155
|
-
finally:
|
|
156
|
-
interpreter.clear()
|
|
157
|
-
interpreter.env = get_scope(parent)
|
|
158
|
-
interpreter.scope_id = parent
|
|
159
|
-
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/__init__.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_channel.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_embed.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_file.py
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_member.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_message.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/dshell_role.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_file.py
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DISCORD_COMMANDS/utils/utils_list.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellInterpreteur/errors.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellPreProcess/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/Dshell/DshellTokenizer/dshell_tokenizer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/dshellInterpreter.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/dshellInterpreter.egg-info/requires.txt
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.11 → dshellinterpreter-1.2.8.0}/dshellInterpreter.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|