minecraft-datapack-language 16.0.18__py3-none-any.whl → 16.0.20__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/_version.py +2 -2
- minecraft_datapack_language/cli.py +2 -35
- minecraft_datapack_language/mdl_compiler.py +142 -11
- minecraft_datapack_language/mdl_parser.py +2 -2
- {minecraft_datapack_language-16.0.18.dist-info → minecraft_datapack_language-16.0.20.dist-info}/METADATA +1 -1
- {minecraft_datapack_language-16.0.18.dist-info → minecraft_datapack_language-16.0.20.dist-info}/RECORD +10 -10
- {minecraft_datapack_language-16.0.18.dist-info → minecraft_datapack_language-16.0.20.dist-info}/WHEEL +0 -0
- {minecraft_datapack_language-16.0.18.dist-info → minecraft_datapack_language-16.0.20.dist-info}/entry_points.txt +0 -0
- {minecraft_datapack_language-16.0.18.dist-info → minecraft_datapack_language-16.0.20.dist-info}/licenses/LICENSE +0 -0
- {minecraft_datapack_language-16.0.18.dist-info → minecraft_datapack_language-16.0.20.dist-info}/top_level.txt +0 -0
@@ -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 = '16.0.
|
32
|
-
__version_tuple__ = version_tuple = (16, 0,
|
31
|
+
__version__ = version = '16.0.20'
|
32
|
+
__version_tuple__ = version_tuple = (16, 0, 20)
|
33
33
|
|
34
34
|
__commit_id__ = commit_id = None
|
@@ -235,32 +235,14 @@ def new_command(args):
|
|
235
235
|
template_content = f'''pack "{pack_name}" "Generated by MDL CLI" {pack_format};
|
236
236
|
namespace "{project_name}";
|
237
237
|
|
238
|
-
// Variables
|
239
|
-
var num counter<@s> = 0;
|
240
|
-
var num global_timer<@a> = 0;
|
241
|
-
|
242
|
-
// Main function
|
243
238
|
function {project_name}:main {{
|
244
239
|
say "Hello from {project_name}!";
|
245
|
-
|
246
|
-
// Variable example
|
247
|
-
counter<@s> = 10;
|
248
|
-
say "Counter: $counter<@s>$";
|
249
|
-
|
250
|
-
// Conditional example
|
251
|
-
if $counter<@s>$ > 5 {{
|
252
|
-
say "High counter!";
|
253
|
-
}} else {{
|
254
|
-
say "Try again!";
|
255
|
-
}}
|
256
240
|
}}
|
257
241
|
|
258
|
-
// Init function (avoid reserved names like 'load' or 'tick')
|
259
242
|
function {project_name}:init {{
|
260
|
-
say "Datapack initialized
|
243
|
+
say "Datapack initialized!";
|
261
244
|
}}
|
262
245
|
|
263
|
-
// Hook to run on load
|
264
246
|
on_load {project_name}:init;
|
265
247
|
'''
|
266
248
|
|
@@ -285,24 +267,9 @@ A Minecraft datapack created with MDL (Minecraft Datapack Language).
|
|
285
267
|
- Run `/reload` in-game
|
286
268
|
|
287
269
|
3. **Run the main function:**
|
288
|
-
```
|
270
|
+
```
|
289
271
|
/function {project_name}:main
|
290
272
|
```
|
291
|
-
|
292
|
-
## Features
|
293
|
-
|
294
|
-
- **Variables**: Player-scoped counter and global timer
|
295
|
-
- **Control Flow**: If/else statements
|
296
|
-
- **Functions**: Main function and load hook
|
297
|
-
- **Automatic Execution**: Runs on datapack load
|
298
|
-
|
299
|
-
## Development
|
300
|
-
|
301
|
-
- Edit `{project_name}.mdl` to modify the datapack
|
302
|
-
- Use `mdl check {project_name}.mdl` to validate syntax
|
303
|
-
- Use `mdl build --mdl {project_name}.mdl -o dist` to rebuild
|
304
|
-
|
305
|
-
For more information, visit: https://www.mcmdl.com
|
306
273
|
'''
|
307
274
|
|
308
275
|
with open(readme_file, 'w', encoding='utf-8') as f:
|
@@ -12,7 +12,7 @@ from .ast_nodes import (
|
|
12
12
|
Program, PackDeclaration, NamespaceDeclaration, TagDeclaration,
|
13
13
|
VariableDeclaration, VariableAssignment, VariableSubstitution, FunctionDeclaration,
|
14
14
|
FunctionCall, IfStatement, WhileLoop, ScheduledWhileLoop, HookDeclaration, RawBlock, MacroLine,
|
15
|
-
SayCommand, BinaryExpression, LiteralExpression, ParenthesizedExpression
|
15
|
+
SayCommand, BinaryExpression, UnaryExpression, LiteralExpression, ParenthesizedExpression
|
16
16
|
)
|
17
17
|
from .dir_map import get_dir_map, DirMap
|
18
18
|
from .mdl_errors import MDLCompilerError
|
@@ -809,6 +809,42 @@ class MDLCompiler:
|
|
809
809
|
objective = self.variables.get(expression.name, expression.name)
|
810
810
|
scope = expression.scope.strip("<>")
|
811
811
|
return f"score {scope} {objective}"
|
812
|
+
elif isinstance(expression, UnaryExpression):
|
813
|
+
# Handle logical NOT elsewhere; here support unary minus for arithmetic
|
814
|
+
op = self._normalize_operator(expression.operator)
|
815
|
+
if op == '!':
|
816
|
+
# For values, ! is not meaningful; fallback to boolean temp
|
817
|
+
bool_var = self._compile_boolean_expression(expression)
|
818
|
+
return f"score @s {bool_var}"
|
819
|
+
if op == '-':
|
820
|
+
# If operand is a literal, constant-fold
|
821
|
+
if isinstance(expression.operand, LiteralExpression) and isinstance(expression.operand.value, (int, float)):
|
822
|
+
try:
|
823
|
+
v = float(expression.operand.value)
|
824
|
+
v = -v
|
825
|
+
if v.is_integer():
|
826
|
+
return str(int(v))
|
827
|
+
return str(v)
|
828
|
+
except Exception:
|
829
|
+
pass
|
830
|
+
# Otherwise, compute 0 - <operand>
|
831
|
+
rhs = self._expression_to_value(expression.operand)
|
832
|
+
temp_var = self._generate_temp_variable_name()
|
833
|
+
self._store_temp_command(f"scoreboard players set @s {temp_var} 0")
|
834
|
+
if isinstance(expression.operand, VariableSubstitution) or (isinstance(rhs, str) and rhs.startswith("score ")):
|
835
|
+
parts = str(rhs).split()
|
836
|
+
if len(parts) >= 3:
|
837
|
+
scope = parts[1]
|
838
|
+
obj = parts[2]
|
839
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} -= {scope} {obj}")
|
840
|
+
else:
|
841
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} -= {rhs}")
|
842
|
+
else:
|
843
|
+
# rhs is a literal number string
|
844
|
+
self._store_temp_command(f"scoreboard players remove @s {temp_var} {rhs}")
|
845
|
+
return f"score @s {temp_var}"
|
846
|
+
# Fallback
|
847
|
+
return self._expression_to_value(expression.operand)
|
812
848
|
elif isinstance(expression, BinaryExpression):
|
813
849
|
# For complex expressions, we need to use temporary variables
|
814
850
|
temp_var = self._generate_temp_variable_name()
|
@@ -898,6 +934,18 @@ class MDLCompiler:
|
|
898
934
|
def unwrap(e: Any) -> Any:
|
899
935
|
while isinstance(e, ParenthesizedExpression):
|
900
936
|
e = e.expression
|
937
|
+
# Collapse unary minus literal for better comparisons
|
938
|
+
try:
|
939
|
+
from .ast_nodes import UnaryExpression as _UExpr, LiteralExpression as _LExpr
|
940
|
+
if isinstance(e, _UExpr) and self._normalize_operator(getattr(e, 'operator', None)) == '-' and isinstance(e.operand, _LExpr) and isinstance(e.operand.value, (int, float)):
|
941
|
+
try:
|
942
|
+
v = float(e.operand.value)
|
943
|
+
v = -v
|
944
|
+
return LiteralExpression(value=v, type="number")
|
945
|
+
except Exception:
|
946
|
+
return e
|
947
|
+
except Exception:
|
948
|
+
pass
|
901
949
|
return e
|
902
950
|
|
903
951
|
# Handle logical operators by compiling to a boolean temp scoreboard var
|
@@ -1089,7 +1137,8 @@ class MDLCompiler:
|
|
1089
1137
|
obj = parts[2]
|
1090
1138
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} = {scope} {obj}")
|
1091
1139
|
else:
|
1092
|
-
self.
|
1140
|
+
lit = self._normalize_integer_literal_string(str(left_value), ctx="addition left operand")
|
1141
|
+
self._store_temp_command(f"scoreboard players set @s {temp_var} {lit}")
|
1093
1142
|
# Add right value
|
1094
1143
|
if isinstance(expression.right, VariableSubstitution) or (isinstance(right_value, str) and right_value.startswith("score ")):
|
1095
1144
|
parts = str(right_value).split()
|
@@ -1097,7 +1146,13 @@ class MDLCompiler:
|
|
1097
1146
|
obj = parts[2]
|
1098
1147
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} += {scope} {obj}")
|
1099
1148
|
else:
|
1100
|
-
self.
|
1149
|
+
lit = self._normalize_integer_literal_string(str(right_value), ctx="addition right operand")
|
1150
|
+
if lit == "0":
|
1151
|
+
pass
|
1152
|
+
elif lit.startswith("-"):
|
1153
|
+
self._store_temp_command(f"scoreboard players remove @s {temp_var} {lit[1:]}")
|
1154
|
+
else:
|
1155
|
+
self._store_temp_command(f"scoreboard players add @s {temp_var} {lit}")
|
1101
1156
|
|
1102
1157
|
elif expression.operator == "MINUS":
|
1103
1158
|
if isinstance(expression.left, BinaryExpression):
|
@@ -1109,7 +1164,8 @@ class MDLCompiler:
|
|
1109
1164
|
obj = parts[2]
|
1110
1165
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} = {scope} {obj}")
|
1111
1166
|
else:
|
1112
|
-
self.
|
1167
|
+
lit = self._normalize_integer_literal_string(str(left_value), ctx="subtraction left operand")
|
1168
|
+
self._store_temp_command(f"scoreboard players set @s {temp_var} {lit}")
|
1113
1169
|
# Subtract right value
|
1114
1170
|
if isinstance(expression.right, VariableSubstitution) or (isinstance(right_value, str) and right_value.startswith("score ")):
|
1115
1171
|
parts = str(right_value).split()
|
@@ -1117,7 +1173,14 @@ class MDLCompiler:
|
|
1117
1173
|
obj = parts[2]
|
1118
1174
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} -= {scope} {obj}")
|
1119
1175
|
else:
|
1120
|
-
self.
|
1176
|
+
lit = self._normalize_integer_literal_string(str(right_value), ctx="subtraction right operand")
|
1177
|
+
if lit == "0":
|
1178
|
+
pass
|
1179
|
+
elif lit.startswith("-"):
|
1180
|
+
# x - (-k) == x + k
|
1181
|
+
self._store_temp_command(f"scoreboard players add @s {temp_var} {lit[1:]}")
|
1182
|
+
else:
|
1183
|
+
self._store_temp_command(f"scoreboard players remove @s {temp_var} {lit}")
|
1121
1184
|
|
1122
1185
|
elif expression.operator == "MULTIPLY":
|
1123
1186
|
if isinstance(expression.left, BinaryExpression):
|
@@ -1137,8 +1200,13 @@ class MDLCompiler:
|
|
1137
1200
|
# For literal values, keep explicit multiply command for compatibility
|
1138
1201
|
if isinstance(expression.right, LiteralExpression):
|
1139
1202
|
# Normalize number formatting (e.g., 2.0 -> 2)
|
1140
|
-
literal_str = self._expression_to_value(expression.right)
|
1141
|
-
|
1203
|
+
literal_str = self._normalize_integer_literal_string(self._expression_to_value(expression.right), ctx="multiply literal")
|
1204
|
+
if literal_str == "0":
|
1205
|
+
self._store_temp_command(f"scoreboard players set @s {temp_var} 0")
|
1206
|
+
elif literal_str == "1":
|
1207
|
+
pass
|
1208
|
+
else:
|
1209
|
+
self._store_temp_command(f"scoreboard players multiply @s {temp_var} {literal_str}")
|
1142
1210
|
else:
|
1143
1211
|
# If right_value is a score reference string, strip the leading 'score '
|
1144
1212
|
if isinstance(right_value, str) and right_value.startswith("score "):
|
@@ -1150,7 +1218,17 @@ class MDLCompiler:
|
|
1150
1218
|
else:
|
1151
1219
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} *= {right_value}")
|
1152
1220
|
else:
|
1153
|
-
|
1221
|
+
# If RHS is a numeric literal string (incl. negatives), use multiply
|
1222
|
+
if self._is_numeric_literal_string(right_value):
|
1223
|
+
lit = self._normalize_integer_literal_string(str(right_value), ctx="multiply literal string")
|
1224
|
+
if lit == "0":
|
1225
|
+
self._store_temp_command(f"scoreboard players set @s {temp_var} 0")
|
1226
|
+
elif lit == "1":
|
1227
|
+
pass
|
1228
|
+
else:
|
1229
|
+
self._store_temp_command(f"scoreboard players multiply @s {temp_var} {lit}")
|
1230
|
+
else:
|
1231
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} *= {right_value}")
|
1154
1232
|
|
1155
1233
|
elif expression.operator == "DIVIDE":
|
1156
1234
|
if isinstance(expression.left, BinaryExpression):
|
@@ -1170,8 +1248,17 @@ class MDLCompiler:
|
|
1170
1248
|
# For literal values, keep explicit divide command for compatibility
|
1171
1249
|
if isinstance(expression.right, LiteralExpression):
|
1172
1250
|
# Normalize number formatting (e.g., 2.0 -> 2)
|
1173
|
-
|
1174
|
-
|
1251
|
+
lit = self._normalize_integer_literal_string(self._expression_to_value(expression.right), ctx="divide literal")
|
1252
|
+
if lit == "0":
|
1253
|
+
raise MDLCompilerError("Division by zero literal is not allowed", "Use a non-zero integer literal")
|
1254
|
+
if lit == "1":
|
1255
|
+
pass
|
1256
|
+
elif lit.startswith("-"):
|
1257
|
+
abs_lit = lit[1:]
|
1258
|
+
self._store_temp_command(f"scoreboard players divide @s {temp_var} {abs_lit}")
|
1259
|
+
self._store_temp_command(f"scoreboard players multiply @s {temp_var} -1")
|
1260
|
+
else:
|
1261
|
+
self._store_temp_command(f"scoreboard players divide @s {temp_var} {lit}")
|
1175
1262
|
else:
|
1176
1263
|
# If right_value is a score reference string, strip the leading 'score '
|
1177
1264
|
if isinstance(right_value, str) and right_value.startswith("score "):
|
@@ -1183,7 +1270,21 @@ class MDLCompiler:
|
|
1183
1270
|
else:
|
1184
1271
|
self._store_temp_command(f"scoreboard players operation @s {temp_var} /= {right_value}")
|
1185
1272
|
else:
|
1186
|
-
|
1273
|
+
# If RHS is a numeric literal string (incl. negatives), use divide
|
1274
|
+
if self._is_numeric_literal_string(right_value):
|
1275
|
+
lit = self._normalize_integer_literal_string(str(right_value), ctx="divide literal string")
|
1276
|
+
if lit == "0":
|
1277
|
+
raise MDLCompilerError("Division by zero literal is not allowed", "Use a non-zero integer literal")
|
1278
|
+
if lit == "1":
|
1279
|
+
pass
|
1280
|
+
elif lit.startswith("-"):
|
1281
|
+
abs_lit = lit[1:]
|
1282
|
+
self._store_temp_command(f"scoreboard players divide @s {temp_var} {abs_lit}")
|
1283
|
+
self._store_temp_command(f"scoreboard players multiply @s {temp_var} -1")
|
1284
|
+
else:
|
1285
|
+
self._store_temp_command(f"scoreboard players divide @s {temp_var} {lit}")
|
1286
|
+
else:
|
1287
|
+
self._store_temp_command(f"scoreboard players operation @s {temp_var} /= {right_value}")
|
1187
1288
|
else:
|
1188
1289
|
# For other operators, just set the value
|
1189
1290
|
self._store_temp_command(f"scoreboard players set @s {temp_var} 0")
|
@@ -1195,6 +1296,36 @@ class MDLCompiler:
|
|
1195
1296
|
else:
|
1196
1297
|
# Fallback: do nothing, but keep behavior predictable
|
1197
1298
|
pass
|
1299
|
+
|
1300
|
+
def _is_numeric_literal_string(self, s: Any) -> bool:
|
1301
|
+
"""Return True if s is a string representing an integer literal (incl. negatives)."""
|
1302
|
+
if not isinstance(s, str):
|
1303
|
+
return False
|
1304
|
+
try:
|
1305
|
+
# Allow floats that are integer-valued like "2.0" by casting then checking is_integer
|
1306
|
+
if "." in s:
|
1307
|
+
f = float(s)
|
1308
|
+
return f.is_integer()
|
1309
|
+
int(s)
|
1310
|
+
return True
|
1311
|
+
except Exception:
|
1312
|
+
return False
|
1313
|
+
|
1314
|
+
def _normalize_integer_literal_string(self, s: str, ctx: str = "") -> str:
|
1315
|
+
"""Normalize a numeric literal string to an integer string, or raise MDLCompilerError.
|
1316
|
+
Accepts negatives and floats that are mathematically integers (e.g., "2.0").
|
1317
|
+
"""
|
1318
|
+
try:
|
1319
|
+
f = float(s)
|
1320
|
+
except Exception:
|
1321
|
+
raise MDLCompilerError(f"Expected integer literal, got '{s}'", f"Invalid numeric literal in {ctx}")
|
1322
|
+
if not float(f).is_integer():
|
1323
|
+
raise MDLCompilerError(f"Scoreboards are integer-only; got non-integer '{s}'", f"Use integers in {ctx}")
|
1324
|
+
n = int(f)
|
1325
|
+
# Normalize -0 to 0
|
1326
|
+
if n == 0:
|
1327
|
+
return "0"
|
1328
|
+
return str(n)
|
1198
1329
|
|
1199
1330
|
def _generate_temp_variable_name(self) -> str:
|
1200
1331
|
"""Generate a unique temporary variable name."""
|
@@ -527,8 +527,8 @@ class MDLParser:
|
|
527
527
|
return expr
|
528
528
|
|
529
529
|
def _parse_unary(self) -> Any:
|
530
|
-
"""Parse unary expressions (logical NOT)."""
|
531
|
-
if not self._is_at_end() and self._peek().type in [TokenType.NOT]:
|
530
|
+
"""Parse unary expressions (logical NOT, unary minus)."""
|
531
|
+
if not self._is_at_end() and self._peek().type in [TokenType.NOT, TokenType.MINUS]:
|
532
532
|
operator = self._peek().type
|
533
533
|
self._advance()
|
534
534
|
operand = self._parse_unary()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: minecraft-datapack-language
|
3
|
-
Version: 16.0.
|
3
|
+
Version: 16.0.20
|
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,18 +1,18 @@
|
|
1
1
|
minecraft_datapack_language/__init__.py,sha256=0KVXBE4ScRaRUrf83aA2tVB-y8A_jplyaxVvtHH6Uw0,1199
|
2
|
-
minecraft_datapack_language/_version.py,sha256=
|
2
|
+
minecraft_datapack_language/_version.py,sha256=ZcIcMufnj-tPySvFqfRV1Vfi4VfjctQQTwFmsEGNEQA,708
|
3
3
|
minecraft_datapack_language/ast_nodes.py,sha256=L5izavSeXDr766vsfRvJrcnflXNJyXcy0WSfyJPq2ZA,4484
|
4
|
-
minecraft_datapack_language/cli.py,sha256=
|
4
|
+
minecraft_datapack_language/cli.py,sha256=shmQtNNXgw5XNlGquAR52wWtYeNyYusZTwwCZl56mMU,9522
|
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=lR33Oi7hNTeEarEw60c93ThL4_KWYaHUl42YMiXsW4g,68106
|
7
7
|
minecraft_datapack_language/mdl_errors.py,sha256=r0Gu3KhoX1YLPAVW_iO7Q_fPgaf_Dv9tOGSOdKNSzmw,16114
|
8
8
|
minecraft_datapack_language/mdl_lexer.py,sha256=YuRflOkoMOcjECPAZzoAkJciMks5amWMtGbcTIVKmAs,24166
|
9
9
|
minecraft_datapack_language/mdl_linter.py,sha256=z85xoAglENurCh30bR7kEHZ_JeMxcYaLDcGNRAl-RAI,17253
|
10
|
-
minecraft_datapack_language/mdl_parser.py,sha256=
|
10
|
+
minecraft_datapack_language/mdl_parser.py,sha256=vIcPRudxDaezNy85Q5CBcumLhCglofCNITsrRmj9YWw,27302
|
11
11
|
minecraft_datapack_language/python_api.py,sha256=Iao1jbdeW6ekeA80BZG6gNqHVjxQJEheB3DbpVsuTZQ,12304
|
12
12
|
minecraft_datapack_language/utils.py,sha256=Aq0HAGlXqj9BUTEjaEilpvzEW0EtZYYMMwOqG9db6dE,684
|
13
|
-
minecraft_datapack_language-16.0.
|
14
|
-
minecraft_datapack_language-16.0.
|
15
|
-
minecraft_datapack_language-16.0.
|
16
|
-
minecraft_datapack_language-16.0.
|
17
|
-
minecraft_datapack_language-16.0.
|
18
|
-
minecraft_datapack_language-16.0.
|
13
|
+
minecraft_datapack_language-16.0.20.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
14
|
+
minecraft_datapack_language-16.0.20.dist-info/METADATA,sha256=J8Fwzv1piUYoNxfCG11EYzbV2amGwX9KC7ofCtSBNuE,8344
|
15
|
+
minecraft_datapack_language-16.0.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
minecraft_datapack_language-16.0.20.dist-info/entry_points.txt,sha256=c6vjBeCiyQflvPHBRyBk2nJCSfYt3Oc7Sc9V87ySi_U,108
|
17
|
+
minecraft_datapack_language-16.0.20.dist-info/top_level.txt,sha256=ADtFI476tbKLLxEAA-aJQAfg53MA3k_DOb0KTFiggfw,28
|
18
|
+
minecraft_datapack_language-16.0.20.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|