dshellInterpreter 0.2.13.14__tar.gz → 0.2.13.16__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.
Potentially problematic release.
This version of dshellInterpreter might be problematic. Click here for more details.
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/dshell_interaction.py +19 -7
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/dshell_message.py +28 -6
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/dshell_pastbin.py +5 -7
- dshellinterpreter-0.2.13.16/Dshell/DISCORD_COMMANDS/utils/utils_message.py +68 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellInterpreteur/dshell_interpreter.py +25 -1
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellParser/ast_nodes.py +24 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellParser/dshell_parser.py +40 -2
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellTokenizer/dshell_keywords.py +2 -2
- {dshellinterpreter-0.2.13.14/dshellInterpreter.egg-info → dshellinterpreter-0.2.13.16}/PKG-INFO +1 -1
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16/dshellInterpreter.egg-info}/PKG-INFO +1 -1
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/setup.py +1 -1
- dshellinterpreter-0.2.13.14/Dshell/DISCORD_COMMANDS/utils/utils_message.py +0 -28
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/__init__.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/dshell_channel.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/dshell_member.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/dshell_role.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/utils/__init__.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/utils/utils_thread.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellInterpreteur/__init__.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellParser/__init__.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellTokenizer/__init__.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellTokenizer/dshell_token_type.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellTokenizer/dshell_tokenizer.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/__init__.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_utils.py +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/LICENSE +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/README.md +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/dshellInterpreter.egg-info/SOURCES.txt +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/dshellInterpreter.egg-info/dependency_links.txt +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/dshellInterpreter.egg-info/requires.txt +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/dshellInterpreter.egg-info/top_level.txt +0 -0
- {dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/setup.cfg +0 -0
|
@@ -4,11 +4,22 @@ __all__ = [
|
|
|
4
4
|
]
|
|
5
5
|
|
|
6
6
|
from types import NoneType
|
|
7
|
-
from discord import Interaction, Embed
|
|
7
|
+
from discord import Interaction, Embed, AllowedMentions
|
|
8
8
|
from pycordViews import EasyModifiedViews
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
from .utils.utils_message import utils_autorised_mentions
|
|
11
|
+
|
|
12
|
+
async def dshell_respond_interaction(ctx: Interaction,
|
|
13
|
+
content: str = None,
|
|
14
|
+
delete=None,
|
|
15
|
+
global_mentions: bool = None,
|
|
16
|
+
everyone_mention: bool = True,
|
|
17
|
+
roles_mentions: bool = True,
|
|
18
|
+
users_mentions: bool = True,
|
|
19
|
+
reply_mention: bool = False,
|
|
20
|
+
hide: bool = False,
|
|
21
|
+
embeds=None,
|
|
22
|
+
view=None) -> int:
|
|
12
23
|
"""
|
|
13
24
|
Responds to a message interaction on Discord
|
|
14
25
|
"""
|
|
@@ -19,13 +30,14 @@ async def dshell_respond_interaction(ctx: Interaction, content: str = None, dele
|
|
|
19
30
|
if delete is not None and not isinstance(delete, (int, float)):
|
|
20
31
|
raise Exception(f'Delete parameter must be a number (seconds) or None, not {type(delete)} !')
|
|
21
32
|
|
|
22
|
-
if not isinstance(mentions, (NoneType, bool)):
|
|
23
|
-
raise Exception(f'Mention parameter must be a boolean or None, not {type(mentions)} !')
|
|
24
|
-
|
|
25
33
|
if not isinstance(hide, bool):
|
|
26
34
|
raise Exception(f'Hide parameter must be a boolean, not {type(hide)} !')
|
|
27
35
|
|
|
28
|
-
allowed_mentions =
|
|
36
|
+
allowed_mentions = utils_autorised_mentions(global_mentions,
|
|
37
|
+
everyone_mention,
|
|
38
|
+
roles_mentions,
|
|
39
|
+
users_mentions,
|
|
40
|
+
reply_mention)
|
|
29
41
|
|
|
30
42
|
from .._DshellParser.ast_nodes import ListNode
|
|
31
43
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
from re import search
|
|
2
|
-
from tkinter import Listbox
|
|
3
2
|
|
|
4
|
-
from discord import Embed, Message
|
|
3
|
+
from discord import Embed, Message
|
|
5
4
|
from discord.ext import commands
|
|
6
5
|
|
|
7
6
|
from pycordViews import EasyModifiedViews
|
|
8
7
|
|
|
9
|
-
from .utils.utils_message import utils_get_message
|
|
8
|
+
from .utils.utils_message import utils_get_message, utils_autorised_mentions
|
|
10
9
|
from .._utils import NoneType
|
|
11
10
|
|
|
12
11
|
__all__ = [
|
|
@@ -24,7 +23,17 @@ __all__ = [
|
|
|
24
23
|
]
|
|
25
24
|
|
|
26
25
|
|
|
27
|
-
async def dshell_send_message(ctx: Message,
|
|
26
|
+
async def dshell_send_message(ctx: Message,
|
|
27
|
+
message=None,
|
|
28
|
+
delete=None,
|
|
29
|
+
channel=None,
|
|
30
|
+
global_mentions: bool = None,
|
|
31
|
+
everyone_mention: bool = True,
|
|
32
|
+
roles_mentions: bool = True,
|
|
33
|
+
users_mentions: bool = True,
|
|
34
|
+
reply_mention: bool = False,
|
|
35
|
+
embeds=None,
|
|
36
|
+
view=None) -> int:
|
|
28
37
|
"""
|
|
29
38
|
Sends a message on Discord
|
|
30
39
|
"""
|
|
@@ -33,6 +42,7 @@ async def dshell_send_message(ctx: Message, message=None, delete=None, channel=N
|
|
|
33
42
|
raise Exception(f'Delete parameter must be a number (seconds) or None, not {type(delete)} !')
|
|
34
43
|
|
|
35
44
|
channel_to_send = ctx.channel if channel is None else ctx.channel.guild.get_channel(channel)
|
|
45
|
+
allowed_mentions = utils_autorised_mentions(global_mentions, everyone_mention, roles_mentions, users_mentions, reply_mention)
|
|
36
46
|
|
|
37
47
|
if channel_to_send is None:
|
|
38
48
|
raise Exception(f'Channel {channel} not found!')
|
|
@@ -54,12 +64,22 @@ async def dshell_send_message(ctx: Message, message=None, delete=None, channel=N
|
|
|
54
64
|
sended_message = await channel_to_send.send(message,
|
|
55
65
|
delete_after=delete,
|
|
56
66
|
embeds=embeds,
|
|
67
|
+
allowed_mentions=allowed_mentions,
|
|
57
68
|
view=view)
|
|
58
69
|
|
|
59
70
|
return sended_message.id
|
|
60
71
|
|
|
61
72
|
|
|
62
|
-
async def dshell_respond_message(ctx: Message,
|
|
73
|
+
async def dshell_respond_message(ctx: Message,
|
|
74
|
+
message=None,
|
|
75
|
+
content: str = None,
|
|
76
|
+
global_mentions: bool = None,
|
|
77
|
+
everyone_mention: bool = True,
|
|
78
|
+
roles_mentions: bool = True,
|
|
79
|
+
users_mentions: bool = True,
|
|
80
|
+
reply_mention: bool = False,
|
|
81
|
+
delete=None,
|
|
82
|
+
embeds=None):
|
|
63
83
|
"""
|
|
64
84
|
Responds to a message on Discord
|
|
65
85
|
"""
|
|
@@ -67,7 +87,8 @@ async def dshell_respond_message(ctx: Message, message=None, content: str = None
|
|
|
67
87
|
raise Exception(f'Delete parameter must be a number (seconds) or None, not {type(delete)} !')
|
|
68
88
|
|
|
69
89
|
respond_message = ctx if message is None else utils_get_message(ctx, message) # builds a reference to the message (even if it doesn't exist)
|
|
70
|
-
|
|
90
|
+
autorised_mentions = utils_autorised_mentions(global_mentions, everyone_mention, roles_mentions, users_mentions, reply_mention)
|
|
91
|
+
mention_author = True if reply_mention else False
|
|
71
92
|
|
|
72
93
|
from .._DshellParser.ast_nodes import ListNode
|
|
73
94
|
|
|
@@ -83,6 +104,7 @@ async def dshell_respond_message(ctx: Message, message=None, content: str = None
|
|
|
83
104
|
sended_message = await respond_message.reply(
|
|
84
105
|
content=str(content),
|
|
85
106
|
mention_author=mention_author,
|
|
107
|
+
allowed_mentions=autorised_mentions,
|
|
86
108
|
delete_after=delete,
|
|
87
109
|
embeds=embeds)
|
|
88
110
|
|
|
@@ -6,14 +6,16 @@ __all__ = [
|
|
|
6
6
|
]
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
async def dshell_get_pastbin(ctx: Message, code: str):
|
|
9
|
+
async def dshell_get_pastbin(ctx: Message, code: str) -> "ListNode":
|
|
10
10
|
"""
|
|
11
11
|
Get a pastbin from a code snippet.
|
|
12
12
|
"""
|
|
13
13
|
if not isinstance(code, str):
|
|
14
14
|
raise Exception(f'Code must be a string, not {type(code)} !')
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
from .._DshellParser.ast_nodes import ListNode
|
|
17
|
+
|
|
18
|
+
content = ListNode([]) # Initialize content to an empty string
|
|
17
19
|
|
|
18
20
|
with get(f"https://pastebin.com/raw/{code}", stream=True, timeout=10) as response:
|
|
19
21
|
|
|
@@ -21,10 +23,6 @@ async def dshell_get_pastbin(ctx: Message, code: str):
|
|
|
21
23
|
raise Exception(f"Failed to retrieve pastbin with code {code} !")
|
|
22
24
|
|
|
23
25
|
for line in response.iter_lines(decode_unicode=True, chunk_size=512):
|
|
24
|
-
|
|
25
|
-
if len_content < 4000 and len_content + len(line) <= 4000:
|
|
26
|
-
content += line + '\n'
|
|
27
|
-
else:
|
|
28
|
-
break
|
|
26
|
+
content.add(line)
|
|
29
27
|
|
|
30
28
|
return content
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from discord import Message, PartialMessage, AllowedMentions
|
|
2
|
+
from typing import Union
|
|
3
|
+
from re import search
|
|
4
|
+
|
|
5
|
+
def utils_get_message(ctx: Message, message: Union[int, str]) -> PartialMessage:
|
|
6
|
+
"""
|
|
7
|
+
Returns the message object of the specified message ID or link.
|
|
8
|
+
Message is only available in the same server as the command and in the same channel.
|
|
9
|
+
If the message is a link, it must be in the format: https://discord.com/channels/{guild_id}/{channel_id}/{message_id}
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
if isinstance(message, int):
|
|
13
|
+
return ctx.channel.get_partial_message(message)
|
|
14
|
+
|
|
15
|
+
elif isinstance(message, str):
|
|
16
|
+
match = search(r'https://discord\.com/channels/(\d+)/(\d+)/(\d+)', message)
|
|
17
|
+
if not match:
|
|
18
|
+
raise Exception("Invalid message link format. Use a valid Discord message link.")
|
|
19
|
+
guild_id = int(match.group(1))
|
|
20
|
+
channel_id = int(match.group(2))
|
|
21
|
+
message_id = int(match.group(3))
|
|
22
|
+
|
|
23
|
+
if guild_id != ctx.guild.id:
|
|
24
|
+
raise Exception("The message must be from the same server as the command !")
|
|
25
|
+
|
|
26
|
+
return ctx.guild.get_channel(channel_id).get_partial_message(message_id)
|
|
27
|
+
|
|
28
|
+
raise Exception(f"Message must be an integer or a string, not {type(message)} !")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def utils_autorised_mentions(global_mentions: bool = None,
|
|
32
|
+
everyone_mention: bool = True,
|
|
33
|
+
roles_mentions: bool = True,
|
|
34
|
+
users_mentions: bool = True,
|
|
35
|
+
reply_mention: bool = False) -> Union[bool, 'AllowedMentions']:
|
|
36
|
+
"""
|
|
37
|
+
Returns the AllowedMentions object based on the provided parameters.
|
|
38
|
+
If global_mentions is set to True or False, it overrides all other parameters.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
from discord import AllowedMentions
|
|
42
|
+
|
|
43
|
+
if not isinstance(global_mentions, (type(None), bool)):
|
|
44
|
+
raise Exception(f'Mention parameter must be a boolean or None, not {type(global_mentions)} !')
|
|
45
|
+
|
|
46
|
+
if not isinstance(everyone_mention, bool):
|
|
47
|
+
raise Exception(f'Everyone mention parameter must be a boolean, not {type(everyone_mention)} !')
|
|
48
|
+
|
|
49
|
+
if not isinstance(roles_mentions, bool):
|
|
50
|
+
raise Exception(f'Roles mention parameter must be a boolean, not {type(roles_mentions)} !')
|
|
51
|
+
|
|
52
|
+
if not isinstance(users_mentions, bool):
|
|
53
|
+
raise Exception(f'Users mention parameter must be a boolean, not {type(users_mentions)} !')
|
|
54
|
+
|
|
55
|
+
if not isinstance(reply_mention, bool):
|
|
56
|
+
raise Exception(f'Reply mention parameter must be a boolean, not {type(reply_mention)} !')
|
|
57
|
+
|
|
58
|
+
if global_mentions is True:
|
|
59
|
+
return AllowedMentions.all()
|
|
60
|
+
|
|
61
|
+
elif global_mentions is False:
|
|
62
|
+
return AllowedMentions.none()
|
|
63
|
+
|
|
64
|
+
else:
|
|
65
|
+
return AllowedMentions(everyone=everyone_mention,
|
|
66
|
+
roles=roles_mentions,
|
|
67
|
+
users=users_mentions,
|
|
68
|
+
replied_user=reply_mention)
|
|
@@ -4,7 +4,7 @@ from typing import TypeVar, Union, Any, Optional, Callable
|
|
|
4
4
|
from random import choice
|
|
5
5
|
from string import ascii_letters, digits
|
|
6
6
|
from copy import deepcopy
|
|
7
|
-
from pycordViews import
|
|
7
|
+
from pycordViews import EasyModifiedViews
|
|
8
8
|
|
|
9
9
|
from discord import AutoShardedBot, Embed, Colour, PermissionOverwrite, Permissions, Guild, Member, Role, Message, Interaction, ButtonStyle
|
|
10
10
|
from discord.ui import Button
|
|
@@ -63,10 +63,18 @@ class DshellInterpreteur:
|
|
|
63
63
|
'__guild__': message.channel.guild.id,
|
|
64
64
|
'__guild_name__': message.channel.guild.name,
|
|
65
65
|
'__guild_id__': message.channel.guild.id,
|
|
66
|
+
'__guild_members__': ListNode([member.id for member in message.channel.guild.members]),
|
|
66
67
|
'__guild_member_count__': message.channel.guild.member_count,
|
|
67
68
|
'__guild_icon__': message.channel.guild.icon.url if message.channel.guild.icon else None,
|
|
68
69
|
'__guild_owner_id__': message.channel.guild.owner_id,
|
|
69
70
|
'__guild_description__': message.channel.guild.description,
|
|
71
|
+
'__guild_roles__': ListNode([role.id for role in message.channel.guild.roles]),
|
|
72
|
+
'__guild_roles_count__': len(message.channel.guild.roles),
|
|
73
|
+
'__guild_emojis__': ListNode([emoji.id for emoji in message.channel.guild.emojis]),
|
|
74
|
+
'__guild_emojis_count__': len(message.channel.guild.emojis),
|
|
75
|
+
'__guild_channels__': ListNode([channel.id for channel in message.channel.guild.channels]),
|
|
76
|
+
'__guild_channels_count__': len(message.channel.guild.channels),
|
|
77
|
+
|
|
70
78
|
} if message is not None or not debug else {} # {} is used in debug mode, when ctx is None
|
|
71
79
|
self.vars = vars if vars is not None else ''
|
|
72
80
|
self.ctx: context = ctx
|
|
@@ -140,6 +148,9 @@ class DshellInterpreteur:
|
|
|
140
148
|
elif isinstance(first_node, UiNode):
|
|
141
149
|
self.env[node.name.value] = build_ui(first_node, self)
|
|
142
150
|
|
|
151
|
+
elif isinstance(first_node, LengthNode):
|
|
152
|
+
self.env[node.name.value] = length(first_node.body)
|
|
153
|
+
|
|
143
154
|
else:
|
|
144
155
|
self.env[node.name.value] = eval_expression(node.body, self)
|
|
145
156
|
|
|
@@ -382,6 +393,19 @@ def regroupe_commandes(body: list[Token], interpreter: DshellInterpreteur, norma
|
|
|
382
393
|
|
|
383
394
|
return list_tokens
|
|
384
395
|
|
|
396
|
+
def length(variable : LengthNode) -> int:
|
|
397
|
+
"""
|
|
398
|
+
Count characters or items in string/list
|
|
399
|
+
:param variable:
|
|
400
|
+
:return:
|
|
401
|
+
"""
|
|
402
|
+
if not isinstance(variable.body, ListNode) and variable.body.type not in (DTT.STR, DTT.IDENT):
|
|
403
|
+
raise Exception(f'Length take string, ident or list, not {type(variable.body)} !')
|
|
404
|
+
|
|
405
|
+
if isinstance(variable.body, ListNode):
|
|
406
|
+
return len(variable.body)
|
|
407
|
+
else:
|
|
408
|
+
return len(variable.body.value)
|
|
385
409
|
|
|
386
410
|
def build_embed(body: list[Token], fields: list[FieldEmbedNode], interpreter: DshellInterpreteur) -> Embed:
|
|
387
411
|
"""
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellParser/ast_nodes.py
RENAMED
|
@@ -5,6 +5,7 @@ from .._DshellTokenizer.dshell_token_type import Token
|
|
|
5
5
|
|
|
6
6
|
__all__ = [
|
|
7
7
|
'ASTNode',
|
|
8
|
+
'LengthNode',
|
|
8
9
|
'StartNode',
|
|
9
10
|
'ElseNode',
|
|
10
11
|
'ElifNode',
|
|
@@ -257,6 +258,29 @@ class VarNode(ASTNode):
|
|
|
257
258
|
"body": [token.to_dict() for token in self.body]
|
|
258
259
|
}
|
|
259
260
|
|
|
261
|
+
class LengthNode(ASTNode):
|
|
262
|
+
"""
|
|
263
|
+
Node representing the length operation in the AST.
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
def __init__(self, body: Token):
|
|
267
|
+
"""
|
|
268
|
+
:param body: list of tokens representing the body of the length operation
|
|
269
|
+
"""
|
|
270
|
+
self.body = body
|
|
271
|
+
|
|
272
|
+
def __repr__(self):
|
|
273
|
+
return f"<LENGTH> - {self.body}"
|
|
274
|
+
|
|
275
|
+
def to_dict(self):
|
|
276
|
+
"""
|
|
277
|
+
Convert the LengthNode to a dictionary representation.
|
|
278
|
+
:return: Dictionary representation of the LengthNode.
|
|
279
|
+
"""
|
|
280
|
+
return {
|
|
281
|
+
"type": "LengthNode",
|
|
282
|
+
"body": self.body.to_dict()
|
|
283
|
+
}
|
|
260
284
|
|
|
261
285
|
class EndNode(ASTNode):
|
|
262
286
|
"""
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellParser/dshell_parser.py
RENAMED
|
@@ -10,6 +10,7 @@ __all__ = [
|
|
|
10
10
|
from typing import Union
|
|
11
11
|
|
|
12
12
|
from .ast_nodes import (ASTNode,
|
|
13
|
+
LengthNode,
|
|
13
14
|
CommandNode,
|
|
14
15
|
IfNode,
|
|
15
16
|
LoopNode,
|
|
@@ -40,7 +41,7 @@ def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[AST
|
|
|
40
41
|
:param start_node: the node where to start the parsing
|
|
41
42
|
"""
|
|
42
43
|
pointeur = 0 # pointeur sur les listes de tokens pour savoir ou parser
|
|
43
|
-
blocks
|
|
44
|
+
blocks = [start_node] # liste d'imbrication des blocks pour gérer l'imbrication
|
|
44
45
|
len_token_lines = len(token_lines)
|
|
45
46
|
|
|
46
47
|
while pointeur < len_token_lines:
|
|
@@ -59,6 +60,8 @@ def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[AST
|
|
|
59
60
|
elif first_token_line.type == DTT.KEYWORD: # si c'est un mot clé
|
|
60
61
|
|
|
61
62
|
if first_token_line.value == 'if': # si c'est une condition
|
|
63
|
+
if len(tokens_by_line) <= 1:
|
|
64
|
+
raise SyntaxError(f'[IF] Take one or more arguments on line {first_token_line.position} !')
|
|
62
65
|
if_node = IfNode(condition=tokens_by_line[1:],
|
|
63
66
|
body=[]) # on crée la node avec les arguments de condition du if
|
|
64
67
|
last_block.body.append(if_node)
|
|
@@ -81,6 +84,8 @@ def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[AST
|
|
|
81
84
|
elif first_token_line.value == 'elif':
|
|
82
85
|
if not isinstance(last_block, (IfNode, ElifNode)):
|
|
83
86
|
raise SyntaxError(f'[ELIF] No conditional bloc open on line {first_token_line.position} !')
|
|
87
|
+
if len(tokens_by_line) <= 1:
|
|
88
|
+
raise SyntaxError(f'[ELIF] Take one or more arguments on line {first_token_line.position} !')
|
|
84
89
|
elif_node = ElifNode(condition=tokens_by_line[1:], body=[],
|
|
85
90
|
parent=last_block if isinstance(last_block, IfNode) else last_block.parent)
|
|
86
91
|
|
|
@@ -110,6 +115,15 @@ def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[AST
|
|
|
110
115
|
blocks.append(else_node)
|
|
111
116
|
|
|
112
117
|
elif first_token_line.value == 'loop':
|
|
118
|
+
if len(tokens_by_line) <= 2:
|
|
119
|
+
raise SyntaxError(f'[LOOP] Take two arguments on line {first_token_line.position} !')
|
|
120
|
+
if tokens_by_line[1].type != DTT.IDENT:
|
|
121
|
+
raise TypeError(f'[LOOP] the variable given must be a ident, '
|
|
122
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
123
|
+
if tokens_by_line[2].type not in (DTT.IDENT, DTT.STR, DTT.INT, DTT.FLOAT, DTT.LIST):
|
|
124
|
+
raise TypeError(f'[LOOP] the iterator must be a ident, string, integer, float or list, '
|
|
125
|
+
f'not {tokens_by_line[2].type} in line {tokens_by_line[2].position}')
|
|
126
|
+
|
|
113
127
|
loop_node = LoopNode(VarNode(tokens_by_line[1], to_postfix(tokens_by_line[2:])), body=[])
|
|
114
128
|
last_block.body.append(loop_node)
|
|
115
129
|
_, p = parse(token_lines[pointeur + 1:],
|
|
@@ -123,7 +137,12 @@ def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[AST
|
|
|
123
137
|
return blocks, pointeur # on renvoie les informations parsé à la dernière loop ouverte
|
|
124
138
|
|
|
125
139
|
elif first_token_line.value == 'var':
|
|
126
|
-
|
|
140
|
+
if len(tokens_by_line) <= 2:
|
|
141
|
+
raise SyntaxError(f'[VAR] Take two arguments on line {first_token_line.position} !')
|
|
142
|
+
if tokens_by_line[1].type != DTT.IDENT:
|
|
143
|
+
raise TypeError(f'[VAR] the variable given must be a ident, '
|
|
144
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
145
|
+
var_node = VarNode(name=tokens_by_line[1], body=[])
|
|
127
146
|
last_block.body.append(var_node)
|
|
128
147
|
result, status = parser_inline(tokens_by_line[
|
|
129
148
|
2:]) # on fait en sorte de mettre les tokens de la ligne séparé par des retour à la ligne à chaque condition/else
|
|
@@ -134,10 +153,21 @@ def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[AST
|
|
|
134
153
|
var_node.body = result[0]
|
|
135
154
|
|
|
136
155
|
elif first_token_line.value == 'sleep':
|
|
156
|
+
if len(tokens_by_line) <= 1:
|
|
157
|
+
raise SyntaxError(f'[SLEEP] Take one arguments on line {first_token_line.position} !')
|
|
158
|
+
if tokens_by_line[1].type != DTT.INT:
|
|
159
|
+
raise TypeError(f'[SLEEP] the variable given must be an integer, '
|
|
160
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
161
|
+
|
|
137
162
|
sleep_node = SleepNode(tokens_by_line[1:])
|
|
138
163
|
last_block.body.append(sleep_node)
|
|
139
164
|
|
|
140
165
|
elif first_token_line.value == 'param':
|
|
166
|
+
if len(tokens_by_line) <= 1:
|
|
167
|
+
raise SyntaxError(f'[PARAM] Take one arguments on line {first_token_line.position} !')
|
|
168
|
+
if tokens_by_line[1].type != DTT.IDENT:
|
|
169
|
+
raise TypeError(f'[PARAM] the variable given must be a ident, '
|
|
170
|
+
f'not {tokens_by_line[1].type} in line {tokens_by_line[1].position}')
|
|
141
171
|
param_node = ParamNode(body=[])
|
|
142
172
|
last_block.body.append(param_node)
|
|
143
173
|
_, p = parse(token_lines[pointeur + 1:], param_node)
|
|
@@ -153,6 +183,14 @@ def parse(token_lines: list[list[Token]], start_node: ASTNode) -> tuple[list[AST
|
|
|
153
183
|
end_node = EndNode()
|
|
154
184
|
last_block.body.append(end_node)
|
|
155
185
|
|
|
186
|
+
elif first_token_line.value in ('length', 'len'):
|
|
187
|
+
if len(tokens_by_line) != 2:
|
|
188
|
+
raise SyntaxError(f"[LENGTH] Take 2 arguments on line {first_token_line.position} !")
|
|
189
|
+
if first_token_line.type not in (DTT.IDENT, DTT.STR, DTT.LIST):
|
|
190
|
+
raise SyntaxError(f"[LENGTH] Take an ident, str or list on line {first_token_line.position}, not {first_token_line.type} !")
|
|
191
|
+
var_node = VarNode(tokens_by_line[1], body=[LengthNode(tokens_by_line[2])])
|
|
192
|
+
last_block.body.append(var_node)
|
|
193
|
+
|
|
156
194
|
############################## DISCORD KEYWORDS ##############################
|
|
157
195
|
|
|
158
196
|
elif first_token_line.type == DTT.DISCORD_KEYWORD:
|
|
@@ -18,7 +18,7 @@ from ..DISCORD_COMMANDS.dshell_role import *
|
|
|
18
18
|
from ..DISCORD_COMMANDS.dshell_interaction import *
|
|
19
19
|
|
|
20
20
|
dshell_keyword: set[str] = {
|
|
21
|
-
'if', 'else', 'elif', 'loop', '#end', 'var', '#loop', '#if', 'sleep', 'param', '#param'
|
|
21
|
+
'if', 'else', 'elif', 'loop', '#end', 'var', '#loop', '#if', 'sleep', 'param', '#param', 'length', 'len'
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
dshell_discord_keyword: set[str] = {
|
|
@@ -36,7 +36,7 @@ dshell_commands: dict[str, Callable] = {
|
|
|
36
36
|
"em": dshell_edit_message, # edit message
|
|
37
37
|
|
|
38
38
|
"sri": dshell_respond_interaction, # respond to an interaction
|
|
39
|
-
"
|
|
39
|
+
"sdi": dshell_defer_interaction, # defer an interaction
|
|
40
40
|
|
|
41
41
|
"cc": dshell_create_text_channel, # create channel
|
|
42
42
|
"cvc": dshell_create_voice_channel, # create voice channel
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="dshellInterpreter",
|
|
8
|
-
version="0.2.13.
|
|
8
|
+
version="0.2.13.16",
|
|
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,28 +0,0 @@
|
|
|
1
|
-
from discord import Message, PartialMessage
|
|
2
|
-
from typing import Union
|
|
3
|
-
from re import search
|
|
4
|
-
|
|
5
|
-
def utils_get_message(ctx: Message, message: Union[int, str]) -> PartialMessage:
|
|
6
|
-
"""
|
|
7
|
-
Returns the message object of the specified message ID or link.
|
|
8
|
-
Message is only available in the same server as the command and in the same channel.
|
|
9
|
-
If the message is a link, it must be in the format: https://discord.com/channels/{guild_id}/{channel_id}/{message_id}
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
if isinstance(message, int):
|
|
13
|
-
return ctx.channel.get_partial_message(message)
|
|
14
|
-
|
|
15
|
-
elif isinstance(message, str):
|
|
16
|
-
match = search(r'https://discord\.com/channels/(\d+)/(\d+)/(\d+)', message)
|
|
17
|
-
if not match:
|
|
18
|
-
raise Exception("Invalid message link format. Use a valid Discord message link.")
|
|
19
|
-
guild_id = int(match.group(1))
|
|
20
|
-
channel_id = int(match.group(2))
|
|
21
|
-
message_id = int(match.group(3))
|
|
22
|
-
|
|
23
|
-
if guild_id != ctx.guild.id:
|
|
24
|
-
raise Exception("The message must be from the same server as the command !")
|
|
25
|
-
|
|
26
|
-
return ctx.guild.get_channel(channel_id).get_partial_message(message_id)
|
|
27
|
-
|
|
28
|
-
raise Exception(f"Message must be an integer or a string, not {type(message)} !")
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/dshell_member.py
RENAMED
|
File without changes
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/DISCORD_COMMANDS/dshell_role.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellInterpreteur/__init__.py
RENAMED
|
File without changes
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellParser/__init__.py
RENAMED
|
File without changes
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/Dshell/_DshellTokenizer/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/dshellInterpreter.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/dshellInterpreter.egg-info/requires.txt
RENAMED
|
File without changes
|
{dshellinterpreter-0.2.13.14 → dshellinterpreter-0.2.13.16}/dshellInterpreter.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|