dshellInterpreter 0.1.9__py3-none-any.whl → 0.1.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dshellInterpreter might be problematic. Click here for more details.
- Dshell/DISCORD_COMMANDS/__init__.py +1 -0
- Dshell/DISCORD_COMMANDS/dshell_channel.py +38 -9
- Dshell/DISCORD_COMMANDS/dshell_member.py +54 -0
- Dshell/DISCORD_COMMANDS/dshell_message.py +7 -7
- Dshell/_DshellInterpreteur/dshell_interpreter.py +90 -63
- Dshell/_DshellParser/ast_nodes.py +115 -12
- Dshell/_DshellParser/dshell_parser.py +3 -1
- Dshell/_DshellTokenizer/dshell_keywords.py +10 -8
- Dshell/_DshellTokenizer/dshell_token_type.py +1 -1
- Dshell/_DshellTokenizer/dshell_tokenizer.py +3 -2
- {dshellinterpreter-0.1.9.dist-info → dshellinterpreter-0.1.11.dist-info}/METADATA +1 -1
- dshellinterpreter-0.1.11.dist-info/RECORD +19 -0
- dshellinterpreter-0.1.9.dist-info/RECORD +0 -18
- {dshellinterpreter-0.1.9.dist-info → dshellinterpreter-0.1.11.dist-info}/WHEEL +0 -0
- {dshellinterpreter-0.1.9.dist-info → dshellinterpreter-0.1.11.dist-info}/licenses/LICENSE +0 -0
- {dshellinterpreter-0.1.9.dist-info → dshellinterpreter-0.1.11.dist-info}/top_level.txt +0 -0
|
@@ -8,15 +8,21 @@ from discord.abc import GuildChannel
|
|
|
8
8
|
__all__ = [
|
|
9
9
|
'dshell_create_text_channel',
|
|
10
10
|
'dshell_delete_channel',
|
|
11
|
-
'dshell_delete_channels'
|
|
11
|
+
'dshell_delete_channels',
|
|
12
|
+
'dshell_create_voice_channel'
|
|
12
13
|
]
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
async def dshell_create_text_channel(ctx: GuildChannel,
|
|
16
|
+
async def dshell_create_text_channel(ctx: GuildChannel,
|
|
17
|
+
name,
|
|
18
|
+
category=None,
|
|
19
|
+
position=MISSING,
|
|
20
|
+
slowmode=MISSING,
|
|
16
21
|
topic=MISSING, nsfw=MISSING,
|
|
17
|
-
permission: dict[Union[Member, Role], PermissionOverwrite] = MISSING
|
|
22
|
+
permission: dict[Union[Member, Role], PermissionOverwrite] = MISSING,
|
|
23
|
+
reason=None):
|
|
18
24
|
"""
|
|
19
|
-
|
|
25
|
+
Creates a text channel on the server
|
|
20
26
|
"""
|
|
21
27
|
|
|
22
28
|
channel_category = ctx.guild.get_channel(category)
|
|
@@ -27,15 +33,38 @@ async def dshell_create_text_channel(ctx: GuildChannel, name, category=None, pos
|
|
|
27
33
|
slowmode_delay=slowmode,
|
|
28
34
|
topic=topic,
|
|
29
35
|
nsfw=nsfw,
|
|
30
|
-
overwrites=permission
|
|
36
|
+
overwrites=permission,
|
|
37
|
+
reason=reason)
|
|
38
|
+
|
|
39
|
+
return created_channel.id
|
|
40
|
+
|
|
41
|
+
async def dshell_create_voice_channel(ctx: GuildChannel,
|
|
42
|
+
name,
|
|
43
|
+
category=None,
|
|
44
|
+
position=MISSING,
|
|
45
|
+
bitrate=MISSING,
|
|
46
|
+
permission: dict[Union[Member, Role], PermissionOverwrite] = MISSING,
|
|
47
|
+
reason=None):
|
|
48
|
+
"""
|
|
49
|
+
Creates a voice channel on the server
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
channel_category = ctx.guild.get_channel(category)
|
|
53
|
+
|
|
54
|
+
created_channel = await ctx.guild.create_voice_channel(name,
|
|
55
|
+
category=channel_category,
|
|
56
|
+
position=position,
|
|
57
|
+
bitrate=bitrate,
|
|
58
|
+
overwrites=permission,
|
|
59
|
+
reason=reason)
|
|
31
60
|
|
|
32
61
|
return created_channel.id
|
|
33
62
|
|
|
34
63
|
|
|
35
64
|
async def dshell_delete_channel(ctx: GuildChannel, channel=None, reason=None, timeout=0):
|
|
36
65
|
"""
|
|
37
|
-
|
|
38
|
-
|
|
66
|
+
Deletes a channel.
|
|
67
|
+
You can add a waiting time before it is deleted (in seconds)
|
|
39
68
|
"""
|
|
40
69
|
|
|
41
70
|
channel_to_delete = ctx if channel is None else ctx.guild.get_channel(channel)
|
|
@@ -52,8 +81,8 @@ async def dshell_delete_channel(ctx: GuildChannel, channel=None, reason=None, ti
|
|
|
52
81
|
|
|
53
82
|
async def dshell_delete_channels(ctx: GuildChannel, name=None, regex=None, reason=None):
|
|
54
83
|
"""
|
|
55
|
-
|
|
56
|
-
|
|
84
|
+
Deletes all channels with the same name and/or matching the same regex.
|
|
85
|
+
If neither is set, it will delete all channels with the same name as the one where the command was executed.
|
|
57
86
|
"""
|
|
58
87
|
for channel in ctx.guild.channels:
|
|
59
88
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from discord import Member, User, MISSING
|
|
2
|
+
from discord.abc import GuildChannel
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"dshell_ban_member",
|
|
7
|
+
"dshell_unban_member",
|
|
8
|
+
"dshell_kick_member"
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
async def dshell_ban_member(ctx: GuildChannel, member: int, reason: str = MISSING):
|
|
12
|
+
"""
|
|
13
|
+
Bans a member from the server.
|
|
14
|
+
"""
|
|
15
|
+
banned_member = ctx.guild.get_member(member)
|
|
16
|
+
|
|
17
|
+
if not banned_member:
|
|
18
|
+
return 1 # Member not found in the server
|
|
19
|
+
|
|
20
|
+
await ctx.guild.ban(banned_member, reason=reason)
|
|
21
|
+
|
|
22
|
+
return banned_member.id
|
|
23
|
+
|
|
24
|
+
async def dshell_unban_member(ctx: GuildChannel, user: int, reason: str = MISSING):
|
|
25
|
+
"""
|
|
26
|
+
Unbans a user from the server.
|
|
27
|
+
"""
|
|
28
|
+
banned_users = ctx.guild.bans()
|
|
29
|
+
user_to_unban = None
|
|
30
|
+
|
|
31
|
+
async for ban_entry in banned_users:
|
|
32
|
+
if ban_entry.user.id == user:
|
|
33
|
+
user_to_unban = ban_entry.user
|
|
34
|
+
break
|
|
35
|
+
|
|
36
|
+
if not user_to_unban:
|
|
37
|
+
return 1 # User not found in the banned list
|
|
38
|
+
|
|
39
|
+
await ctx.guild.unban(user_to_unban, reason=reason)
|
|
40
|
+
|
|
41
|
+
return user_to_unban.id
|
|
42
|
+
|
|
43
|
+
async def dshell_kick_member(ctx: GuildChannel, member: int, reason: str = MISSING):
|
|
44
|
+
"""
|
|
45
|
+
Kicks a member from the server.
|
|
46
|
+
"""
|
|
47
|
+
kicked_member = ctx.guild.get_member(member)
|
|
48
|
+
|
|
49
|
+
if not kicked_member:
|
|
50
|
+
return 1 # Member not found in the server
|
|
51
|
+
|
|
52
|
+
await ctx.guild.kick(kicked_member, reason=reason)
|
|
53
|
+
|
|
54
|
+
return kicked_member.id
|
|
@@ -11,12 +11,12 @@ __all__ = [
|
|
|
11
11
|
async def dshell_send_message(ctx: GuildChannel, message=None, delete=None, channel=None, embeds=None, embed=None):
|
|
12
12
|
from .._DshellParser.ast_nodes import ListNode
|
|
13
13
|
"""
|
|
14
|
-
|
|
14
|
+
Sends a message on Discord
|
|
15
15
|
"""
|
|
16
16
|
channel_to_send = ctx if channel is None else ctx.guild.get_channel(channel)
|
|
17
17
|
|
|
18
18
|
if channel_to_send is None:
|
|
19
|
-
raise Exception(f'
|
|
19
|
+
raise Exception(f'Channel {channel} not found!')
|
|
20
20
|
|
|
21
21
|
if embeds is None:
|
|
22
22
|
embeds = ListNode([])
|
|
@@ -36,25 +36,25 @@ async def dshell_send_message(ctx: GuildChannel, message=None, delete=None, chan
|
|
|
36
36
|
|
|
37
37
|
async def dshell_delete_message(ctx: GuildChannel, message, reason=None, delay=0):
|
|
38
38
|
"""
|
|
39
|
-
|
|
39
|
+
Deletes a message
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
-
delete_message = ctx.get_partial_message(message) #
|
|
42
|
+
delete_message = ctx.get_partial_message(message) # builds a reference to the message (even if it doesn't exist)
|
|
43
43
|
|
|
44
44
|
if delay > 3600:
|
|
45
|
-
raise Exception(f'
|
|
45
|
+
raise Exception(f'The message deletion delay is too long! ({delay} seconds)')
|
|
46
46
|
|
|
47
47
|
await delete_message.delete(delay=delay, reason=reason)
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
async def dshell_purge_message(ctx: GuildChannel, message_number, channel=None, reason=None):
|
|
51
51
|
"""
|
|
52
|
-
|
|
52
|
+
Purges messages from a channel
|
|
53
53
|
"""
|
|
54
54
|
|
|
55
55
|
purge_channel = ctx if channel is None else ctx.guild.get_channel(channel)
|
|
56
56
|
|
|
57
57
|
if purge_channel is None:
|
|
58
|
-
raise Exception(f"
|
|
58
|
+
raise Exception(f"Channel {channel} to purge not found!")
|
|
59
59
|
|
|
60
60
|
await purge_channel.purge(limit=message_number, reason=reason)
|
|
@@ -2,6 +2,7 @@ from asyncio import sleep
|
|
|
2
2
|
from re import findall
|
|
3
3
|
from typing import TypeVar, Union, Any, Optional, Callable
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
from discord import AutoShardedBot, Embed, Colour, PermissionOverwrite, Permissions, Guild, Member, Role
|
|
6
7
|
from discord.abc import GuildChannel, PrivateChannel
|
|
7
8
|
|
|
@@ -18,12 +19,17 @@ context = TypeVar('context', AutoShardedBot, GuildChannel, PrivateChannel)
|
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class DshellInterpreteur:
|
|
22
|
+
"""
|
|
23
|
+
Discord Dshell interpreter.
|
|
24
|
+
Make what you want with Dshell code to interact with Discord !
|
|
25
|
+
"""
|
|
21
26
|
|
|
22
|
-
def __init__(self,
|
|
27
|
+
def __init__(self, code: str, ctx: context, debug: bool = False):
|
|
23
28
|
"""
|
|
24
|
-
Interpreter Dshell code
|
|
29
|
+
Interpreter Dshell code
|
|
30
|
+
:param code: The code to interpret. Each line must end with a newline character, except SEPARATOR and SUB_SEPARATOR tokens.
|
|
25
31
|
"""
|
|
26
|
-
self.ast: list[ASTNode] = parse(DshellTokenizer(
|
|
32
|
+
self.ast: list[ASTNode] = parse(DshellTokenizer(code).start(), StartNode([]))[0]
|
|
27
33
|
self.env: dict[str, Any] = {}
|
|
28
34
|
self.ctx: context = ctx
|
|
29
35
|
if debug:
|
|
@@ -31,7 +37,16 @@ class DshellInterpreteur:
|
|
|
31
37
|
|
|
32
38
|
async def execute(self, ast: Optional[list[All_nodes]] = None):
|
|
33
39
|
"""
|
|
34
|
-
|
|
40
|
+
Executes the abstract syntax tree (AST) generated from the Dshell code.
|
|
41
|
+
|
|
42
|
+
This asynchronous method traverses and interprets each node in the AST, executing commands,
|
|
43
|
+
handling control flow structures (such as if, elif, else, and loops), managing variables,
|
|
44
|
+
and interacting with Discord through the provided context. It supports command execution,
|
|
45
|
+
variable assignment, sleep operations, and permission handling, among other features.
|
|
46
|
+
|
|
47
|
+
:param ast: Optional list of AST nodes to execute. If None, uses the interpreter's main AST.
|
|
48
|
+
:raises RuntimeError: If an EndNode is encountered, indicating execution should be stopped.
|
|
49
|
+
:raises Exception: If sleep duration is out of allowed bounds.
|
|
35
50
|
"""
|
|
36
51
|
if ast is None:
|
|
37
52
|
ast = self.ast
|
|
@@ -90,19 +105,20 @@ class DshellInterpreteur:
|
|
|
90
105
|
elif isinstance(node, SleepNode):
|
|
91
106
|
sleep_time = eval_expression(node.body, self)
|
|
92
107
|
if sleep_time > 3600:
|
|
93
|
-
raise Exception(f
|
|
108
|
+
raise Exception(f"Sleep time is too long! ({sleep_time} seconds) - maximum is 3600 seconds)")
|
|
94
109
|
elif sleep_time < 1:
|
|
95
|
-
raise Exception(f
|
|
110
|
+
raise Exception(f"Sleep time is too short! ({sleep_time} seconds) - minimum is 1 second)")
|
|
96
111
|
|
|
97
112
|
await sleep(sleep_time)
|
|
98
113
|
|
|
99
114
|
|
|
100
115
|
elif isinstance(node, EndNode):
|
|
101
|
-
raise RuntimeError(
|
|
116
|
+
raise RuntimeError("Execution stopped - EndNode encountered")
|
|
102
117
|
|
|
103
118
|
def eval_data_token(self, token: Token):
|
|
104
119
|
"""
|
|
105
|
-
|
|
120
|
+
Eval a data token and returns its value in Python.
|
|
121
|
+
:param token: The token to evaluate.
|
|
106
122
|
"""
|
|
107
123
|
|
|
108
124
|
if not hasattr(token, 'type'):
|
|
@@ -135,7 +151,9 @@ class DshellInterpreteur:
|
|
|
135
151
|
|
|
136
152
|
def eval_expression_inline(if_node: IfNode, interpreter: DshellInterpreteur) -> Token:
|
|
137
153
|
"""
|
|
138
|
-
|
|
154
|
+
Eval a conditional expression inline.
|
|
155
|
+
:param if_node: The IfNode to evaluate.
|
|
156
|
+
:param interpreter: The Dshell interpreter instance.
|
|
139
157
|
"""
|
|
140
158
|
if eval_expression(if_node.condition, interpreter):
|
|
141
159
|
return eval_expression(if_node.body, interpreter)
|
|
@@ -145,7 +163,9 @@ def eval_expression_inline(if_node: IfNode, interpreter: DshellInterpreteur) ->
|
|
|
145
163
|
|
|
146
164
|
def eval_expression(tokens: list[Token], interpreter: DshellInterpreteur) -> Any:
|
|
147
165
|
"""
|
|
148
|
-
|
|
166
|
+
Evaluates an arithmetic and logical expression.
|
|
167
|
+
:param tokens: A list of tokens representing the expression.
|
|
168
|
+
:param interpreter: The Dshell interpreter instance.
|
|
149
169
|
"""
|
|
150
170
|
postfix = to_postfix(tokens)
|
|
151
171
|
stack = []
|
|
@@ -170,24 +190,28 @@ def eval_expression(tokens: list[Token], interpreter: DshellInterpreteur) -> Any
|
|
|
170
190
|
stack.append(result)
|
|
171
191
|
|
|
172
192
|
else:
|
|
173
|
-
raise SyntaxError(f"
|
|
193
|
+
raise SyntaxError(f"Unexpected token type: {token.type} - {token.value}")
|
|
174
194
|
|
|
175
195
|
if len(stack) != 1:
|
|
176
|
-
raise SyntaxError("
|
|
196
|
+
raise SyntaxError("Invalid expression: stack should contain exactly one element after evaluation.")
|
|
177
197
|
|
|
178
198
|
return stack[0]
|
|
179
199
|
|
|
180
200
|
|
|
181
201
|
async def call_function(function: Callable, args: ArgsCommandNode, interpreter: DshellInterpreteur):
|
|
182
202
|
"""
|
|
183
|
-
|
|
203
|
+
Call the function with the given arguments.
|
|
204
|
+
It can be an async function !
|
|
205
|
+
:param function: The function to call.
|
|
206
|
+
:param args: The arguments to pass to the function.
|
|
207
|
+
:param interpreter: The Dshell interpreter instance.
|
|
184
208
|
"""
|
|
185
209
|
reformatted = regroupe_commandes(args.body, interpreter)[0]
|
|
186
210
|
|
|
187
211
|
# conversion des args en valeurs Python
|
|
188
212
|
absolute_args = reformatted.pop('*', list())
|
|
189
213
|
|
|
190
|
-
reformatted: dict[str, Token]
|
|
214
|
+
reformatted: dict[str, Token]
|
|
191
215
|
|
|
192
216
|
absolute_args.insert(0, interpreter.ctx)
|
|
193
217
|
keyword_args = {
|
|
@@ -198,64 +222,69 @@ async def call_function(function: Callable, args: ArgsCommandNode, interpreter:
|
|
|
198
222
|
|
|
199
223
|
def regroupe_commandes(body: list[Token], interpreter: DshellInterpreteur) -> list[dict[str, list[Any]]]:
|
|
200
224
|
"""
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
225
|
+
Groups the command arguments in the form of a python dictionary.
|
|
226
|
+
Note that you can specify the parameter you wish to pass via -- followed by the parameter name. But this is not mandatory!
|
|
227
|
+
Non-mandatory parameters will be stored in a list in the form of tokens with the key ‘*’.
|
|
228
|
+
The others, having been specified via a separator, will be in the form of a list of tokens with the IDENT token as key, following the separator for each argument.
|
|
229
|
+
If two parameters have the same name, the last one will overwrite the previous one.
|
|
230
|
+
To accept duplicates, use the SUB_SEPARATOR (~~) to create a sub-dictionary for parameters with the same name.
|
|
231
|
+
|
|
232
|
+
:param body: The list of tokens to group.
|
|
233
|
+
:param interpreter: The Dshell interpreter instance.
|
|
205
234
|
"""
|
|
206
|
-
tokens = {'*': []} #
|
|
207
|
-
current_arg = '*' #
|
|
235
|
+
tokens = {'*': []} # tokens to return
|
|
236
|
+
current_arg = '*' # the argument keys are the types they belong to. '*' is for all arguments not explicitly specified by a separator and an IDENT
|
|
208
237
|
n = len(body)
|
|
209
238
|
list_tokens: list[dict] = [tokens]
|
|
210
239
|
|
|
211
240
|
i = 0
|
|
212
241
|
while i < n:
|
|
213
242
|
if body[i].type == DTT.SEPARATOR and body[
|
|
214
|
-
i + 1].type == DTT.IDENT: #
|
|
215
|
-
current_arg = body[i + 1].value #
|
|
216
|
-
tokens[current_arg] = '' #
|
|
217
|
-
i += 2 #
|
|
243
|
+
i + 1].type == DTT.IDENT: # Check if it's a separator and if the next token is an IDENT
|
|
244
|
+
current_arg = body[i + 1].value # change the current argument. It will be impossible to return to '*'
|
|
245
|
+
tokens[current_arg] = '' # create a key/value pair for it
|
|
246
|
+
i += 2 # skip the IDENT after the separator since it has just been processed
|
|
218
247
|
|
|
219
248
|
elif body[
|
|
220
|
-
i].type == DTT.SUB_SEPARATOR: #
|
|
249
|
+
i].type == DTT.SUB_SEPARATOR: # allows to delimit parameters and to have several with the same name
|
|
221
250
|
list_tokens += regroupe_commandes(
|
|
222
251
|
[Token(
|
|
223
252
|
type_=DTT.SEPARATOR, value=body[i].value, position=body[i].position)
|
|
224
253
|
] + body[i + 1:], interpreter
|
|
225
|
-
) #
|
|
254
|
+
) # add a sub-dictionary for sub-commands
|
|
226
255
|
return list_tokens
|
|
227
256
|
|
|
228
257
|
else:
|
|
229
258
|
if current_arg == '*':
|
|
230
259
|
tokens[current_arg].append(interpreter.eval_data_token(body[i]))
|
|
231
260
|
else:
|
|
232
|
-
tokens[current_arg] = interpreter.eval_data_token(body[i]) #
|
|
261
|
+
tokens[current_arg] = interpreter.eval_data_token(body[i]) # add the token to the current argument
|
|
233
262
|
i += 1
|
|
234
263
|
return list_tokens
|
|
235
264
|
|
|
236
265
|
|
|
237
266
|
def build_embed(body: list[Token], fields: list[FieldEmbedNode], interpreter: DshellInterpreteur) -> Embed:
|
|
238
267
|
"""
|
|
239
|
-
|
|
268
|
+
Builds an embed from the command information.
|
|
240
269
|
"""
|
|
241
270
|
args_main_embed: dict[str, list[Any]] = regroupe_commandes(body, interpreter)[0]
|
|
242
|
-
args_main_embed.pop('*') #
|
|
243
|
-
args_main_embed: dict[str, Token] #
|
|
271
|
+
args_main_embed.pop('*') # remove unspecified parameters for the embed
|
|
272
|
+
args_main_embed: dict[str, Token] # specify what it contains from now on
|
|
244
273
|
|
|
245
274
|
args_fields: list[dict[str, Token]] = []
|
|
246
|
-
for field in fields: #
|
|
275
|
+
for field in fields: # do the same for the fields
|
|
247
276
|
a = regroupe_commandes(field.body, interpreter)[0]
|
|
248
277
|
a.pop('*')
|
|
249
278
|
a: dict[str, Token]
|
|
250
279
|
args_fields.append(a)
|
|
251
280
|
|
|
252
281
|
if 'color' in args_main_embed and isinstance(args_main_embed['color'],
|
|
253
|
-
ListNode): #
|
|
282
|
+
ListNode): # if color is a ListNode, convert it to Colour
|
|
254
283
|
args_main_embed['color'] = Colour.from_rgb(*args_main_embed['color'])
|
|
255
284
|
|
|
256
|
-
embed = Embed(**args_main_embed) #
|
|
285
|
+
embed = Embed(**args_main_embed) # build the main embed
|
|
257
286
|
for field in args_fields:
|
|
258
|
-
embed.add_field(**field) #
|
|
287
|
+
embed.add_field(**field) # add all fields
|
|
259
288
|
|
|
260
289
|
return embed
|
|
261
290
|
|
|
@@ -263,7 +292,7 @@ def build_embed(body: list[Token], fields: list[FieldEmbedNode], interpreter: Ds
|
|
|
263
292
|
def build_permission(body: list[Token], interpreter: DshellInterpreteur) -> dict[
|
|
264
293
|
Union[Member, Role], PermissionOverwrite]:
|
|
265
294
|
"""
|
|
266
|
-
|
|
295
|
+
Builds a dictionary of PermissionOverwrite objects from the command information.
|
|
267
296
|
"""
|
|
268
297
|
args_permissions: list[dict[str, list[Any]]] = regroupe_commandes(body, interpreter)
|
|
269
298
|
permissions: dict[Union[Member, Role], PermissionOverwrite] = {}
|
|
@@ -272,12 +301,12 @@ def build_permission(body: list[Token], interpreter: DshellInterpreteur) -> dict
|
|
|
272
301
|
i.pop('*')
|
|
273
302
|
permissions.update(DshellPermissions(i).get_permission_overwrite(interpreter.ctx.guild))
|
|
274
303
|
|
|
275
|
-
|
|
304
|
+
return permissions
|
|
276
305
|
|
|
277
306
|
|
|
278
307
|
class DshellIterator:
|
|
279
308
|
"""
|
|
280
|
-
|
|
309
|
+
Used to transform anything into an iterable
|
|
281
310
|
"""
|
|
282
311
|
|
|
283
312
|
def __init__(self, data):
|
|
@@ -301,20 +330,20 @@ class DshellPermissions:
|
|
|
301
330
|
|
|
302
331
|
def __init__(self, target: dict[str, list[int]]):
|
|
303
332
|
"""
|
|
304
|
-
|
|
305
|
-
:param target:
|
|
306
|
-
|
|
307
|
-
|
|
333
|
+
Creates a Dshell permissions object.
|
|
334
|
+
:param target: A dictionary containing parameters and their values.
|
|
335
|
+
Expected parameters: “allow”, “deny”, ‘members’, “roles”.
|
|
336
|
+
For “members” and “roles”, values must be ID ListNodes.
|
|
308
337
|
"""
|
|
309
338
|
self.target: dict[str, Union[ListNode, int]] = target
|
|
310
339
|
|
|
311
340
|
@staticmethod
|
|
312
341
|
def get_instance(guild: Guild, target_id: int) -> Union[Member, Role]:
|
|
313
342
|
"""
|
|
314
|
-
|
|
315
|
-
:param guild:
|
|
316
|
-
:param target_id:
|
|
317
|
-
:return:
|
|
343
|
+
Returns the instance corresponding to the given id. Only a Member or Role.
|
|
344
|
+
:param guild: The Discord server in which to search
|
|
345
|
+
:param target_id: The ID of the member or role
|
|
346
|
+
:return: An instance of Member or Role
|
|
318
347
|
"""
|
|
319
348
|
try:
|
|
320
349
|
member = DshellPermissions.get_member(guild, target_id)
|
|
@@ -332,48 +361,46 @@ class DshellPermissions:
|
|
|
332
361
|
if role is not None:
|
|
333
362
|
return role
|
|
334
363
|
|
|
335
|
-
raise ValueError(f"Aucun membre ou rôle trouvé avec l'ID {target_id} dans le serveur {guild.name}.")
|
|
336
|
-
|
|
337
364
|
@staticmethod
|
|
338
365
|
def get_member(guild: Guild, target_id: int) -> Member:
|
|
339
366
|
"""
|
|
340
|
-
|
|
341
|
-
:param guild:
|
|
342
|
-
:param target_id:
|
|
343
|
-
:return:
|
|
367
|
+
Returns the Member instance corresponding to the given id.
|
|
368
|
+
:param guild: The Discord server to search
|
|
369
|
+
:param target_id: The member ID
|
|
370
|
+
:return: A Member instance
|
|
344
371
|
"""
|
|
345
372
|
member = guild.get_member(target_id)
|
|
346
373
|
if member is not None:
|
|
347
374
|
return member
|
|
348
375
|
|
|
349
|
-
raise ValueError(f"
|
|
376
|
+
raise ValueError(f"No member found with ID {target_id} in guild {guild.name}.")
|
|
350
377
|
|
|
351
378
|
@staticmethod
|
|
352
379
|
def get_role(guild: Guild, target_id: int) -> Role:
|
|
353
380
|
"""
|
|
354
|
-
|
|
355
|
-
:param guild:
|
|
356
|
-
:param target_id:
|
|
357
|
-
:return:
|
|
381
|
+
Returns the Role instance corresponding to the given id.
|
|
382
|
+
:param guild: The Discord server to search
|
|
383
|
+
:param target_id: The role ID
|
|
384
|
+
:return: A Role instance
|
|
358
385
|
"""
|
|
359
386
|
role = guild.get_role(target_id)
|
|
360
387
|
if role is not None:
|
|
361
388
|
return role
|
|
362
389
|
|
|
363
|
-
raise ValueError(f"
|
|
390
|
+
raise ValueError(f"No role found with ID {target_id} in guild {guild.name}.")
|
|
364
391
|
|
|
365
392
|
def get_permission_overwrite(self, guild: Guild) -> dict[Union[Member, Role], PermissionOverwrite]:
|
|
366
393
|
"""
|
|
367
|
-
|
|
368
|
-
:param guild:
|
|
369
|
-
:return:
|
|
394
|
+
Returns a PermissionOverwrite object with member and role permissions.
|
|
395
|
+
:param guild: The Discord server
|
|
396
|
+
:return: A dictionary of PermissionOverwrite objects with members and roles as keys
|
|
370
397
|
"""
|
|
371
398
|
permissions: dict[Union[Member, Role], PermissionOverwrite] = {}
|
|
372
399
|
target_keys = self.target.keys()
|
|
373
400
|
|
|
374
401
|
if 'members' in target_keys:
|
|
375
402
|
for member_id in (
|
|
376
|
-
self.target['members'] if isinstance(self.target['members'], ListNode) else [self.target['members']]): #
|
|
403
|
+
self.target['members'] if isinstance(self.target['members'], ListNode) else [self.target['members']]): # allow a single ID
|
|
377
404
|
member = self.get_member(guild, member_id)
|
|
378
405
|
permissions[member] = PermissionOverwrite.from_pair(
|
|
379
406
|
allow=Permissions(permissions=self.target.get('allow', 0)),
|
|
@@ -382,13 +409,13 @@ class DshellPermissions:
|
|
|
382
409
|
|
|
383
410
|
elif 'roles' in target_keys:
|
|
384
411
|
for role_id in (
|
|
385
|
-
self.target['roles'] if isinstance(self.target['roles'], ListNode) else [self.target['roles']]):
|
|
412
|
+
self.target['roles'] if isinstance(self.target['roles'], ListNode) else [self.target['roles']]): # allow a single ID
|
|
386
413
|
role = self.get_role(guild, role_id)
|
|
387
414
|
permissions[role] = PermissionOverwrite.from_pair(
|
|
388
415
|
allow=Permissions(permissions=self.target.get('allow', 0)),
|
|
389
416
|
deny=Permissions(permissions=self.target.get('deny', 0))
|
|
390
417
|
)
|
|
391
418
|
else:
|
|
392
|
-
raise ValueError("
|
|
419
|
+
raise ValueError("No members or roles specified in the permissions target.")
|
|
393
420
|
|
|
394
421
|
return permissions
|
|
@@ -23,10 +23,16 @@ __all__ = [
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class ASTNode:
|
|
26
|
+
"""
|
|
27
|
+
Base class for all AST nodes.
|
|
28
|
+
"""
|
|
26
29
|
pass
|
|
27
30
|
|
|
28
31
|
|
|
29
32
|
class StartNode(ASTNode):
|
|
33
|
+
"""
|
|
34
|
+
Node representing the start of the AST.
|
|
35
|
+
"""
|
|
30
36
|
def __init__(self, body: list):
|
|
31
37
|
self.body = body
|
|
32
38
|
|
|
@@ -35,7 +41,13 @@ class StartNode(ASTNode):
|
|
|
35
41
|
|
|
36
42
|
|
|
37
43
|
class ElseNode(ASTNode):
|
|
44
|
+
"""
|
|
45
|
+
Node representing the 'else' part of an if statement.
|
|
46
|
+
"""
|
|
38
47
|
def __init__(self, body: list[Token]):
|
|
48
|
+
"""
|
|
49
|
+
:param body: list of tokens representing the body of the else statement
|
|
50
|
+
"""
|
|
39
51
|
self.body = body
|
|
40
52
|
|
|
41
53
|
def __repr__(self):
|
|
@@ -43,7 +55,15 @@ class ElseNode(ASTNode):
|
|
|
43
55
|
|
|
44
56
|
|
|
45
57
|
class ElifNode(ASTNode):
|
|
58
|
+
"""
|
|
59
|
+
Node representing an 'elif' part of an if statement.
|
|
60
|
+
"""
|
|
46
61
|
def __init__(self, condition: list[Token], body: list[Token], parent: "IfNode"):
|
|
62
|
+
"""
|
|
63
|
+
:param condition: list of tokens representing the condition for the elif
|
|
64
|
+
:param body: list of tokens representing the body of the elif
|
|
65
|
+
:param parent: the if node that this elif belongs to
|
|
66
|
+
"""
|
|
47
67
|
self.condition = condition
|
|
48
68
|
self.body = body
|
|
49
69
|
self.parent = parent
|
|
@@ -53,8 +73,17 @@ class ElifNode(ASTNode):
|
|
|
53
73
|
|
|
54
74
|
|
|
55
75
|
class IfNode(ASTNode):
|
|
76
|
+
"""
|
|
77
|
+
Node representing an 'if' statement, which can contain 'elif' and 'else' parts.
|
|
78
|
+
"""
|
|
56
79
|
def __init__(self, condition: list[Token], body: list[Token], elif_nodes: Optional[list[ElifNode]] = None,
|
|
57
80
|
else_body: Optional[ElseNode] = None):
|
|
81
|
+
"""
|
|
82
|
+
:param condition: list of tokens representing the condition for the if statement
|
|
83
|
+
:param body: list of tokens representing the body of the if statement
|
|
84
|
+
:param elif_nodes: optional list of ElifNode instances representing 'elif' parts
|
|
85
|
+
:param else_body: optional ElseNode instance representing the 'else' part
|
|
86
|
+
"""
|
|
58
87
|
self.condition = condition
|
|
59
88
|
self.body = body
|
|
60
89
|
self.elif_nodes = elif_nodes
|
|
@@ -65,8 +94,15 @@ class IfNode(ASTNode):
|
|
|
65
94
|
|
|
66
95
|
|
|
67
96
|
class LoopNode(ASTNode):
|
|
97
|
+
"""
|
|
98
|
+
Node representing a loop structure in the AST.
|
|
99
|
+
"""
|
|
68
100
|
def __init__(self, variable: "VarNode", body: list):
|
|
69
|
-
|
|
101
|
+
"""
|
|
102
|
+
:param variable: VarNode representing the loop variable. This variable will be used to iterate over the body. Can contain a ListNode, string or integer.
|
|
103
|
+
:param body: list of tokens representing the body of the loop
|
|
104
|
+
"""
|
|
105
|
+
self.variable = variable
|
|
70
106
|
self.body = body
|
|
71
107
|
|
|
72
108
|
def __repr__(self):
|
|
@@ -74,7 +110,13 @@ class LoopNode(ASTNode):
|
|
|
74
110
|
|
|
75
111
|
|
|
76
112
|
class ArgsCommandNode(ASTNode):
|
|
113
|
+
"""
|
|
114
|
+
Node representing the arguments of a command in the AST.
|
|
115
|
+
"""
|
|
77
116
|
def __init__(self, body: list[Token]):
|
|
117
|
+
"""
|
|
118
|
+
:param body: list of tokens representing the arguments of the command
|
|
119
|
+
"""
|
|
78
120
|
self.body: list[Token] = body
|
|
79
121
|
|
|
80
122
|
def __repr__(self):
|
|
@@ -82,7 +124,14 @@ class ArgsCommandNode(ASTNode):
|
|
|
82
124
|
|
|
83
125
|
|
|
84
126
|
class CommandNode(ASTNode):
|
|
127
|
+
"""
|
|
128
|
+
Node representing a command in the AST.
|
|
129
|
+
"""
|
|
85
130
|
def __init__(self, name: str, body: ArgsCommandNode):
|
|
131
|
+
"""
|
|
132
|
+
:param name: The command name (e.g., "sm", "cc")
|
|
133
|
+
:param body: ArgsCommandNode containing the arguments of the command
|
|
134
|
+
"""
|
|
86
135
|
self.name = name
|
|
87
136
|
self.body = body
|
|
88
137
|
|
|
@@ -91,7 +140,14 @@ class CommandNode(ASTNode):
|
|
|
91
140
|
|
|
92
141
|
|
|
93
142
|
class VarNode(ASTNode):
|
|
143
|
+
"""
|
|
144
|
+
Node representing a variable declaration in the AST.
|
|
145
|
+
"""
|
|
94
146
|
def __init__(self, name: Token, body: list[Token]):
|
|
147
|
+
"""
|
|
148
|
+
:param name: Token representing the variable name
|
|
149
|
+
:param body: list of tokens representing the body of the variable
|
|
150
|
+
"""
|
|
95
151
|
self.name = name
|
|
96
152
|
self.body = body
|
|
97
153
|
|
|
@@ -100,6 +156,9 @@ class VarNode(ASTNode):
|
|
|
100
156
|
|
|
101
157
|
|
|
102
158
|
class EndNode(ASTNode):
|
|
159
|
+
"""
|
|
160
|
+
Node representing the end of the AST.
|
|
161
|
+
"""
|
|
103
162
|
def __init__(self):
|
|
104
163
|
pass
|
|
105
164
|
|
|
@@ -108,7 +167,13 @@ class EndNode(ASTNode):
|
|
|
108
167
|
|
|
109
168
|
|
|
110
169
|
class FieldEmbedNode(ASTNode):
|
|
170
|
+
"""
|
|
171
|
+
Node representing a field in an embed structure.
|
|
172
|
+
"""
|
|
111
173
|
def __init__(self, body: list[Token]):
|
|
174
|
+
"""
|
|
175
|
+
:param body: list of tokens representing the field content
|
|
176
|
+
"""
|
|
112
177
|
self.body: list[Token] = body
|
|
113
178
|
|
|
114
179
|
def __repr__(self):
|
|
@@ -116,7 +181,14 @@ class FieldEmbedNode(ASTNode):
|
|
|
116
181
|
|
|
117
182
|
|
|
118
183
|
class EmbedNode(ASTNode):
|
|
184
|
+
"""
|
|
185
|
+
Node representing an embed structure in the AST.
|
|
186
|
+
"""
|
|
119
187
|
def __init__(self, body: list[Token], fields: list[FieldEmbedNode]):
|
|
188
|
+
"""
|
|
189
|
+
:param body: list of tokens representing the embed content
|
|
190
|
+
:param fields: list of FieldEmbedNode instances representing the fields of the embed
|
|
191
|
+
"""
|
|
120
192
|
self.body = body
|
|
121
193
|
self.fields = fields
|
|
122
194
|
|
|
@@ -125,7 +197,13 @@ class EmbedNode(ASTNode):
|
|
|
125
197
|
|
|
126
198
|
|
|
127
199
|
class PermissionNode(ASTNode):
|
|
200
|
+
"""
|
|
201
|
+
Node representing a permission structure in the AST.
|
|
202
|
+
"""
|
|
128
203
|
def __init__(self, body: list[Token]):
|
|
204
|
+
"""
|
|
205
|
+
:param body: list of tokens representing the permission content
|
|
206
|
+
"""
|
|
129
207
|
self.body = body
|
|
130
208
|
|
|
131
209
|
def __repr__(self):
|
|
@@ -133,7 +211,13 @@ class PermissionNode(ASTNode):
|
|
|
133
211
|
|
|
134
212
|
|
|
135
213
|
class SleepNode(ASTNode):
|
|
214
|
+
"""
|
|
215
|
+
Node representing a sleep command in the AST.
|
|
216
|
+
"""
|
|
136
217
|
def __init__(self, body: list[Token]):
|
|
218
|
+
"""
|
|
219
|
+
:param body: list of tokens representing the sleep duration
|
|
220
|
+
"""
|
|
137
221
|
self.body = body
|
|
138
222
|
|
|
139
223
|
def __repr__(self):
|
|
@@ -142,14 +226,20 @@ class SleepNode(ASTNode):
|
|
|
142
226
|
|
|
143
227
|
class IdentOperationNode(ASTNode):
|
|
144
228
|
"""
|
|
145
|
-
|
|
146
|
-
|
|
229
|
+
Node representing an operation on an identifier in the AST.
|
|
230
|
+
Manages operations on idendifiers (function calls)
|
|
231
|
+
Ensure that the function call returns the associated class to allow nesting. Not mandatory in itself if it returns something
|
|
147
232
|
"""
|
|
148
233
|
|
|
149
234
|
def __init__(self, ident: Token, function: Token, args: Token):
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
235
|
+
"""
|
|
236
|
+
:param ident: Token representing the identifier (e.g., a class or object)
|
|
237
|
+
:param function: Token representing the function to be called on the identifier
|
|
238
|
+
:param args: Token representing the arguments passed to the function
|
|
239
|
+
"""
|
|
240
|
+
self.ident = ident
|
|
241
|
+
self.function = function
|
|
242
|
+
self.args = args
|
|
153
243
|
|
|
154
244
|
def __repr__(self):
|
|
155
245
|
return f"<IDENT OPERATION> - {self.ident}.{self.function}({self.args})"
|
|
@@ -157,33 +247,42 @@ class IdentOperationNode(ASTNode):
|
|
|
157
247
|
|
|
158
248
|
class ListNode(ASTNode):
|
|
159
249
|
"""
|
|
160
|
-
|
|
161
|
-
|
|
250
|
+
Node representing a list structure in the AST.
|
|
251
|
+
Iterable class for browsing lists created from Dshell code.
|
|
252
|
+
This class also lets you interact with the list via specific methods not built in by python.
|
|
162
253
|
"""
|
|
163
254
|
|
|
164
255
|
def __init__(self, body: list[Any]):
|
|
256
|
+
"""
|
|
257
|
+
:param body: list of elements to initialize the ListNode with
|
|
258
|
+
"""
|
|
165
259
|
self.iterable: list[Any] = body
|
|
166
260
|
self.len_iterable: int = len(body)
|
|
167
261
|
self.iterateur_count: int = 0
|
|
168
262
|
|
|
169
263
|
def add(self, value: Any):
|
|
170
264
|
"""
|
|
171
|
-
|
|
265
|
+
Add a value to the list.
|
|
172
266
|
"""
|
|
173
267
|
if self.len_iterable > 10000:
|
|
174
|
-
raise PermissionError('
|
|
268
|
+
raise PermissionError('The list is too long, it must not exceed 10,000 elements !')
|
|
175
269
|
|
|
176
270
|
self.iterable.append(value)
|
|
177
271
|
self.len_iterable += 1
|
|
178
272
|
|
|
179
273
|
def remove(self, value: Any, number: int = 1):
|
|
180
274
|
"""
|
|
181
|
-
|
|
275
|
+
Remove a value from the list.
|
|
182
276
|
"""
|
|
183
277
|
if number < 1:
|
|
184
|
-
raise Exception(f"
|
|
278
|
+
raise Exception(f"The number of elements to remove must be at least 1, not {number} !")
|
|
185
279
|
|
|
186
280
|
def __add__(self, other: "ListNode"):
|
|
281
|
+
"""
|
|
282
|
+
Add another ListNode to this one.
|
|
283
|
+
:param other: Another ListNode to add to this one.
|
|
284
|
+
:return: Instance of ListNode with combined elements.
|
|
285
|
+
"""
|
|
187
286
|
for i in other:
|
|
188
287
|
self.add(i)
|
|
189
288
|
return self
|
|
@@ -192,6 +291,10 @@ class ListNode(ASTNode):
|
|
|
192
291
|
return self
|
|
193
292
|
|
|
194
293
|
def __next__(self):
|
|
294
|
+
"""
|
|
295
|
+
Iterate over the elements of the list.
|
|
296
|
+
:return: an element from the list.
|
|
297
|
+
"""
|
|
195
298
|
|
|
196
299
|
if self.iterateur_count >= self.len_iterable:
|
|
197
300
|
self.iterateur_count = 0
|
|
@@ -32,7 +32,9 @@ if TYPE_CHECKING:
|
|
|
32
32
|
|
|
33
33
|
def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[ASTNode], int]:
|
|
34
34
|
"""
|
|
35
|
-
|
|
35
|
+
Parse the list of tokens and return a list of AST nodes.
|
|
36
|
+
:param token_lines: table of tokens
|
|
37
|
+
:param start_node: the node where to start the parsing
|
|
36
38
|
"""
|
|
37
39
|
pointeur = 0 # pointeur sur les listes de tokens pour savoir ou parser
|
|
38
40
|
blocks: list[Union[ASTNode, EndNode]] = [start_node] # liste d'imbrication des blocks pour gérer l'imbrication
|
|
@@ -11,6 +11,7 @@ from typing import Callable
|
|
|
11
11
|
|
|
12
12
|
from ..DISCORD_COMMANDS.dshell_channel import *
|
|
13
13
|
from ..DISCORD_COMMANDS.dshell_message import *
|
|
14
|
+
from ..DISCORD_COMMANDS.dshell_member import *
|
|
14
15
|
|
|
15
16
|
dshell_keyword: set[str] = {
|
|
16
17
|
'if', 'else', 'elif', 'loop', '#end', 'var', '#loop', '#if', 'sleep'
|
|
@@ -24,11 +25,12 @@ dshell_commands: dict[str, Callable] = {
|
|
|
24
25
|
"dm": dshell_delete_message,
|
|
25
26
|
"pm": dshell_purge_message,
|
|
26
27
|
"cc": dshell_create_text_channel, # create channel
|
|
28
|
+
"cvc": dshell_create_voice_channel, # create voice channel
|
|
27
29
|
"dc": dshell_delete_channel, # delete channel
|
|
28
|
-
"dcs": dshell_delete_channels,
|
|
29
|
-
"
|
|
30
|
-
#
|
|
31
|
-
"
|
|
30
|
+
"dcs": dshell_delete_channels, # delete several channels by name or regex
|
|
31
|
+
"bm": dshell_ban_member, # ban member
|
|
32
|
+
"um": dshell_unban_member, # unban member
|
|
33
|
+
"km": dshell_kick_member, # kick member
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
dshell_mathematical_operators: dict[str, tuple[Callable, int]] = {
|
|
@@ -43,11 +45,11 @@ dshell_mathematical_operators: dict[str, tuple[Callable, int]] = {
|
|
|
43
45
|
r"=>": (lambda a, b: a >= b, 4),
|
|
44
46
|
|
|
45
47
|
r".": (lambda a, b: a.b, 9),
|
|
46
|
-
r"->": (lambda a: a.at, 10), #
|
|
48
|
+
r"->": (lambda a: a.at, 10), # equivalent to calling .at(key)
|
|
47
49
|
|
|
48
50
|
r"+": (lambda a, b: a + b, 6),
|
|
49
51
|
r"-": (lambda a, b=None: -a if b is None else a - b, 6),
|
|
50
|
-
#
|
|
52
|
+
# warning: ambiguity between unary and binary to be handled in your parser
|
|
51
53
|
r"**": (lambda a, b: a ** b, 8),
|
|
52
54
|
r"*": (lambda a, b: a * b, 7),
|
|
53
55
|
r"%": (lambda a, b: a % b, 7),
|
|
@@ -71,7 +73,7 @@ dshell_operators.update(dshell_mathematical_operators)
|
|
|
71
73
|
|
|
72
74
|
'''
|
|
73
75
|
C_create_var = "var"
|
|
74
|
-
C_obligate_var = "ovar" #
|
|
76
|
+
C_obligate_var = "ovar" # makes variables mandatory
|
|
75
77
|
|
|
76
78
|
# guild
|
|
77
79
|
C_create_channel = "cc"
|
|
@@ -120,5 +122,5 @@ C_create_var = "var"
|
|
|
120
122
|
C_clear_emoji = "ce"
|
|
121
123
|
C_remove_reaction = "rre"
|
|
122
124
|
|
|
123
|
-
#
|
|
125
|
+
# button
|
|
124
126
|
C_create_button = "b"'''
|
|
@@ -32,7 +32,7 @@ class DshellTokenType(Enum):
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class Token:
|
|
35
|
-
def __init__(self, type_: "DTT", value: Union[str, list], position: int):
|
|
35
|
+
def __init__(self, type_: "DTT", value: Union[str, list], position: tuple[int, int]):
|
|
36
36
|
self.type = type_
|
|
37
37
|
self.value = value
|
|
38
38
|
self.position = position
|
|
@@ -59,6 +59,7 @@ class DshellTokenizer:
|
|
|
59
59
|
"""
|
|
60
60
|
tokens: list[list[Token]] = []
|
|
61
61
|
|
|
62
|
+
line_number = 1
|
|
62
63
|
for ligne in commandes_lines: # iter chaque ligne du code
|
|
63
64
|
tokens_par_ligne: list[Token] = []
|
|
64
65
|
|
|
@@ -66,7 +67,7 @@ class DshellTokenizer:
|
|
|
66
67
|
|
|
67
68
|
for match in finditer(pattern, ligne): # iter les résultat du match pour avoir leur position
|
|
68
69
|
if token_type != DTT.COMMENT: # si ce n'est pas un commentaire
|
|
69
|
-
token = Token(token_type, match.group(1), match.start()) # on enregistre son token
|
|
70
|
+
token = Token(token_type, match.group(1), (line_number, match.start())) # on enregistre son token
|
|
70
71
|
tokens_par_ligne.append(token)
|
|
71
72
|
|
|
72
73
|
len_match = len(match.group(0))
|
|
@@ -81,7 +82,7 @@ class DshellTokenizer:
|
|
|
81
82
|
result) > 0 else result # gère si la structure de donnée est vide ou non
|
|
82
83
|
|
|
83
84
|
tokens_par_ligne.sort(key=lambda
|
|
84
|
-
token: token.position) # trie la position par rapport aux positions de match des tokens pour les avoir dans l'ordre du code
|
|
85
|
+
token: token.position[1]) # trie la position par rapport aux positions de match des tokens pour les avoir dans l'ordre du code
|
|
85
86
|
if tokens_par_ligne:
|
|
86
87
|
tokens.append(tokens_par_ligne)
|
|
87
88
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Dshell/__init__.py,sha256=UPvXnewe_8FX9aoevMA78UN1k8AY-u8LTY3vEVxaDxw,72
|
|
2
|
+
Dshell/DISCORD_COMMANDS/__init__.py,sha256=unbZE4sxFCbUQ4Qptr1BhWu-nwhvI2oRzcDLtRmX6Ug,92
|
|
3
|
+
Dshell/DISCORD_COMMANDS/dshell_channel.py,sha256=Es1boRZmL5kTip-Lfs0JFtj6hShzEGDp-W49e8cGw3A,3722
|
|
4
|
+
Dshell/DISCORD_COMMANDS/dshell_member.py,sha256=enDFS7gFqNSK4nZWN1VwSGmoXxiREuhhaf82cwReuUc,1425
|
|
5
|
+
Dshell/DISCORD_COMMANDS/dshell_message.py,sha256=LBaEpwkOPDGt3xWAQI287pqEEdlZgKzpB2YmnarwrFg,1840
|
|
6
|
+
Dshell/_DshellInterpreteur/__init__.py,sha256=xy5-J-R3YmY99JF3NBHTRRLsComFxpjnCA5xacISctU,35
|
|
7
|
+
Dshell/_DshellInterpreteur/dshell_interpreter.py,sha256=U6appx8CA0wo1nX44szejQb2Q4E24s88FVoTe9mSmyw,17277
|
|
8
|
+
Dshell/_DshellParser/__init__.py,sha256=ONDfhZMvClqP_6tE8SLjp-cf3pXL-auQYnfYRrHZxC4,56
|
|
9
|
+
Dshell/_DshellParser/ast_nodes.py,sha256=ZPZAA6yqR62mLAMGVO94wTUVmpYM91qAwSKFiWNAt74,9125
|
|
10
|
+
Dshell/_DshellParser/dshell_parser.py,sha256=SqZRG7i8_vdIFhaQwLi-Q8LWIwyw5FaPFEGMX5vsWwU,14074
|
|
11
|
+
Dshell/_DshellTokenizer/__init__.py,sha256=LIQSRhDx2B9pmPx5ADMwwD0Xr9ybneVLhHH8qrJWw_s,172
|
|
12
|
+
Dshell/_DshellTokenizer/dshell_keywords.py,sha256=pCL-y3Sppq-LecXVmrg8bTN-IVLjGh4Rkkm6ZQpR62Q,3720
|
|
13
|
+
Dshell/_DshellTokenizer/dshell_token_type.py,sha256=p0cR4sxhmq03AqBjd0h_sg2eDzgBmd3dhrrchYkL1Pk,1011
|
|
14
|
+
Dshell/_DshellTokenizer/dshell_tokenizer.py,sha256=DSGiSHj9jLqP7RkC-8WFRqFvitJ7P4b7p0CJn4ek7hE,5831
|
|
15
|
+
dshellinterpreter-0.1.11.dist-info/licenses/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
|
|
16
|
+
dshellinterpreter-0.1.11.dist-info/METADATA,sha256=kMhgLtXUntL8mpMWQ-TksVsbEgcIp3TyTCRFQ_MNToA,1096
|
|
17
|
+
dshellinterpreter-0.1.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
+
dshellinterpreter-0.1.11.dist-info/top_level.txt,sha256=B4CMhtmchGwPQJLuqUy0GhRG-0cUGxKL4GqEbCiB_vE,7
|
|
19
|
+
dshellinterpreter-0.1.11.dist-info/RECORD,,
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
Dshell/__init__.py,sha256=UPvXnewe_8FX9aoevMA78UN1k8AY-u8LTY3vEVxaDxw,72
|
|
2
|
-
Dshell/DISCORD_COMMANDS/__init__.py,sha256=s58iMazDXNPDLZ3Hvymh__C5w7lcgEvaYfX0-SHocRo,62
|
|
3
|
-
Dshell/DISCORD_COMMANDS/dshell_channel.py,sha256=RmzqXiuwWTbIUV37KtutFsw2uuXNY7HJFtbJCut5rgg,2388
|
|
4
|
-
Dshell/DISCORD_COMMANDS/dshell_message.py,sha256=cOZzPbm4wkgObuIL42CH1R3qDhPP8ONiP4BA-XTfAMc,1880
|
|
5
|
-
Dshell/_DshellInterpreteur/__init__.py,sha256=xy5-J-R3YmY99JF3NBHTRRLsComFxpjnCA5xacISctU,35
|
|
6
|
-
Dshell/_DshellInterpreteur/dshell_interpreter.py,sha256=j3ppzNv0HIMyWbj0vkIT7RsJSozUnobvnwk2UFT3hys,16088
|
|
7
|
-
Dshell/_DshellParser/__init__.py,sha256=ONDfhZMvClqP_6tE8SLjp-cf3pXL-auQYnfYRrHZxC4,56
|
|
8
|
-
Dshell/_DshellParser/ast_nodes.py,sha256=dRAYD7ZgNB6q5RGwqgWrM68PtUzSFGMBb6xEwvzaDxo,5687
|
|
9
|
-
Dshell/_DshellParser/dshell_parser.py,sha256=mA8uA-xBhKcfnSKfLfePwI_fD0GrHbj0VBVeJPbcGas,13956
|
|
10
|
-
Dshell/_DshellTokenizer/__init__.py,sha256=LIQSRhDx2B9pmPx5ADMwwD0Xr9ybneVLhHH8qrJWw_s,172
|
|
11
|
-
Dshell/_DshellTokenizer/dshell_keywords.py,sha256=wTV89px9bUY4uf0KCnDr356H_dBIVgcPr55L_6-AWdg,3661
|
|
12
|
-
Dshell/_DshellTokenizer/dshell_token_type.py,sha256=NE-sVloBYtioZpWKnWuO5p0YcObGJZPNaKwc8lWDonQ,999
|
|
13
|
-
Dshell/_DshellTokenizer/dshell_tokenizer.py,sha256=2tto_gXYj94fLFx99p6nBbtplALT3Ysz9oBwatX9tIA,5788
|
|
14
|
-
dshellinterpreter-0.1.9.dist-info/licenses/LICENSE,sha256=lNgcw1_xb7QENAQi3uHGymaFtbs0RV-ihiCd7AoLQjA,1082
|
|
15
|
-
dshellinterpreter-0.1.9.dist-info/METADATA,sha256=lLhxzDPjhB4U7iMth8pB_iWsb6vGo5WN-O5W2I6V_f4,1095
|
|
16
|
-
dshellinterpreter-0.1.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
17
|
-
dshellinterpreter-0.1.9.dist-info/top_level.txt,sha256=B4CMhtmchGwPQJLuqUy0GhRG-0cUGxKL4GqEbCiB_vE,7
|
|
18
|
-
dshellinterpreter-0.1.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|