minecraft-datapack-language 15.4.34__py3-none-any.whl → 15.4.35__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.
- minecraft_datapack_language/__init__.py +3 -1
- minecraft_datapack_language/_version.py +2 -2
- minecraft_datapack_language/mdl_compiler.py +14 -13
- minecraft_datapack_language/python_api.py +207 -0
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.35.dist-info}/METADATA +1 -1
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.35.dist-info}/RECORD +10 -9
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.35.dist-info}/WHEEL +0 -0
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.35.dist-info}/entry_points.txt +0 -0
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.35.dist-info}/licenses/LICENSE +0 -0
- {minecraft_datapack_language-15.4.34.dist-info → minecraft_datapack_language-15.4.35.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@ from .mdl_lexer import MDLLexer, Token, TokenType
|
|
3
3
|
from .mdl_parser import MDLParser
|
4
4
|
from .ast_nodes import *
|
5
5
|
from .dir_map import DirMap
|
6
|
+
from .python_api import Pack
|
6
7
|
|
7
8
|
__all__ = [
|
8
9
|
"MDLLexer", "Token", "TokenType",
|
@@ -13,7 +14,8 @@ __all__ = [
|
|
13
14
|
"SayCommand", "TellrawCommand", "ExecuteCommand", "ScoreboardCommand",
|
14
15
|
"BinaryExpression", "UnaryExpression", "ParenthesizedExpression", "LiteralExpression",
|
15
16
|
"ScopeSelector",
|
16
|
-
"DirMap"
|
17
|
+
"DirMap",
|
18
|
+
"Pack"
|
17
19
|
]
|
18
20
|
|
19
21
|
# CLI entry point
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
28
28
|
commit_id: COMMIT_ID
|
29
29
|
__commit_id__: COMMIT_ID
|
30
30
|
|
31
|
-
__version__ = version = '15.4.
|
32
|
-
__version_tuple__ = version_tuple = (15, 4,
|
31
|
+
__version__ = version = '15.4.35'
|
32
|
+
__version_tuple__ = version_tuple = (15, 4, 35)
|
33
33
|
|
34
34
|
__commit_id__ = commit_id = None
|
@@ -152,6 +152,12 @@ class MDLCompiler:
|
|
152
152
|
if hasattr(self, 'temp_commands'):
|
153
153
|
self.temp_commands = []
|
154
154
|
|
155
|
+
# Set current function context and reset per-function counters
|
156
|
+
self._current_function_name = func.name
|
157
|
+
self.if_counter = 0
|
158
|
+
self.else_counter = 0
|
159
|
+
self.while_counter = 0
|
160
|
+
|
155
161
|
# Generate commands from function body
|
156
162
|
for statement in func.body:
|
157
163
|
cmd = self._statement_to_command(statement)
|
@@ -497,10 +503,8 @@ class MDLCompiler:
|
|
497
503
|
loop_body_lines.append(cmd)
|
498
504
|
|
499
505
|
# Add the recursive call at the end to continue the loop
|
500
|
-
|
501
|
-
|
502
|
-
else:
|
503
|
-
loop_body_lines.append(f"execute if {condition} run function {self.current_namespace}:{loop_function_name}")
|
506
|
+
cond_str, _inv = self._build_condition(while_loop.condition)
|
507
|
+
loop_body_lines.append(f"execute if {cond_str} run function {self.current_namespace}:{loop_function_name}")
|
504
508
|
|
505
509
|
# Store the loop function as its own file
|
506
510
|
self._store_generated_function(loop_function_name, loop_body_lines)
|
@@ -517,24 +521,21 @@ class MDLCompiler:
|
|
517
521
|
|
518
522
|
def _generate_if_function_name(self) -> str:
|
519
523
|
"""Generate a unique name for an if function."""
|
520
|
-
if not hasattr(self, 'if_counter'):
|
521
|
-
self.if_counter = 0
|
522
524
|
self.if_counter += 1
|
523
|
-
|
525
|
+
prefix = getattr(self, '_current_function_name', 'fn')
|
526
|
+
return f"{prefix}__if_{self.if_counter}"
|
524
527
|
|
525
528
|
def _generate_else_function_name(self) -> str:
|
526
529
|
"""Generate a unique name for an else function."""
|
527
|
-
if not hasattr(self, 'else_counter'):
|
528
|
-
self.else_counter = 0
|
529
530
|
self.else_counter += 1
|
530
|
-
|
531
|
+
prefix = getattr(self, '_current_function_name', 'fn')
|
532
|
+
return f"{prefix}__else_{self.else_counter}"
|
531
533
|
|
532
534
|
def _generate_while_function_name(self) -> str:
|
533
535
|
"""Generate a unique name for a while function."""
|
534
|
-
if not hasattr(self, 'while_counter'):
|
535
|
-
self.while_counter = 0
|
536
536
|
self.while_counter += 1
|
537
|
-
|
537
|
+
prefix = getattr(self, '_current_function_name', 'fn')
|
538
|
+
return f"{prefix}__while_{self.while_counter}"
|
538
539
|
|
539
540
|
def _store_generated_function(self, name: str, lines: List[str]):
|
540
541
|
"""Store a generated function as a separate file under the same namespace."""
|
@@ -0,0 +1,207 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import Callable, List, Optional, Union
|
5
|
+
|
6
|
+
from .ast_nodes import (
|
7
|
+
Program,
|
8
|
+
PackDeclaration,
|
9
|
+
NamespaceDeclaration,
|
10
|
+
TagDeclaration,
|
11
|
+
VariableDeclaration,
|
12
|
+
VariableAssignment,
|
13
|
+
VariableSubstitution,
|
14
|
+
FunctionDeclaration,
|
15
|
+
FunctionCall,
|
16
|
+
IfStatement,
|
17
|
+
WhileLoop,
|
18
|
+
RawBlock,
|
19
|
+
SayCommand,
|
20
|
+
BinaryExpression,
|
21
|
+
LiteralExpression,
|
22
|
+
)
|
23
|
+
from .mdl_compiler import MDLCompiler
|
24
|
+
|
25
|
+
|
26
|
+
# ---------- Expression helpers ----------
|
27
|
+
|
28
|
+
def num(value: Union[int, float]) -> LiteralExpression:
|
29
|
+
return LiteralExpression(value=value, type="number")
|
30
|
+
|
31
|
+
|
32
|
+
def var_read(name: str, scope: str) -> VariableSubstitution:
|
33
|
+
# scope must look like <@s>, <@a>, <@e[...]>, or <global>
|
34
|
+
return VariableSubstitution(name=name, scope=scope)
|
35
|
+
|
36
|
+
|
37
|
+
def binop(left, operator: str, right) -> BinaryExpression:
|
38
|
+
# operator one of: PLUS, MINUS, MULTIPLY, DIVIDE, GREATER, LESS, GREATER_EQUAL, LESS_EQUAL, EQUAL, NOT_EQUAL
|
39
|
+
return BinaryExpression(left=left, operator=operator, right=right)
|
40
|
+
|
41
|
+
|
42
|
+
# ---------- Python Bindings ----------
|
43
|
+
|
44
|
+
|
45
|
+
class Pack:
|
46
|
+
def __init__(self, name: str, description: str = "", pack_format: int = 82):
|
47
|
+
self._pack = PackDeclaration(name=name, description=description, pack_format=pack_format)
|
48
|
+
self._namespaces: List[Namespace] = []
|
49
|
+
self._variables: List[VariableDeclaration] = []
|
50
|
+
self._tags: List[TagDeclaration] = []
|
51
|
+
self._hooks: List = [] # HookDeclaration built by Namespace
|
52
|
+
|
53
|
+
def namespace(self, name: str) -> "Namespace":
|
54
|
+
ns = Namespace(self, name)
|
55
|
+
self._namespaces.append(ns)
|
56
|
+
return ns
|
57
|
+
|
58
|
+
# Lifecycle hooks reference functions by id "ns:name"
|
59
|
+
def on_load(self, function_id: str, scope: Optional[str] = None):
|
60
|
+
# defer to Namespace to create HookDeclaration during build
|
61
|
+
self._hooks.append(("on_load", function_id, scope))
|
62
|
+
|
63
|
+
def on_tick(self, function_id: str, scope: Optional[str] = None):
|
64
|
+
self._hooks.append(("on_tick", function_id, scope))
|
65
|
+
|
66
|
+
def tag(self, registry: str, name: str, values: Optional[List[str]] = None, replace: bool = False):
|
67
|
+
values = values or []
|
68
|
+
# We store TagDeclaration; the compiler writes tag files based on tag_type/name/file_path
|
69
|
+
# Here, we map registry + name to a tag reference name; file_path left as name for placeholder.
|
70
|
+
self._tags.append(TagDeclaration(tag_type=registry, name=name, file_path=name))
|
71
|
+
|
72
|
+
def declare_var(self, name: str, scope: str, initial_value: Union[int, float]) -> None:
|
73
|
+
self._variables.append(
|
74
|
+
VariableDeclaration(var_type="num", name=name, scope=scope, initial_value=num(initial_value))
|
75
|
+
)
|
76
|
+
|
77
|
+
def build(self, output_dir: str):
|
78
|
+
# Build Program AST
|
79
|
+
namespace_nodes: List[NamespaceDeclaration] = []
|
80
|
+
function_nodes: List[FunctionDeclaration] = []
|
81
|
+
hook_nodes: List = []
|
82
|
+
|
83
|
+
# Namespaces and functions
|
84
|
+
for ns in self._namespaces:
|
85
|
+
namespace_nodes.append(NamespaceDeclaration(name=ns.name))
|
86
|
+
function_nodes.extend(ns._functions)
|
87
|
+
hook_nodes.extend(ns._hooks)
|
88
|
+
|
89
|
+
# Hooks added via Pack-level convenience
|
90
|
+
for hook_type, function_id, scope in self._hooks:
|
91
|
+
ns_name, fn_name = function_id.split(":", 1)
|
92
|
+
from .ast_nodes import HookDeclaration
|
93
|
+
|
94
|
+
hook_nodes.append(
|
95
|
+
HookDeclaration(hook_type=hook_type, namespace=ns_name, name=fn_name, scope=scope)
|
96
|
+
)
|
97
|
+
|
98
|
+
program = Program(
|
99
|
+
pack=self._pack,
|
100
|
+
namespace=namespace_nodes[0] if namespace_nodes else None,
|
101
|
+
tags=self._tags,
|
102
|
+
variables=self._variables,
|
103
|
+
functions=function_nodes,
|
104
|
+
hooks=hook_nodes,
|
105
|
+
statements=[],
|
106
|
+
)
|
107
|
+
|
108
|
+
MDLCompiler(output_dir).compile(program, output_dir)
|
109
|
+
|
110
|
+
|
111
|
+
class Namespace:
|
112
|
+
def __init__(self, pack: Pack, name: str):
|
113
|
+
self._pack = pack
|
114
|
+
self.name = name
|
115
|
+
self._functions: List[FunctionDeclaration] = []
|
116
|
+
self._hooks: List = []
|
117
|
+
|
118
|
+
def function(self, name: str, *commands_or_builder: Union[str, Callable[["FunctionBuilder"], None]]):
|
119
|
+
builder = FunctionBuilder(self._pack, self, name)
|
120
|
+
|
121
|
+
# If a single callable is given, treat it as a builder lambda
|
122
|
+
if len(commands_or_builder) == 1 and callable(commands_or_builder[0]):
|
123
|
+
commands_or_builder[0](builder)
|
124
|
+
else:
|
125
|
+
# Interpret simple strings: say "..."; exec ns:name; raw lines fall back to RawBlock
|
126
|
+
for cmd in commands_or_builder:
|
127
|
+
if not isinstance(cmd, str):
|
128
|
+
continue
|
129
|
+
stripped = cmd.strip().rstrip(";")
|
130
|
+
if stripped.startswith("say "):
|
131
|
+
msg = stripped[len("say ") :].strip()
|
132
|
+
if msg.startswith("\"") and msg.endswith("\""):
|
133
|
+
msg = msg[1:-1]
|
134
|
+
builder.say(msg)
|
135
|
+
elif stripped.startswith("exec "):
|
136
|
+
target = stripped[len("exec ") :].strip()
|
137
|
+
# Optional scope in angle brackets e.g., util:helper<@s>
|
138
|
+
scope = None
|
139
|
+
if "<" in target and target.endswith(">"):
|
140
|
+
scope = target[target.index("<") :]
|
141
|
+
target = target[: target.index("<")]
|
142
|
+
builder.exec(target, scope)
|
143
|
+
else:
|
144
|
+
builder.raw(cmd)
|
145
|
+
|
146
|
+
func_node = FunctionDeclaration(namespace=self.name, name=name, scope=None, body=builder._body)
|
147
|
+
self._functions.append(func_node)
|
148
|
+
return func_node
|
149
|
+
|
150
|
+
# Convenience forwarding
|
151
|
+
def on_load(self, function_id: str, scope: Optional[str] = None):
|
152
|
+
from .ast_nodes import HookDeclaration
|
153
|
+
|
154
|
+
ns_name, fn_name = function_id.split(":", 1)
|
155
|
+
self._hooks.append(HookDeclaration(hook_type="on_load", namespace=ns_name, name=fn_name, scope=scope))
|
156
|
+
|
157
|
+
def on_tick(self, function_id: str, scope: Optional[str] = None):
|
158
|
+
from .ast_nodes import HookDeclaration
|
159
|
+
|
160
|
+
ns_name, fn_name = function_id.split(":", 1)
|
161
|
+
self._hooks.append(HookDeclaration(hook_type="on_tick", namespace=ns_name, name=fn_name, scope=scope))
|
162
|
+
|
163
|
+
|
164
|
+
class FunctionBuilder:
|
165
|
+
def __init__(self, pack: Pack, namespace: Namespace, function_name: str):
|
166
|
+
self._pack = pack
|
167
|
+
self._namespace = namespace
|
168
|
+
self._name = function_name
|
169
|
+
self._body: List = []
|
170
|
+
|
171
|
+
# Basics
|
172
|
+
def say(self, message: str):
|
173
|
+
self._body.append(SayCommand(message=message, variables=[]))
|
174
|
+
|
175
|
+
def raw(self, content: str):
|
176
|
+
self._body.append(RawBlock(content=content.rstrip(";")))
|
177
|
+
|
178
|
+
def exec(self, function_id: str, scope: Optional[str] = None):
|
179
|
+
ns, fn = function_id.split(":", 1)
|
180
|
+
self._body.append(FunctionCall(namespace=ns, name=fn, scope=scope))
|
181
|
+
|
182
|
+
# Variables
|
183
|
+
def declare_var(self, name: str, scope: str, initial_value: Union[int, float]):
|
184
|
+
self._pack.declare_var(name, scope, initial_value)
|
185
|
+
# Also set to initial value in this function
|
186
|
+
self.set(name, scope, num(initial_value))
|
187
|
+
|
188
|
+
def set(self, name: str, scope: str, value_expr) -> None:
|
189
|
+
self._body.append(VariableAssignment(name=name, scope=scope, value=value_expr))
|
190
|
+
|
191
|
+
# Control flow
|
192
|
+
def if_(self, condition_expr, then_builder: Callable[["FunctionBuilder"], None], else_builder: Optional[Callable[["FunctionBuilder"], None]] = None):
|
193
|
+
then_fb = FunctionBuilder(self._pack, self._namespace, self._name)
|
194
|
+
then_builder(then_fb)
|
195
|
+
else_body = None
|
196
|
+
if else_builder:
|
197
|
+
else_fb = FunctionBuilder(self._pack, self._namespace, self._name)
|
198
|
+
else_builder(else_fb)
|
199
|
+
else_body = else_fb._body
|
200
|
+
self._body.append(IfStatement(condition=condition_expr, then_body=then_fb._body, else_body=else_body))
|
201
|
+
|
202
|
+
def while_(self, condition_expr, body_builder: Callable[["FunctionBuilder"], None]):
|
203
|
+
body_fb = FunctionBuilder(self._pack, self._namespace, self._name)
|
204
|
+
body_builder(body_fb)
|
205
|
+
self._body.append(WhileLoop(condition=condition_expr, body=body_fb._body))
|
206
|
+
|
207
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: minecraft-datapack-language
|
3
|
-
Version: 15.4.
|
3
|
+
Version: 15.4.35
|
4
4
|
Summary: Compile MDL language with explicit scoping into a Minecraft datapack (1.21+ ready). Features variables, control flow, error handling, and VS Code extension.
|
5
5
|
Project-URL: Homepage, https://www.mcmdl.com
|
6
6
|
Project-URL: Documentation, https://www.mcmdl.com/docs
|
@@ -1,17 +1,18 @@
|
|
1
|
-
minecraft_datapack_language/__init__.py,sha256=
|
2
|
-
minecraft_datapack_language/_version.py,sha256=
|
1
|
+
minecraft_datapack_language/__init__.py,sha256=0KVXBE4ScRaRUrf83aA2tVB-y8A_jplyaxVvtHH6Uw0,1199
|
2
|
+
minecraft_datapack_language/_version.py,sha256=W9y3fLZG1wVFwyZO8tkeYzJ_ngoWlfZ8UpHlW0Gsaw4,708
|
3
3
|
minecraft_datapack_language/ast_nodes.py,sha256=nbWrRz137MGMRpmnq8QkXNzrtlaCgyPEknytbkrS_M8,3899
|
4
4
|
minecraft_datapack_language/cli.py,sha256=-TMAL1HCCtwf0aG46x88MVBsYUswPRCVhy854li7X9c,9780
|
5
5
|
minecraft_datapack_language/dir_map.py,sha256=HmxFkuvWGkzHF8o_GFb4BpuMCRc6QMw8UbmcAI8JVdY,1788
|
6
|
-
minecraft_datapack_language/mdl_compiler.py,sha256=
|
6
|
+
minecraft_datapack_language/mdl_compiler.py,sha256=uw6IcX428HtFD6b_nlcOQQ2V7vx0g4HesQzg22vBnOg,35367
|
7
7
|
minecraft_datapack_language/mdl_errors.py,sha256=r0Gu3KhoX1YLPAVW_iO7Q_fPgaf_Dv9tOGSOdKNSzmw,16114
|
8
8
|
minecraft_datapack_language/mdl_lexer.py,sha256=CjbEUpuuF4eU_ucA_WIhw6wSMcHGk2BchtQ0bLAGvwg,22033
|
9
9
|
minecraft_datapack_language/mdl_linter.py,sha256=z85xoAglENurCh30bR7kEHZ_JeMxcYaLDcGNRAl-RAI,17253
|
10
10
|
minecraft_datapack_language/mdl_parser.py,sha256=aQPKcmATM9BOMzO7vCXmMdxU1qjOJNLCSAKJopu5h3g,23429
|
11
|
+
minecraft_datapack_language/python_api.py,sha256=yU8SIhxRfCWsDW3qBheMQD2Ii0Y6-Tk9VMvVncEPlv4,8183
|
11
12
|
minecraft_datapack_language/utils.py,sha256=Aq0HAGlXqj9BUTEjaEilpvzEW0EtZYYMMwOqG9db6dE,684
|
12
|
-
minecraft_datapack_language-15.4.
|
13
|
-
minecraft_datapack_language-15.4.
|
14
|
-
minecraft_datapack_language-15.4.
|
15
|
-
minecraft_datapack_language-15.4.
|
16
|
-
minecraft_datapack_language-15.4.
|
17
|
-
minecraft_datapack_language-15.4.
|
13
|
+
minecraft_datapack_language-15.4.35.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
14
|
+
minecraft_datapack_language-15.4.35.dist-info/METADATA,sha256=Np352vNOiaQ91lHGz0TRPKkeYaCye84jo2Kyg7M6tvY,8360
|
15
|
+
minecraft_datapack_language-15.4.35.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
minecraft_datapack_language-15.4.35.dist-info/entry_points.txt,sha256=c6vjBeCiyQflvPHBRyBk2nJCSfYt3Oc7Sc9V87ySi_U,108
|
17
|
+
minecraft_datapack_language-15.4.35.dist-info/top_level.txt,sha256=ADtFI476tbKLLxEAA-aJQAfg53MA3k_DOb0KTFiggfw,28
|
18
|
+
minecraft_datapack_language-15.4.35.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|