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.
@@ -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.18'
32
- __version_tuple__ = version_tuple = (16, 0, 18)
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 successfully!";
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
- ```bash
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._store_temp_command(f"scoreboard players set @s {temp_var} {left_value}")
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._store_temp_command(f"scoreboard players add @s {temp_var} {right_value}")
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._store_temp_command(f"scoreboard players set @s {temp_var} {left_value}")
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._store_temp_command(f"scoreboard players remove @s {temp_var} {right_value}")
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
- self._store_temp_command(f"scoreboard players multiply @s {temp_var} {literal_str}")
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
- self._store_temp_command(f"scoreboard players operation @s {temp_var} *= {right_value}")
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
- literal_str = self._expression_to_value(expression.right)
1174
- self._store_temp_command(f"scoreboard players divide @s {temp_var} {literal_str}")
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
- self._store_temp_command(f"scoreboard players operation @s {temp_var} /= {right_value}")
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.18
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=mdkSHoP-7a-SjOHB7GFAkWYMURefj-puFhnmsSxEKLE,708
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=R4QZYtox-Da9B8pr_kCg_9qc9aI-ORTah7kMkhsI5tw,10373
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=3oF0XjXozma8UugNYSd3BbRADIWDAKYXYkcn_mveGHI,60636
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=Bwfk1i6PFsMB3Zs7Z6a3fgngPaWPv-KKqQRQUkFRquM,27272
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.18.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
14
- minecraft_datapack_language-16.0.18.dist-info/METADATA,sha256=h_rvudGiJ3j0gffl-lpx0BmXkKs_ycMpjzHeBxnIb_c,8344
15
- minecraft_datapack_language-16.0.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
16
- minecraft_datapack_language-16.0.18.dist-info/entry_points.txt,sha256=c6vjBeCiyQflvPHBRyBk2nJCSfYt3Oc7Sc9V87ySi_U,108
17
- minecraft_datapack_language-16.0.18.dist-info/top_level.txt,sha256=ADtFI476tbKLLxEAA-aJQAfg53MA3k_DOb0KTFiggfw,28
18
- minecraft_datapack_language-16.0.18.dist-info/RECORD,,
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,,