bTagScript 5.0.0__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.
- bTagScript/__init__.py +66 -0
- bTagScript/adapter/__init__.py +16 -0
- bTagScript/adapter/discord_adapters.py +275 -0
- bTagScript/adapter/function_adapter.py +33 -0
- bTagScript/adapter/int_adapter.py +30 -0
- bTagScript/adapter/object_adapter.py +41 -0
- bTagScript/adapter/string_adapter.py +69 -0
- bTagScript/block/__init__.py +67 -0
- bTagScript/block/break_block.py +41 -0
- bTagScript/block/case_block.py +62 -0
- bTagScript/block/comment_block.py +33 -0
- bTagScript/block/control_block.py +161 -0
- bTagScript/block/counting_blocks.py +88 -0
- bTagScript/block/digitshorthand_block.py +38 -0
- bTagScript/block/discord_blocks/__init__.py +20 -0
- bTagScript/block/discord_blocks/command_block.py +52 -0
- bTagScript/block/discord_blocks/cooldown_block.py +101 -0
- bTagScript/block/discord_blocks/delete_block.py +47 -0
- bTagScript/block/discord_blocks/embed_block.py +248 -0
- bTagScript/block/discord_blocks/override_block.py +61 -0
- bTagScript/block/discord_blocks/react_block.py +49 -0
- bTagScript/block/discord_blocks/redirect_block.py +42 -0
- bTagScript/block/discord_blocks/requirement_blocks.py +83 -0
- bTagScript/block/helpers.py +121 -0
- bTagScript/block/math_blocks.py +257 -0
- bTagScript/block/random_block.py +65 -0
- bTagScript/block/range_block.py +54 -0
- bTagScript/block/replace_block.py +110 -0
- bTagScript/block/stop_block.py +38 -0
- bTagScript/block/strf_block.py +70 -0
- bTagScript/block/url_blocks.py +76 -0
- bTagScript/block/util_blocks/__init__.py +3 -0
- bTagScript/block/util_blocks/debug_block.py +107 -0
- bTagScript/block/var_block.py +49 -0
- bTagScript/block/vargetter_blocks.py +91 -0
- bTagScript/exceptions.py +139 -0
- bTagScript/interface/__init__.py +4 -0
- bTagScript/interface/adapter.py +43 -0
- bTagScript/interface/block.py +136 -0
- bTagScript/interpreter.py +614 -0
- bTagScript/utils.py +65 -0
- bTagScript/verb.py +129 -0
- btagscript-5.0.0.dist-info/METADATA +109 -0
- btagscript-5.0.0.dist-info/RECORD +47 -0
- btagscript-5.0.0.dist-info/WHEEL +5 -0
- btagscript-5.0.0.dist-info/licenses/LICENSE +1 -0
- btagscript-5.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from ...interface import Block
|
|
4
|
+
from ...interpreter import Context
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DebugBlock(Block):
|
|
8
|
+
"""
|
|
9
|
+
The debug block allows you to debug your tagscript quickly and easily,
|
|
10
|
+
it will save the output to the debug_var key in the response dict.
|
|
11
|
+
Separate the variables you want to include or exclude with a comma or
|
|
12
|
+
a tilde.
|
|
13
|
+
|
|
14
|
+
If no parameters are provided in addition to no payload, all variables
|
|
15
|
+
will be included. If no parameters are provided and a payload is
|
|
16
|
+
provided, it will assume you want to include those variables.
|
|
17
|
+
|
|
18
|
+
**Usage:** ``{debug(["i", "include", "e", "exclude"]):<variables>}``
|
|
19
|
+
|
|
20
|
+
**Aliases:** ``None``
|
|
21
|
+
|
|
22
|
+
**Payload:** ``variables``
|
|
23
|
+
|
|
24
|
+
**Parameter:** ``"i", "include", "e", "exclude"``
|
|
25
|
+
|
|
26
|
+
.. note::
|
|
27
|
+
|
|
28
|
+
{debug} is the same as {debug(exclude):}
|
|
29
|
+
|
|
30
|
+
{debug:somevar~anothervar} is the same as {debug(include):somevar~anothervar}
|
|
31
|
+
|
|
32
|
+
**Examples:**
|
|
33
|
+
|
|
34
|
+
.. note::
|
|
35
|
+
|
|
36
|
+
THIS SHOULD ALWAYS BE PLACED AT THE VERY BOTTOM, IT WILL NOT RETURN ANYTHING UNDER IT.
|
|
37
|
+
|
|
38
|
+
.. tagscript::
|
|
39
|
+
|
|
40
|
+
Assuming we have the following tagscript, we first set the var something, then set
|
|
41
|
+
parsed (using the dollar sign method), to Hello|World, (assume we actually wanted just the Hello
|
|
42
|
+
but we forgot)
|
|
43
|
+
|
|
44
|
+
{=(something):Hello/World}
|
|
45
|
+
{$parsed:{something(1)}}
|
|
46
|
+
{if({parsed}==Hello):Hello|Bye}
|
|
47
|
+
|
|
48
|
+
Running this would provided the output Bye, using the debug block below:
|
|
49
|
+
{debug}
|
|
50
|
+
We'll get all the variables at their, "final state"
|
|
51
|
+
This will be provided in a dict, which you can further parse and output to your liking.
|
|
52
|
+
|
|
53
|
+
EG, in YAML format:
|
|
54
|
+
something: Hello/World
|
|
55
|
+
parsed: Hello/World
|
|
56
|
+
|
|
57
|
+
This allow's you to see that you forgot to parse with a delimiter which will lead to easy fixing.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
ACCEPTED_NAMES = ("debug",)
|
|
61
|
+
|
|
62
|
+
def process(self, ctx: Context) -> Optional[str]: # pylint: disable=too-many-branches
|
|
63
|
+
"""
|
|
64
|
+
Debug the tagscript!
|
|
65
|
+
"""
|
|
66
|
+
debug = {}
|
|
67
|
+
|
|
68
|
+
if ctx.verb.parameter:
|
|
69
|
+
if ctx.verb.parameter in ("e", "exc", "exclude"):
|
|
70
|
+
if ctx.verb.payload:
|
|
71
|
+
if "~" in ctx.verb.payload:
|
|
72
|
+
exclude = ctx.verb.payload.split("~")
|
|
73
|
+
else:
|
|
74
|
+
exclude = ctx.verb.payload.split(",")
|
|
75
|
+
for k, v in ctx.response.variables.items():
|
|
76
|
+
if k not in exclude:
|
|
77
|
+
debug[k] = v.get_value(ctx.verb)
|
|
78
|
+
else:
|
|
79
|
+
return None
|
|
80
|
+
|
|
81
|
+
elif ctx.verb.parameter in ("i", "inc", "include"):
|
|
82
|
+
if ctx.verb.payload:
|
|
83
|
+
if "~" in ctx.verb.payload:
|
|
84
|
+
include = ctx.verb.payload.split("~")
|
|
85
|
+
else:
|
|
86
|
+
include = ctx.verb.payload.split(",")
|
|
87
|
+
|
|
88
|
+
for k, v in ctx.response.variables.items():
|
|
89
|
+
if k in include:
|
|
90
|
+
debug[k] = v.get_value(ctx.verb)
|
|
91
|
+
else:
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
elif ctx.verb.payload:
|
|
95
|
+
if "~" in ctx.verb.payload:
|
|
96
|
+
include = ctx.verb.payload.split("~")
|
|
97
|
+
else:
|
|
98
|
+
include = ctx.verb.payload.split(",")
|
|
99
|
+
|
|
100
|
+
for k, v in ctx.response.variables.items():
|
|
101
|
+
if k in include:
|
|
102
|
+
debug[k] = v.get_value(ctx.verb)
|
|
103
|
+
else:
|
|
104
|
+
for k, v in ctx.response.variables.items():
|
|
105
|
+
debug[k] = v.get_value(ctx.verb)
|
|
106
|
+
ctx.response.extras["debug"] = debug
|
|
107
|
+
return ""
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from ..adapter import StringAdapter
|
|
4
|
+
from ..interface import Block
|
|
5
|
+
from ..interpreter import Context
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class VarBlock(Block):
|
|
9
|
+
"""
|
|
10
|
+
Variables are useful for choosing a value and referencing it later in a tag.
|
|
11
|
+
Variables can be referenced using brackets as any other block.
|
|
12
|
+
Note that if the variable's name is being "used" by any other block the variable
|
|
13
|
+
will be ignored.
|
|
14
|
+
|
|
15
|
+
**Usage:** ``{=(<name>):<value>}``
|
|
16
|
+
|
|
17
|
+
**Aliases:** ``assign, let, var, =``
|
|
18
|
+
|
|
19
|
+
**Payload:** ``value``
|
|
20
|
+
|
|
21
|
+
**Parameter:** ``name``
|
|
22
|
+
|
|
23
|
+
**Examples:**
|
|
24
|
+
|
|
25
|
+
.. tagscript::
|
|
26
|
+
|
|
27
|
+
{=(prefix):!}
|
|
28
|
+
The prefix here is `{prefix}`.
|
|
29
|
+
The prefix here is `!`.
|
|
30
|
+
|
|
31
|
+
{let(day):Monday}
|
|
32
|
+
{if({day}==Wednesday):It's Wednesday my dudes!|The day is {day}.}
|
|
33
|
+
The day is Monday.
|
|
34
|
+
|
|
35
|
+
Variables can also be created like so if the interpreter uses loose variables
|
|
36
|
+
{$<name>:<value>}
|
|
37
|
+
{$day:Monday} == {=(day):Monday}
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
ACCEPTED_NAMES = ("=", "assign", "let", "var")
|
|
41
|
+
|
|
42
|
+
def process(self, ctx: Context) -> Optional[str]:
|
|
43
|
+
"""
|
|
44
|
+
Process the block and assign the variable.
|
|
45
|
+
"""
|
|
46
|
+
if ctx.verb.parameter in ctx.interpreter._blocknames: # pylint: disable=protected-access
|
|
47
|
+
return None
|
|
48
|
+
ctx.response.variables[ctx.verb.parameter] = StringAdapter(str(ctx.verb.payload))
|
|
49
|
+
return ""
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from ..adapter import StringAdapter
|
|
4
|
+
from ..interface import Block
|
|
5
|
+
from ..interpreter import Context
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LooseVariableGetterBlock(Block):
|
|
9
|
+
"""
|
|
10
|
+
The loose variable block represents the adapters for any seeded or defined variables.
|
|
11
|
+
This variable implementation is considered "loose" since it checks whether the variable is
|
|
12
|
+
valid during :meth:`process`, rather than :meth:`will_accept`.
|
|
13
|
+
You may also define variables here with {$<variable name>:<value>}, note that this is not
|
|
14
|
+
available using the StrictVariableGetterBlock class.
|
|
15
|
+
|
|
16
|
+
**Usage:** ``{<variable_name>([parameter]):[payload]}``
|
|
17
|
+
|
|
18
|
+
**Aliases:** This block is valid for any inputted declaration.
|
|
19
|
+
|
|
20
|
+
**Payload:** Depends on the variable's underlying adapter.
|
|
21
|
+
|
|
22
|
+
**Parameter:** Depends on the variable's underlying adapter.
|
|
23
|
+
|
|
24
|
+
**Examples:**
|
|
25
|
+
|
|
26
|
+
.. tagscript::
|
|
27
|
+
|
|
28
|
+
{=(example):This is my variable.}
|
|
29
|
+
{example}
|
|
30
|
+
This is my variable.
|
|
31
|
+
|
|
32
|
+
{$variablename:This is another variable.}
|
|
33
|
+
{variablename}
|
|
34
|
+
This is another variable.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def will_accept(self, ctx: Context) -> bool: # pylint: disable=arguments-differ
|
|
38
|
+
"""
|
|
39
|
+
This block will accept any declaration.
|
|
40
|
+
"""
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
def process(self, ctx: Context) -> Optional[str]:
|
|
44
|
+
"""
|
|
45
|
+
This block will check whether the variable is valid.
|
|
46
|
+
"""
|
|
47
|
+
if ctx.verb.declaration.startswith("$"):
|
|
48
|
+
varname = ctx.verb.declaration.split("$", 1)[1]
|
|
49
|
+
ctx.response.variables[varname] = StringAdapter(str(ctx.verb.payload))
|
|
50
|
+
return ""
|
|
51
|
+
if ctx.verb.declaration in ctx.response.variables:
|
|
52
|
+
return ctx.response.variables[ctx.verb.declaration].get_value(ctx.verb)
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class StrictVariableGetterBlock(Block):
|
|
57
|
+
"""
|
|
58
|
+
The strict variable block represents the adapters for any seeded or defined variables.
|
|
59
|
+
This variable implementation is considered "strict" since it checks whether the variable is
|
|
60
|
+
valid during :meth:`will_accept` and is only processed if the declaration refers to a valid
|
|
61
|
+
variable. The main difference between this and the LooseVariableGetterBlock is that this
|
|
62
|
+
block will only attempt to process if the variable's already been defined.
|
|
63
|
+
|
|
64
|
+
**Usage:** ``{<variable_name>([parameter]):[payload]}``
|
|
65
|
+
|
|
66
|
+
**Aliases:** This block is valid for any variable name in `Response.variables`.
|
|
67
|
+
|
|
68
|
+
**Payload:** Depends on the variable's underlying adapter.
|
|
69
|
+
|
|
70
|
+
**Parameter:** Depends on the variable's underlying adapter.
|
|
71
|
+
|
|
72
|
+
**Examples:**
|
|
73
|
+
|
|
74
|
+
.. tagscript::
|
|
75
|
+
|
|
76
|
+
{=(example):This is my variable.}
|
|
77
|
+
{example}
|
|
78
|
+
This is my variable.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def will_accept(self, ctx: Context) -> bool: # pylint: disable=arguments-differ
|
|
82
|
+
"""
|
|
83
|
+
Check if the declaration is in the response variables
|
|
84
|
+
"""
|
|
85
|
+
return ctx.verb.declaration in ctx.response.variables
|
|
86
|
+
|
|
87
|
+
def process(self, ctx: Context) -> Optional[str]:
|
|
88
|
+
"""
|
|
89
|
+
Process the strict variable block
|
|
90
|
+
"""
|
|
91
|
+
return ctx.response.variables[ctx.verb.declaration].get_value(ctx.verb)
|
bTagScript/exceptions.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from discord.ext.commands import Cooldown
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from .interpreter import Interpreter, Response
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
__all__ = (
|
|
12
|
+
"TagScriptError",
|
|
13
|
+
"WorkloadExceededError",
|
|
14
|
+
"ProcessError",
|
|
15
|
+
"EmbedParseError",
|
|
16
|
+
"BadColourArgument",
|
|
17
|
+
"StopError",
|
|
18
|
+
"CooldownExceeded",
|
|
19
|
+
"BlocknameDuplicateError",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TagScriptError(Exception):
|
|
24
|
+
"""
|
|
25
|
+
Base class for all module errors.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class WorkloadExceededError(TagScriptError):
|
|
30
|
+
"""
|
|
31
|
+
Raised when the interpreter goes over its passed character limit.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ProcessError(TagScriptError):
|
|
36
|
+
"""
|
|
37
|
+
Raised when an exception occurs during interpreter processing.
|
|
38
|
+
|
|
39
|
+
Attributes
|
|
40
|
+
----------
|
|
41
|
+
original: Exception
|
|
42
|
+
The original exception that occurred during processing.
|
|
43
|
+
response: Response
|
|
44
|
+
The incomplete response that was being processed when the exception occurred.
|
|
45
|
+
interpreter: Interpreter
|
|
46
|
+
The interpreter used for processing.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self, error: Exception, response: Response, interpreter: Interpreter) -> None:
|
|
50
|
+
"""
|
|
51
|
+
Construct the error
|
|
52
|
+
"""
|
|
53
|
+
self.original: Exception = error
|
|
54
|
+
self.response: Response = response
|
|
55
|
+
self.interpreter: Interpreter = interpreter
|
|
56
|
+
super().__init__(error)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class EmbedParseError(TagScriptError):
|
|
60
|
+
"""
|
|
61
|
+
Raised if an exception occurs while attempting to parse an embed.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class BadColourArgument(EmbedParseError):
|
|
66
|
+
"""
|
|
67
|
+
Raised when the passed input fails to convert to `discord.Colour`.
|
|
68
|
+
|
|
69
|
+
Attributes
|
|
70
|
+
----------
|
|
71
|
+
argument: str
|
|
72
|
+
The invalid input.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def __init__(self, argument: str) -> None:
|
|
76
|
+
"""
|
|
77
|
+
Init the error
|
|
78
|
+
"""
|
|
79
|
+
self.argument = argument
|
|
80
|
+
super().__init__(f'Colour "{argument}" is invalid.')
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class StopError(TagScriptError):
|
|
84
|
+
"""
|
|
85
|
+
Raised by the StopBlock to stop processing.
|
|
86
|
+
|
|
87
|
+
Attributes
|
|
88
|
+
----------
|
|
89
|
+
message: str
|
|
90
|
+
The stop error message.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
def __init__(self, message: str):
|
|
94
|
+
self.message = message
|
|
95
|
+
super().__init__(message)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class CooldownExceeded(StopError):
|
|
99
|
+
"""
|
|
100
|
+
Raised by the cooldown block when a cooldown is exceeded.
|
|
101
|
+
|
|
102
|
+
Attributes
|
|
103
|
+
----------
|
|
104
|
+
message: str
|
|
105
|
+
The cooldown error message.
|
|
106
|
+
cooldown: discord.ext.commands.Cooldown
|
|
107
|
+
The cooldown bucket with information on the cooldown.
|
|
108
|
+
key: str
|
|
109
|
+
The cooldown key that reached its cooldown.
|
|
110
|
+
retry_after: float
|
|
111
|
+
The seconds left til the cooldown ends.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def __init__(self, message: str, cooldown: Cooldown, key: str, retry_after: float) -> None:
|
|
115
|
+
"""
|
|
116
|
+
Construct the error
|
|
117
|
+
"""
|
|
118
|
+
self.cooldown = cooldown
|
|
119
|
+
self.key = key
|
|
120
|
+
self.retry_after = retry_after
|
|
121
|
+
super().__init__(message)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class BlocknameDuplicateError(TagScriptError):
|
|
125
|
+
"""
|
|
126
|
+
Raised when a a duplicate block name is passed to the interpreter
|
|
127
|
+
|
|
128
|
+
Attributes
|
|
129
|
+
----------
|
|
130
|
+
blockname: str
|
|
131
|
+
The blockname that was duplicated
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
def __init__(self, blockname: str) -> None:
|
|
135
|
+
"""
|
|
136
|
+
Init
|
|
137
|
+
"""
|
|
138
|
+
self.blockname: str = blockname
|
|
139
|
+
super().__init__()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from ..interpreter import Context
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Adapter:
|
|
10
|
+
"""
|
|
11
|
+
The base class for TagScript adapters.
|
|
12
|
+
|
|
13
|
+
Implementations must subclass this to create adapters.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __repr__(self) -> str:
|
|
17
|
+
"""
|
|
18
|
+
String repr
|
|
19
|
+
"""
|
|
20
|
+
return f"<{type(self).__qualname__} at {hex(id(self))}>"
|
|
21
|
+
|
|
22
|
+
def get_value(self, ctx: Context) -> Optional[str]:
|
|
23
|
+
"""
|
|
24
|
+
Processes the adapter's actions for a given :class:`~bTagScript.interpreter.Context`.
|
|
25
|
+
|
|
26
|
+
Subclasses must implement this.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
ctx: Context
|
|
31
|
+
The context object containing the TagScript :class:`~bTagScript.verb.Verb`.
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
Optional[str]
|
|
36
|
+
The adapters's processed value.
|
|
37
|
+
|
|
38
|
+
Raises
|
|
39
|
+
------
|
|
40
|
+
NotImplementedError
|
|
41
|
+
The subclass did not implement this required method.
|
|
42
|
+
"""
|
|
43
|
+
raise NotImplementedError
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from functools import lru_cache
|
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from ..interpreter import Context
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__ = ("Block", "verb_required_block")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Block:
|
|
14
|
+
"""
|
|
15
|
+
The base class for TagScript blocks.
|
|
16
|
+
|
|
17
|
+
Implementations must subclass this to create new blocks.
|
|
18
|
+
|
|
19
|
+
Attributes
|
|
20
|
+
----------
|
|
21
|
+
ACCEPTED_NAMES: Tuple[str, ...]
|
|
22
|
+
The accepted names for this block. This ideally should be set as a class attribute.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
ACCEPTED_NAMES = ()
|
|
26
|
+
|
|
27
|
+
def __repr__(self) -> str:
|
|
28
|
+
"""
|
|
29
|
+
String repr
|
|
30
|
+
"""
|
|
31
|
+
return f"<{type(self).__qualname__} at {hex(id(self))}>"
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def will_accept(cls, ctx: Context) -> bool:
|
|
35
|
+
"""
|
|
36
|
+
Describes whether the block is valid for the given :class:`~bTagScript.interpreter.Context`.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
ctx: Context
|
|
41
|
+
The context object containing the TagScript :class:`~bTagScript.verb.Verb`.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
bool
|
|
46
|
+
Whether the block should be processed for this :class:`~bTagScript.interpreter.Context`.
|
|
47
|
+
"""
|
|
48
|
+
dec = ctx.verb.declaration.lower()
|
|
49
|
+
return dec in cls.ACCEPTED_NAMES
|
|
50
|
+
|
|
51
|
+
def pre_process(self, ctx: Context) -> Optional[str]: # pylint: disable=unused-argument
|
|
52
|
+
"""
|
|
53
|
+
Any pre processing that needs to be done before the block is processed.
|
|
54
|
+
"""
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
def process(self, ctx: Context) -> Optional[str]:
|
|
58
|
+
"""
|
|
59
|
+
Processes the block's actions for a given :class:`~bTagScript.interpreter.Context`.
|
|
60
|
+
|
|
61
|
+
Subclasses must implement this.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
ctx: Context
|
|
66
|
+
The context object containing the TagScript :class:`~bTagScript.verb.Verb`.
|
|
67
|
+
|
|
68
|
+
Returns
|
|
69
|
+
-------
|
|
70
|
+
Optional[str]
|
|
71
|
+
The block's processed value.
|
|
72
|
+
|
|
73
|
+
Raises
|
|
74
|
+
------
|
|
75
|
+
NotImplementedError
|
|
76
|
+
The subclass did not implement this required method.
|
|
77
|
+
"""
|
|
78
|
+
raise NotImplementedError
|
|
79
|
+
|
|
80
|
+
def post_process(self, ctx: Context) -> Optional[str]: # pylint: disable=unused-argument
|
|
81
|
+
"""
|
|
82
|
+
Any post processing that needs to be done after the block is processed.
|
|
83
|
+
"""
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@lru_cache(maxsize=None)
|
|
88
|
+
def verb_required_block(
|
|
89
|
+
implicit: bool,
|
|
90
|
+
*,
|
|
91
|
+
parameter: bool = False,
|
|
92
|
+
payload: bool = False,
|
|
93
|
+
) -> Block:
|
|
94
|
+
"""
|
|
95
|
+
Get a Block subclass that requires a verb to implicitly or explicitly have a parameter or payload passed.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
implicit: bool
|
|
100
|
+
Specifies whether the value is required to be passed implicitly or explicitly.
|
|
101
|
+
``{block()}`` would be allowed if implicit is False.
|
|
102
|
+
parameter: bool
|
|
103
|
+
Passing True will cause the block to require a parameter to be passed.
|
|
104
|
+
payload: bool
|
|
105
|
+
Passing True will cause the block to require the payload to be passed.
|
|
106
|
+
"""
|
|
107
|
+
check = (lambda x: x) if implicit else (lambda x: x is not None)
|
|
108
|
+
|
|
109
|
+
class RequireMeta(type):
|
|
110
|
+
"""
|
|
111
|
+
Require a verb to have a parameter or payload if added.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
def __repr__(cls) -> str:
|
|
115
|
+
"""
|
|
116
|
+
String repr
|
|
117
|
+
"""
|
|
118
|
+
return f"VerbRequiredBlock(implicit={implicit!r}, payload={payload!r}, parameter={parameter!r})"
|
|
119
|
+
|
|
120
|
+
class VerbRequiredBlock(Block, metaclass=RequireMeta): # pylint: disable=abstract-method
|
|
121
|
+
"""
|
|
122
|
+
The required block.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def will_accept(self, ctx: Context) -> bool: # pylint: disable=arguments-differ
|
|
126
|
+
"""
|
|
127
|
+
Describes whether the block is valid for the given :class:`~bTagScript.interpreter.Context`.
|
|
128
|
+
"""
|
|
129
|
+
verb = ctx.verb
|
|
130
|
+
if payload and not check(verb.payload):
|
|
131
|
+
return False
|
|
132
|
+
if parameter and not check(verb.parameter):
|
|
133
|
+
return False
|
|
134
|
+
return super().will_accept(ctx)
|
|
135
|
+
|
|
136
|
+
return VerbRequiredBlock
|