dshellInterpreter 1.2.7.2__tar.gz → 1.2.7.4__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.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_type_validation.py +1 -1
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/dshell_interpreter.py +2 -2
- dshellinterpreter-1.2.7.4/Dshell/DshellPreProcess/dshell_preprocess.py +73 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellTokenizer/dshell_keywords.py +21 -8
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellTokenizer/dshell_tokenizer.py +66 -87
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/full_import.py +1 -0
- {dshellinterpreter-1.2.7.2/dshellInterpreter.egg-info → dshellinterpreter-1.2.7.4}/PKG-INFO +1 -1
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4/dshellInterpreter.egg-info}/PKG-INFO +1 -1
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/setup.py +1 -1
- dshellinterpreter-1.2.7.2/Dshell/DshellPreProcess/dshell_preprocess.py +0 -38
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/__init__.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_channel.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_embed.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_file.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_interaction.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_member.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_message.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_role.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_ui.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/__init__.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_embed.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_file.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_global.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_list.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_member.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_message.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_numbers.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_permissions.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_string.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_thread.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/__init__.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/cached_messages.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/dshell_arguments.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/dshell_global_variables.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/dshell_iterators.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/dshell_scope.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/errors.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/utils_interpreter.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellParser/__init__.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellParser/ast_nodes.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellParser/dshell_parser.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellParser/errors.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellPreProcess/__init__.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellTokenizer/__init__.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellTokenizer/dshell_token_type.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/__init__.py +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/LICENSE +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/README.md +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/dshellInterpreter.egg-info/SOURCES.txt +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/dshellInterpreter.egg-info/dependency_links.txt +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/dshellInterpreter.egg-info/requires.txt +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/dshellInterpreter.egg-info/top_level.txt +0 -0
- {dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/setup.cfg +0 -0
|
@@ -117,7 +117,7 @@ def _validate_optional_permission(value, param_name: StrNode, command_name: StrN
|
|
|
117
117
|
:param command_name: The command name for error messages (optional)
|
|
118
118
|
:raises TypeError: If the value is not None and not a PermissionNode
|
|
119
119
|
"""
|
|
120
|
-
if value is not None and not isinstance(value, PermissionNode):
|
|
120
|
+
if value is not None and not isinstance(value, _MissingSentinel) and not isinstance(value, PermissionNode):
|
|
121
121
|
raise TypeError(f"[{command_name}] -> {param_name} must be a PermissionNode or None, not {type(value).__name__}")
|
|
122
122
|
|
|
123
123
|
|
|
@@ -88,7 +88,7 @@ class DshellInterpreteur:
|
|
|
88
88
|
'__message_add_reaction__': None, # Can be overwritten by add vars_env parameter to get the reaction added on message add event reaction
|
|
89
89
|
'__message_remove_reaction__': None, # Can be overwritten by add vars_env parameter to get the reaction removed on message remove event reaction
|
|
90
90
|
'__message_url__': StrNode(message.jump_url) if hasattr(message, 'jump_url') else None,
|
|
91
|
-
'__last_message__': IntNode(message.channel.last_message_id),
|
|
91
|
+
'__last_message__': IntNode(message.channel.last_message_id or 1),
|
|
92
92
|
|
|
93
93
|
'__channel__': IntNode(message.channel.id),
|
|
94
94
|
'__channel_name__': StrNode(message.channel.name),
|
|
@@ -102,7 +102,7 @@ class DshellInterpreteur:
|
|
|
102
102
|
'__guild_members__': ListNode([IntNode(member.id) for member in message.channel.guild.members], bypass_limit_elt=True, editable=False),
|
|
103
103
|
'__guild_member_count__': IntNode(message.channel.guild.member_count),
|
|
104
104
|
'__guild_icon__': StrNode(message.channel.guild.icon.url) if message.channel.guild.icon else None,
|
|
105
|
-
'__guild_owner_id__': IntNode(message.channel.guild.owner_id),
|
|
105
|
+
'__guild_owner_id__': IntNode(message.channel.guild.owner_id or 1),
|
|
106
106
|
'__guild_description__': StrNode(message.channel.guild.description),
|
|
107
107
|
'__guild_roles__': ListNode([IntNode(role.id) for role in message.channel.guild.roles], bypass_limit_elt=True, editable=False),
|
|
108
108
|
'__guild_roles_count__': IntNode(len(message.channel.guild.roles)),
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from ..full_import import sub, MULTILINE, StrEnum, search, compile, DOTALL
|
|
2
|
+
|
|
3
|
+
class PreProcessorInstructions(StrEnum):
|
|
4
|
+
DEFINE = "define"
|
|
5
|
+
|
|
6
|
+
class PreProcessorData:
|
|
7
|
+
def __init__(self, instruction: str, symbol: str, value: str):
|
|
8
|
+
self.instruction = instruction
|
|
9
|
+
self.symbol = symbol
|
|
10
|
+
self.value = value
|
|
11
|
+
|
|
12
|
+
def define(code: str, pre_processor_data: PreProcessorData) -> str:
|
|
13
|
+
"""
|
|
14
|
+
Replace all symbol with the current value
|
|
15
|
+
:param code: the code before tokenization
|
|
16
|
+
:param pre_processor_data: all data for the ##define pre-processor
|
|
17
|
+
:return:
|
|
18
|
+
"""
|
|
19
|
+
return sub(f"(?<![a-zA-Z]){pre_processor_data.symbol}(?![a-zA-Z])", pre_processor_data.value, code)
|
|
20
|
+
|
|
21
|
+
pre_processor_pattern = compile(r"^\s*## *([a-zA-Z]+) +([a-zA-Z]+)(?: +(.*))?$", flags=MULTILINE|DOTALL)
|
|
22
|
+
def preProcessor(code: list[str]) -> list[str]:
|
|
23
|
+
"""
|
|
24
|
+
Execute preprocessor line
|
|
25
|
+
:param code: a list of code line before tokenization
|
|
26
|
+
:return: a new list of string after pre-processor and since pre-processor instructions
|
|
27
|
+
"""
|
|
28
|
+
pre_processor_data: list[PreProcessorData] = list()
|
|
29
|
+
new_code: list[str] = []
|
|
30
|
+
|
|
31
|
+
for line in code:
|
|
32
|
+
|
|
33
|
+
line = removeCommentPreProcessor(line)
|
|
34
|
+
|
|
35
|
+
if pre_processor_match := search(pre_processor_pattern, line):
|
|
36
|
+
|
|
37
|
+
instruction: str = pre_processor_match.group(1).lower()
|
|
38
|
+
symbol: str = pre_processor_match.group(2)
|
|
39
|
+
value: str = pre_processor_match.group(3)
|
|
40
|
+
if instruction in PreProcessorInstructions:
|
|
41
|
+
pre_processor_data.append(PreProcessorData(instruction, symbol, value))
|
|
42
|
+
|
|
43
|
+
else:
|
|
44
|
+
# apply pre-processor instructions
|
|
45
|
+
line = applyPreProcessor(line, pre_processor_data)
|
|
46
|
+
new_code.append(line)
|
|
47
|
+
|
|
48
|
+
return new_code
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def applyPreProcessor(code: str, pre_processor_data: list[PreProcessorData]) -> str:
|
|
53
|
+
"""
|
|
54
|
+
Apply preprocessor data to code
|
|
55
|
+
:param line: the current line before tokenization
|
|
56
|
+
:param pre_processor_data:
|
|
57
|
+
:return:
|
|
58
|
+
"""
|
|
59
|
+
for pre_processor in pre_processor_data:
|
|
60
|
+
match pre_processor.instruction:
|
|
61
|
+
case "define":
|
|
62
|
+
code = define(code, pre_processor)
|
|
63
|
+
|
|
64
|
+
return code
|
|
65
|
+
|
|
66
|
+
def removeCommentPreProcessor(code: str) -> str:
|
|
67
|
+
"""
|
|
68
|
+
Remove all comment in the code
|
|
69
|
+
:param code:
|
|
70
|
+
:return:
|
|
71
|
+
"""
|
|
72
|
+
# add \ before or in :: like \:: or :\: disable comment. Usable in string to add :: characters sequence.
|
|
73
|
+
return sub(r"(?<!\\):(?<!\\)?:.*", "", code, flags=MULTILINE)
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellTokenizer/dshell_keywords.py
RENAMED
|
@@ -10,9 +10,10 @@ __all__ = [
|
|
|
10
10
|
|
|
11
11
|
from ..DISCORD_COMMANDS import *
|
|
12
12
|
|
|
13
|
-
from ..full_import import Callable
|
|
13
|
+
from ..full_import import Callable, ChainMap
|
|
14
14
|
from ..DshellInterpreteur.dshell_iterators import IntIterator
|
|
15
15
|
|
|
16
|
+
|
|
16
17
|
dshell_keyword: set[str] = {
|
|
17
18
|
'if', 'else', 'elif', 'loop', '#end', 'var', '#loop', '#if', 'sleep',
|
|
18
19
|
'param', '#param', 'code', '#code', 'eval', 'return', 'break',
|
|
@@ -174,7 +175,16 @@ Tuple format: (function, precedence, number of operands min, number of operands
|
|
|
174
175
|
Optional[index to translate into value])
|
|
175
176
|
"""
|
|
176
177
|
|
|
177
|
-
|
|
178
|
+
Operator = tuple[
|
|
179
|
+
Callable,
|
|
180
|
+
int,
|
|
181
|
+
int,
|
|
182
|
+
int,
|
|
183
|
+
Optional[int],
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
dshell_mathematical_operators: dict[str, Operator] = {
|
|
178
188
|
|
|
179
189
|
r"++": (lambda a: a + 1, 6, 1, 1, None),
|
|
180
190
|
r"--": (lambda a: a - 1, 6, 1, 1, None),
|
|
@@ -197,14 +207,14 @@ dshell_mathematical_operators: dict[str, tuple[Callable, int, int, int, Optional
|
|
|
197
207
|
|
|
198
208
|
}
|
|
199
209
|
|
|
200
|
-
dshell_logical_word_operators: dict[str,
|
|
210
|
+
dshell_logical_word_operators: dict[str, Operator] = {
|
|
201
211
|
r"and": (lambda a, b: bool(a and b), 2, 2, 2, None),
|
|
202
212
|
r"or": (lambda a, b: bool(a or b), 1, 2, 2, None),
|
|
203
213
|
r"not": (lambda a: not a, 3, 1, 1, None),
|
|
204
214
|
r"in": (lambda a, b: a in b, 4, 2, 2, None),
|
|
205
215
|
}
|
|
206
216
|
|
|
207
|
-
dshell_logical_operators: dict[str,
|
|
217
|
+
dshell_logical_operators: dict[str, Operator] = {
|
|
208
218
|
|
|
209
219
|
r"==": (lambda a, b: a == b, 4, 2, 2, None),
|
|
210
220
|
r"<=": (lambda a, b: a <= b, 4, 2, 2, None),
|
|
@@ -222,10 +232,13 @@ dshell_logical_operators: dict[str, tuple[Callable, int, int, int, Optional[int]
|
|
|
222
232
|
r">": (lambda a, b: a > b, 4, 2, 2, None),
|
|
223
233
|
r"!": (lambda a: not a, 3, 1, 1, None),
|
|
224
234
|
r"?": (lambda condition, first, second: first if condition else second, 1, 3, 3, 1),
|
|
225
|
-
#r".": (lambda target, attribute: target.call(attribute) if hasattr(target, attribute) and hasattr(target, 'call') else None, 9, 2, 2), # attribute access operator
|
|
226
|
-
|
|
227
235
|
}
|
|
228
236
|
|
|
229
|
-
dshell_operators:
|
|
237
|
+
dshell_operators: ChainMap[str, Operator] = ChainMap(
|
|
238
|
+
dshell_logical_operators,
|
|
239
|
+
dshell_logical_word_operators,
|
|
240
|
+
dshell_mathematical_operators)
|
|
241
|
+
|
|
242
|
+
"""dshell_operators: dict[str, tuple[Callable, int, int, int, Optional[int]]] = dshell_logical_operators.copy()
|
|
230
243
|
dshell_operators.update(dshell_logical_word_operators)
|
|
231
|
-
dshell_operators.update(dshell_mathematical_operators)
|
|
244
|
+
dshell_operators.update(dshell_mathematical_operators)"""
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellTokenizer/dshell_tokenizer.py
RENAMED
|
@@ -7,16 +7,15 @@ __all__ = [
|
|
|
7
7
|
from .dshell_token_type import Token
|
|
8
8
|
from .dshell_token_type import DshellTokenType as DTT
|
|
9
9
|
|
|
10
|
-
from Dshell.full_import import (
|
|
10
|
+
from Dshell.full_import import (
|
|
11
11
|
Pattern,
|
|
12
12
|
ASCII,
|
|
13
13
|
DOTALL,
|
|
14
14
|
IGNORECASE,
|
|
15
|
-
MULTILINE,
|
|
16
15
|
compile,
|
|
17
16
|
escape,
|
|
18
|
-
findall,
|
|
19
17
|
finditer,
|
|
18
|
+
Match,
|
|
20
19
|
sub)
|
|
21
20
|
|
|
22
21
|
from .dshell_keywords import (dshell_keyword,
|
|
@@ -26,7 +25,7 @@ from .dshell_keywords import (dshell_keyword,
|
|
|
26
25
|
dshell_logical_operators,
|
|
27
26
|
dshell_logical_word_operators)
|
|
28
27
|
|
|
29
|
-
from ..DshellPreProcess.dshell_preprocess import preProcessor
|
|
28
|
+
from ..DshellPreProcess.dshell_preprocess import preProcessor
|
|
30
29
|
|
|
31
30
|
MASK_CHARACTER = '§'
|
|
32
31
|
|
|
@@ -36,24 +35,23 @@ def is_line_empty(line: str) -> bool:
|
|
|
36
35
|
:param line: The line to check.
|
|
37
36
|
:return: True if the line is empty, False otherwise.
|
|
38
37
|
"""
|
|
39
|
-
return all(c in (MASK_CHARACTER, ' ') for c in line)
|
|
38
|
+
return all(c in (MASK_CHARACTER, ' ', '\n') for c in line)
|
|
40
39
|
|
|
41
40
|
table_regex: dict[DTT, Pattern] = {
|
|
42
|
-
DTT.COMMENT: compile(r"::(.*)", flags=MULTILINE),
|
|
43
41
|
DTT.STR: compile(r'"((?:[^\\"]|\\.)*)"', flags=DOTALL),
|
|
44
42
|
DTT.EVAL_L_EXPRESSION: compile(r"({)"),
|
|
45
43
|
DTT.EVAL_R_EXPRESSION: compile(r"(})"),
|
|
46
|
-
DTT.EVAL_L_GROUP: compile(
|
|
44
|
+
DTT.EVAL_L_GROUP: compile(rf"(\()"),
|
|
47
45
|
DTT.EVAL_R_GROUP: compile(r"(\))"),
|
|
48
46
|
DTT.EVAL_OUTDATED_GROUP: compile(r"(`)"),
|
|
49
47
|
DTT.LIST_L: compile(r"(\[)"),
|
|
50
48
|
DTT.LIST_R: compile(r"(])"),
|
|
51
49
|
DTT.PARAMETERS: compile(rf"--\*\s*([A-Za-z_]+)\s*", flags=ASCII),
|
|
52
|
-
DTT.STR_PARAMETER: compile(rf"
|
|
50
|
+
DTT.STR_PARAMETER: compile(rf"--'\s*([A-Za-z_]+)\s*", flags=ASCII),
|
|
53
51
|
DTT.PARAMETER: compile(rf"--\s*([A-Za-z_]+)\s*", flags=ASCII),
|
|
54
|
-
DTT.MENTION: compile(r'<(
|
|
52
|
+
DTT.MENTION: compile(r'<(?:@[!&]?|#)([0-9]+)>'),
|
|
55
53
|
DTT.KEYWORD: compile(rf"(?<!\w)(#?{'|'.join(dshell_keyword)})(?!\w)"),
|
|
56
|
-
DTT.DISCORD_KEYWORD: compile(rf"(
|
|
54
|
+
DTT.DISCORD_KEYWORD: compile(rf"(?<![\w\-])(#?{'|'.join(dshell_discord_keyword)})(?![\w\-])" , flags=IGNORECASE),
|
|
57
55
|
DTT.COMMAND: compile(rf"\b({'|'.join(dshell_commands.keys())})\b", flags=IGNORECASE),
|
|
58
56
|
DTT.FLOAT: compile(r"(\d+\.\d+)"),
|
|
59
57
|
DTT.HEXA: compile(r"(0[Xx][0-9a-fA-F]+)"),
|
|
@@ -65,21 +63,19 @@ table_regex: dict[DTT, Pattern] = {
|
|
|
65
63
|
DTT.BOOL: compile(r"(True|False)", flags=IGNORECASE),
|
|
66
64
|
DTT.NONE: compile(r"(None)", flags=IGNORECASE),
|
|
67
65
|
DTT.IDENT: compile(rf"([A-Za-z0-9_]+)"),
|
|
68
|
-
DTT.ANY_CHARACTER: compile(rf"([^{MASK_CHARACTER}\n]+)"),
|
|
69
66
|
}
|
|
70
67
|
|
|
68
|
+
backslash_pattern = compile(r"\\(.)", flags=DOTALL)
|
|
71
69
|
|
|
72
70
|
class DshellTokenizer:
|
|
73
71
|
|
|
74
|
-
def __init__(self, code: str
|
|
72
|
+
def __init__(self, code: str):
|
|
75
73
|
"""
|
|
76
74
|
Initialize the tokenizer.
|
|
77
75
|
:param code: The code to tokenize
|
|
78
76
|
:param match_any_character: Whether to match any character
|
|
79
77
|
"""
|
|
80
78
|
self.code: str = code
|
|
81
|
-
self.match_any_character: bool = match_any_character
|
|
82
|
-
self.data_pre_processor: list[PreProcessorData] = []
|
|
83
79
|
|
|
84
80
|
def start(self):
|
|
85
81
|
"""
|
|
@@ -87,6 +83,7 @@ class DshellTokenizer:
|
|
|
87
83
|
Returns an array of tokens per line (normally separated by \\n)
|
|
88
84
|
"""
|
|
89
85
|
split_commands = self.split(self.code)
|
|
86
|
+
split_commands = preProcessor(split_commands)
|
|
90
87
|
return self.tokenizer(split_commands)
|
|
91
88
|
|
|
92
89
|
def tokenizer(self, command_lines: list[str]) -> list[list[Token]]:
|
|
@@ -95,73 +92,47 @@ class DshellTokenizer:
|
|
|
95
92
|
:param command_lines: The code separated into multiple lines by the split method
|
|
96
93
|
"""
|
|
97
94
|
tokens: list[list[Token]] = []
|
|
95
|
+
ident_tokens = 0
|
|
98
96
|
|
|
99
|
-
line_number =
|
|
100
|
-
|
|
101
|
-
tokens_per_line: list[Token] = []
|
|
102
|
-
is_comment: bool = False
|
|
97
|
+
for line_number, line in enumerate(command_lines, start=1):
|
|
98
|
+
line: str = command_lines[line_number-1] # get the current line
|
|
103
99
|
|
|
100
|
+
# if the line is empty or already tokenized, pass the line.
|
|
104
101
|
if is_line_empty(line):
|
|
105
|
-
line_number += 1
|
|
106
102
|
continue
|
|
107
103
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
continue
|
|
111
|
-
else:
|
|
112
|
-
if self.data_pre_processor:
|
|
113
|
-
for processor_data in self.data_pre_processor:
|
|
114
|
-
line = applyPreProcessor(line, processor_data)
|
|
115
|
-
|
|
116
|
-
for token_type, pattern in table_regex.items(): # iterate the regex table to test all patterns on the line
|
|
117
|
-
|
|
118
|
-
if is_comment:
|
|
119
|
-
is_comment = False
|
|
120
|
-
break
|
|
121
|
-
|
|
122
|
-
if is_line_empty(line):
|
|
123
|
-
break
|
|
104
|
+
tokens.append([])
|
|
105
|
+
tokens_per_line = tokens[ident_tokens]
|
|
124
106
|
|
|
125
|
-
|
|
126
|
-
|
|
107
|
+
for token_type, regex in table_regex.items():
|
|
108
|
+
for match in finditer(regex, line):
|
|
109
|
+
match: Match
|
|
127
110
|
|
|
128
|
-
|
|
111
|
+
start_match = match.start()
|
|
112
|
+
end_match = match.end()
|
|
129
113
|
|
|
130
|
-
|
|
131
|
-
if len(match.group(0)) == len(line):
|
|
132
|
-
is_comment = True
|
|
133
|
-
break
|
|
134
|
-
else:
|
|
135
|
-
line = line[:match.start()]
|
|
136
|
-
continue
|
|
137
|
-
|
|
138
|
-
start_match = match.start() # start position of the match
|
|
139
|
-
|
|
140
|
-
token = Token(token_type, match.group(1), (line_number, start_match)) # record its token
|
|
114
|
+
token = Token(token_type, match.group(1), (line_number, start_match))
|
|
141
115
|
tokens_per_line.append(token)
|
|
142
116
|
|
|
143
117
|
if token_type == DTT.STR:
|
|
144
|
-
token.value =
|
|
145
|
-
|
|
146
|
-
len_match = len(match.group(0)) # length of the match found
|
|
147
|
-
line = line[:start_match] + (MASK_CHARACTER * len_match) + line[
|
|
148
|
-
match.end():] # replace the match to avoid matching it a second time
|
|
149
|
-
|
|
150
|
-
tokens_per_line.sort(key=lambda
|
|
151
|
-
token: token.position[1]) # sort the position based on token match positions to have them in code order
|
|
152
|
-
if tokens_per_line:
|
|
118
|
+
token.value = sub(backslash_pattern, lambda m: escape(m.group(1)), token.value)
|
|
153
119
|
|
|
154
|
-
|
|
155
|
-
|
|
120
|
+
len_match = len(match.group(0))
|
|
121
|
+
line = line[:start_match] + MASK_CHARACTER * len_match + line[end_match:]
|
|
156
122
|
|
|
157
|
-
|
|
123
|
+
tokens_per_line.sort(key=lambda t: t.position[1])
|
|
158
124
|
|
|
159
|
-
|
|
125
|
+
if tokens_per_line:
|
|
126
|
+
tokens[ident_tokens] = self.parse_group(tokens_per_line, line_number)
|
|
160
127
|
|
|
128
|
+
ident_tokens += 1
|
|
161
129
|
return tokens
|
|
162
130
|
|
|
163
131
|
@staticmethod
|
|
164
|
-
def split(command: str,
|
|
132
|
+
def split(command: str,
|
|
133
|
+
global_split='\n',
|
|
134
|
+
keep_grouping_character=True,
|
|
135
|
+
grouping_character='"') -> list[
|
|
165
136
|
str]:
|
|
166
137
|
"""
|
|
167
138
|
Separate commands into a list while respecting strings between quotes.
|
|
@@ -173,31 +144,39 @@ class DshellTokenizer:
|
|
|
173
144
|
:return: A list of split commands with restored strings.
|
|
174
145
|
"""
|
|
175
146
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
147
|
+
result: list[str] = []
|
|
148
|
+
in_string: bool = False # True if we are in a string
|
|
149
|
+
backslash: bool = False
|
|
150
|
+
line: list[str] = [] # buffer for each line
|
|
151
|
+
|
|
152
|
+
for char in command:
|
|
153
|
+
|
|
154
|
+
if backslash:
|
|
155
|
+
line.append('\\')
|
|
156
|
+
line.append(char)
|
|
157
|
+
backslash = False
|
|
158
|
+
|
|
159
|
+
elif char == global_split and not in_string:
|
|
160
|
+
result.append(''.join(line))
|
|
161
|
+
line.clear()
|
|
162
|
+
|
|
163
|
+
elif char == grouping_character:
|
|
164
|
+
in_string = not in_string
|
|
165
|
+
if keep_grouping_character:
|
|
166
|
+
line.append(char)
|
|
167
|
+
|
|
168
|
+
elif char == '\\':
|
|
169
|
+
backslash = True
|
|
170
|
+
|
|
171
|
+
else:
|
|
172
|
+
line.append(char)
|
|
173
|
+
|
|
174
|
+
result.append(''.join(line))
|
|
175
|
+
|
|
197
176
|
return result
|
|
198
177
|
|
|
199
178
|
@staticmethod
|
|
200
|
-
def parse_group(
|
|
179
|
+
def parse_group(tokens_in_line: list[Token],
|
|
201
180
|
line_position: int):
|
|
202
181
|
"""
|
|
203
182
|
Parse all list in the current token line and return the modified list line.
|
|
@@ -225,8 +204,8 @@ class DshellTokenizer:
|
|
|
225
204
|
last_tokens[-1].value.append(token)
|
|
226
205
|
|
|
227
206
|
i = 0
|
|
228
|
-
while i < len(
|
|
229
|
-
token =
|
|
207
|
+
while i < len(tokens_in_line):
|
|
208
|
+
token = tokens_in_line[i]
|
|
230
209
|
|
|
231
210
|
if token.type == DTT.LIST_L:
|
|
232
211
|
if last_tokens:
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="dshellInterpreter",
|
|
8
|
-
version="1.2.7.
|
|
8
|
+
version="1.2.7.4",
|
|
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,38 +0,0 @@
|
|
|
1
|
-
from ..full_import import search, sub, Optional
|
|
2
|
-
|
|
3
|
-
class PreProcessorData:
|
|
4
|
-
def __init__(self, instruction: str, symbol: str, value: str):
|
|
5
|
-
self.instruction = instruction
|
|
6
|
-
self.symbol = symbol
|
|
7
|
-
self.value = value
|
|
8
|
-
|
|
9
|
-
def define(code, pre_processor_data: PreProcessorData) -> str:
|
|
10
|
-
"""
|
|
11
|
-
Replace all symbol with the current value
|
|
12
|
-
:param symbol:
|
|
13
|
-
:param value:
|
|
14
|
-
:return:
|
|
15
|
-
"""
|
|
16
|
-
return sub(f"(?<![a-zA-Z]){pre_processor_data.symbol}(?![a-zA-Z])", pre_processor_data.value, code)
|
|
17
|
-
|
|
18
|
-
def preProcessor(code: str) -> Optional[PreProcessorData]:
|
|
19
|
-
"""
|
|
20
|
-
Execute preprocessor code
|
|
21
|
-
:param code:
|
|
22
|
-
:return:
|
|
23
|
-
"""
|
|
24
|
-
pre_process_match = search(r"^\s*##([a-zA-Z]+)\s+([a-zA-Z]+)\s+(.*)$", code)
|
|
25
|
-
if pre_process_match:
|
|
26
|
-
return PreProcessorData(pre_process_match.group(1).lower(), pre_process_match.group(2), pre_process_match.group(3))
|
|
27
|
-
return None
|
|
28
|
-
|
|
29
|
-
def applyPreProcessor(code: str, pre_processor_data: PreProcessorData):
|
|
30
|
-
"""
|
|
31
|
-
Apply preprocessor data to code
|
|
32
|
-
:param code:
|
|
33
|
-
:param pre_processor_data:
|
|
34
|
-
:return:
|
|
35
|
-
"""
|
|
36
|
-
match pre_processor_data.instruction:
|
|
37
|
-
case "define":
|
|
38
|
-
return define(code, pre_processor_data)
|
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_channel.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_embed.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_file.py
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_member.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_message.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_role.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/dshell_ui.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/__init__.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_embed.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DISCORD_COMMANDS/utils/utils_file.py
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/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
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/__init__.py
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/cached_messages.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellInterpreteur/dshell_scope.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellParser/dshell_parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/Dshell/DshellTokenizer/dshell_token_type.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/dshellInterpreter.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/dshellInterpreter.egg-info/requires.txt
RENAMED
|
File without changes
|
{dshellinterpreter-1.2.7.2 → dshellinterpreter-1.2.7.4}/dshellInterpreter.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|