minecraft-datapack-language 15.4.27__py3-none-any.whl → 15.4.29__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.
Files changed (27) hide show
  1. minecraft_datapack_language/__init__.py +17 -2
  2. minecraft_datapack_language/_version.py +2 -2
  3. minecraft_datapack_language/ast_nodes.py +87 -59
  4. minecraft_datapack_language/mdl_compiler.py +470 -0
  5. minecraft_datapack_language/mdl_errors.py +14 -0
  6. minecraft_datapack_language/mdl_lexer.py +624 -0
  7. minecraft_datapack_language/mdl_parser.py +573 -0
  8. minecraft_datapack_language-15.4.29.dist-info/METADATA +266 -0
  9. minecraft_datapack_language-15.4.29.dist-info/RECORD +16 -0
  10. minecraft_datapack_language/cli.py +0 -159
  11. minecraft_datapack_language/cli_build.py +0 -1292
  12. minecraft_datapack_language/cli_check.py +0 -155
  13. minecraft_datapack_language/cli_colors.py +0 -264
  14. minecraft_datapack_language/cli_help.py +0 -508
  15. minecraft_datapack_language/cli_new.py +0 -300
  16. minecraft_datapack_language/cli_utils.py +0 -276
  17. minecraft_datapack_language/expression_processor.py +0 -352
  18. minecraft_datapack_language/linter.py +0 -409
  19. minecraft_datapack_language/mdl_lexer_js.py +0 -754
  20. minecraft_datapack_language/mdl_parser_js.py +0 -1049
  21. minecraft_datapack_language/pack.py +0 -758
  22. minecraft_datapack_language-15.4.27.dist-info/METADATA +0 -1274
  23. minecraft_datapack_language-15.4.27.dist-info/RECORD +0 -25
  24. {minecraft_datapack_language-15.4.27.dist-info → minecraft_datapack_language-15.4.29.dist-info}/WHEEL +0 -0
  25. {minecraft_datapack_language-15.4.27.dist-info → minecraft_datapack_language-15.4.29.dist-info}/entry_points.txt +0 -0
  26. {minecraft_datapack_language-15.4.27.dist-info → minecraft_datapack_language-15.4.29.dist-info}/licenses/LICENSE +0 -0
  27. {minecraft_datapack_language-15.4.27.dist-info → minecraft_datapack_language-15.4.29.dist-info}/top_level.txt +0 -0
@@ -1,352 +0,0 @@
1
- """
2
- Expression Processor for MDL to Minecraft Command Translation
3
-
4
- This module handles simple expressions for the simplified MDL language.
5
- Only supports number variables, simple arithmetic, and variable substitutions.
6
- """
7
-
8
- import re
9
- from typing import List, Optional
10
- from dataclasses import dataclass
11
-
12
-
13
- @dataclass
14
- class ProcessedExpression:
15
- """Represents a processed expression with its temporary variables and final command"""
16
- temp_assignments: List[str] # Commands to set up temporary variables
17
- final_command: str # The final command using the processed expression
18
- temp_vars: List[str] # List of temporary variables created
19
-
20
-
21
- class ExpressionProcessor:
22
- """Handles simple expressions for the simplified MDL language"""
23
-
24
- def __init__(self):
25
- self.temp_counter = 0
26
- self.temp_vars_used = set()
27
-
28
- def generate_temp_var(self, prefix: str = "temp") -> str:
29
- """Generate a unique temporary variable name"""
30
- while True:
31
- temp_var = f"{prefix}_{self.temp_counter}"
32
- self.temp_counter += 1
33
- if temp_var not in self.temp_vars_used:
34
- self.temp_vars_used.add(temp_var)
35
- return temp_var
36
-
37
- def is_complex_expression(self, expr) -> bool:
38
- """Determine if an expression is complex and needs breakdown"""
39
- if not hasattr(expr, '__class__'):
40
- return False
41
-
42
- class_name = expr.__class__.__name__
43
-
44
- # Only complex expressions we support
45
- complex_types = [
46
- 'BinaryExpression', # a + b, a * b, etc.
47
- ]
48
-
49
- return class_name in complex_types
50
-
51
- def process_binary_expression(self, expr, target_var: str, selector: str = "@s") -> ProcessedExpression:
52
- """Process binary expressions like a + b, a * b, etc."""
53
- print(f"DEBUG: process_binary_expression called: target_var='{target_var}', selector='{selector}', operator='{expr.operator}'")
54
- commands = []
55
- temp_vars = []
56
-
57
- # Process left operand
58
- if self.is_complex_expression(expr.left):
59
- left_temp = self.generate_temp_var("left")
60
- temp_vars.append(left_temp)
61
- left_result = self.process_expression(expr.left, left_temp, selector)
62
- commands.extend(left_result.temp_assignments)
63
- left_var = left_temp
64
- else:
65
- left_var = self.extract_simple_value(expr.left)
66
-
67
- # Process right operand
68
- if self.is_complex_expression(expr.right):
69
- right_temp = self.generate_temp_var("right")
70
- temp_vars.append(right_temp)
71
- right_result = self.process_expression(expr.right, right_temp, selector)
72
- commands.extend(right_result.temp_assignments)
73
- right_var = right_temp
74
- else:
75
- right_var = self.extract_simple_value(expr.right)
76
-
77
- # Generate operation command
78
- op_command = self.generate_binary_operation(expr.operator, left_var, right_var, target_var, selector)
79
- commands.append(op_command)
80
-
81
- return ProcessedExpression(commands, "", temp_vars)
82
-
83
- def extract_simple_value(self, expr) -> str:
84
- """Extract a simple value from an expression"""
85
- if hasattr(expr, 'name'):
86
- # Check if the variable name contains scope information
87
- if '<' in expr.name and expr.name.endswith('>'):
88
- return expr.name # Return the full scoped variable name
89
- return expr.name
90
- elif hasattr(expr, 'value'):
91
- return str(expr.value)
92
- elif hasattr(expr, 'variable_name'):
93
- # Handle VariableSubstitutionExpression
94
- if hasattr(expr, 'scope_selector') and expr.scope_selector:
95
- # For scoped variables, we need to handle them specially in binary operations
96
- return f"{expr.variable_name}<{expr.scope_selector}>"
97
- else:
98
- return expr.variable_name
99
- else:
100
- return str(expr)
101
-
102
- def _is_same_variable(self, var1: str, var2: str) -> bool:
103
- """Check if two variables are the same, handling scoped variables"""
104
- # Extract base variable names (without scope)
105
- base1 = var1.split('<')[0] if '<' in var1 else var1
106
- base2 = var2.split('<')[0] if '<' in var2 else var2
107
- result = base1 == base2
108
- print(f"DEBUG: _is_same_variable({var1}, {var2}) -> base1={base1}, base2={base2}, result={result}")
109
- return result
110
-
111
- def parse_scoped_variable(self, var_str: str) -> tuple[str, str]:
112
- """Parse a scoped variable string into (scope_selector, variable_name) for use in scoreboard commands"""
113
- if '<' in var_str and var_str.endswith('>'):
114
- parts = var_str.split('<', 1)
115
- if len(parts) == 2:
116
- variable_name = parts[0]
117
- scope_selector = parts[1][:-1] # Remove closing >
118
- # Resolve special selectors
119
- if scope_selector == "global":
120
- scope_selector = "@e[type=armor_stand,tag=mdl_server,limit=1]"
121
- return scope_selector, variable_name # Return (selector, variable_name) for correct command order
122
- return "@s", var_str # Default to @s if no scope specified
123
-
124
- def generate_binary_operation(self, operator: str, left: str, right: str, target: str, selector: str = "@s") -> str:
125
- """Generate a binary operation command"""
126
- print(f"DEBUG: generate_binary_operation called: operator='{operator}', left='{left}', right='{right}', target='{target}'")
127
- # Extract base variable name from target if it's scoped
128
- base_target = target
129
- if '<' in target and target.endswith('>'):
130
- base_target = target.split('<', 1)[0]
131
-
132
- # Check if left and right are numeric literals
133
- try:
134
- left_num = int(left)
135
- is_left_literal = True
136
- except (ValueError, TypeError):
137
- is_left_literal = False
138
-
139
- try:
140
- right_num = int(right)
141
- is_right_literal = True
142
- except (ValueError, TypeError):
143
- is_right_literal = False
144
-
145
- # Check if left and right are scoped variables
146
- left_selector, left_var = self.parse_scoped_variable(left)
147
- right_selector, right_var = self.parse_scoped_variable(right)
148
-
149
- # The parse_scoped_variable now returns (selector, variable_name) for correct command order
150
-
151
- # For literal numbers, we can use direct add/remove/set
152
- # For variable operands, we need to use scoreboard operations
153
-
154
- if operator == '+':
155
- if is_right_literal:
156
- # For literal numbers, use direct add
157
- # Check if this is a self-modification case (left variable equals target variable)
158
- print(f"DEBUG: + operator with literal: left='{left}', target='{target}'")
159
- # More aggressive check for same variable
160
- left_base = left.split('<')[0] if '<' in left else left
161
- target_base = target.split('<')[0] if '<' in target else target
162
- if left_base == target_base or self._is_same_variable(left, target):
163
- # Avoid self-assignment - just add the literal
164
- print(f"DEBUG: Same variable detected for + operator, using direct add")
165
- return f"scoreboard players add {selector} {base_target} {right}"
166
- elif is_left_literal:
167
- # Both are literals, set left then add right
168
- return f"scoreboard players set {selector} {base_target} {left}\nscoreboard players add {selector} {base_target} {right}"
169
- else:
170
- # Left is variable, right is literal
171
- return f"scoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players add {selector} {base_target} {right}"
172
- else:
173
- # For variable operands, use scoreboard operation
174
- if left == target:
175
- # Avoid self-assignment
176
- return f"scoreboard players operation {selector} {base_target} += {right_selector} {right_var}"
177
- elif is_left_literal:
178
- # Left is literal, right is variable
179
- return f"scoreboard players set {selector} {base_target} {left}\nscoreboard players operation {selector} {base_target} += {right_selector} {right_var}"
180
- else:
181
- # Both are variables
182
- return f"scoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players operation {selector} {base_target} += {right_selector} {right_var}"
183
-
184
- elif operator == '-':
185
- if is_right_literal:
186
- # For literal numbers, use direct remove
187
- # Check if this is a self-modification case (left variable equals target variable)
188
- print(f"DEBUG: - operator with literal: left='{left}', target='{target}'")
189
- # More aggressive check for same variable
190
- left_base = left.split('<')[0] if '<' in left else left
191
- target_base = target.split('<')[0] if '<' in target else target
192
- if left_base == target_base or self._is_same_variable(left, target):
193
- # Avoid self-assignment - just remove the literal
194
- print(f"DEBUG: Same variable detected for - operator, using direct remove")
195
- return f"scoreboard players remove {selector} {base_target} {right}"
196
- elif is_left_literal:
197
- # Both are literals, set left then remove right
198
- return f"scoreboard players set {selector} {base_target} {left}\nscoreboard players remove {selector} {base_target} {right}"
199
- else:
200
- # Left is variable, right is literal
201
- return f"scoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players remove {selector} {base_target} {right}"
202
- else:
203
- # For variable operands, use scoreboard operation
204
- if left == target:
205
- # Avoid self-assignment
206
- return f"scoreboard players operation {selector} {base_target} -= {right_selector} {right_var}"
207
- elif is_left_literal:
208
- # Left is literal, right is variable
209
- return f"scoreboard players set {selector} {base_target} {left}\nscoreboard players operation {selector} {base_target} -= {right_selector} {right_var}"
210
- else:
211
- # Both are variables
212
- return f"scoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players operation {selector} {base_target} -= {right_selector} {right_var}"
213
-
214
- elif operator == '*':
215
- if is_right_literal:
216
- # For multiplication with literal, we need to create a temporary objective
217
- temp_obj = f"temp_{right}"
218
- if left == target:
219
- # Avoid self-assignment
220
- return f"scoreboard objectives add {temp_obj} dummy\nscoreboard players set {selector} {temp_obj} {right}\nscoreboard players operation {selector} {base_target} *= @s {temp_obj}"
221
- elif is_left_literal:
222
- # Both are literals, set left then multiply by right
223
- return f"scoreboard objectives add {temp_obj} dummy\nscoreboard players set {selector} {base_target} {left}\nscoreboard players set {selector} {temp_obj} {right}\nscoreboard players operation {selector} {base_target} *= @s {temp_obj}"
224
- else:
225
- # Left is variable, right is literal
226
- return f"scoreboard objectives add {temp_obj} dummy\nscoreboard players set {selector} {temp_obj} {right}\nscoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players operation {selector} {base_target} *= @s {temp_obj}"
227
- else:
228
- # For variable operands, use scoreboard operation
229
- if left == target:
230
- # Avoid self-assignment
231
- return f"scoreboard players operation {selector} {base_target} *= {right_selector} {right_var}"
232
- elif is_left_literal:
233
- # Left is literal, right is variable
234
- return f"scoreboard players set {selector} {base_target} {left}\nscoreboard players operation {selector} {base_target} *= {right_selector} {right_var}"
235
- else:
236
- # Both are variables
237
- return f"scoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players operation {selector} {base_target} *= {right_selector} {right_var}"
238
-
239
- elif operator == '/':
240
- if is_right_literal:
241
- # For division with literal, we need to create a temporary objective
242
- temp_obj = f"temp_{right}"
243
- if left == target:
244
- # Avoid self-assignment
245
- return f"scoreboard objectives add {temp_obj} dummy\nscoreboard players set {selector} {temp_obj} {right}\nscoreboard players operation {selector} {base_target} /= @s {temp_obj}"
246
- elif is_left_literal:
247
- # Both are literals, set left then divide by right
248
- return f"scoreboard objectives add {temp_obj} dummy\nscoreboard players set {selector} {base_target} {left}\nscoreboard players set {selector} {temp_obj} {right}\nscoreboard players operation {selector} {base_target} /= @s {temp_obj}"
249
- else:
250
- # Left is variable, right is literal
251
- return f"scoreboard objectives add {temp_obj} dummy\nscoreboard players set {selector} {temp_obj} {right}\nscoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players operation {selector} {base_target} /= @s {temp_obj}"
252
- else:
253
- # For variable operands, use scoreboard operation
254
- if left == target:
255
- # Avoid self-assignment
256
- return f"scoreboard players operation {selector} {base_target} /= {right_selector} {right_var}"
257
- elif is_left_literal:
258
- # Left is literal, right is variable
259
- return f"scoreboard players set {selector} {base_target} {left}\nscoreboard players operation {selector} {base_target} /= {right_selector} {right_var}"
260
- else:
261
- # Both are variables
262
- return f"scoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players operation {selector} {base_target} /= {right_selector} {right_var}"
263
-
264
- else:
265
- # Default to addition for unknown operators
266
- if is_right_literal:
267
- if left == target:
268
- # Avoid self-assignment
269
- return f"scoreboard players add {selector} {base_target} {right}"
270
- elif is_left_literal:
271
- # Both are literals, set left then add right
272
- return f"scoreboard players set {selector} {base_target} {left}\nscoreboard players add {selector} {base_target} {right}"
273
- else:
274
- # Left is variable, right is literal
275
- return f"scoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players add {selector} {base_target} {right}"
276
- else:
277
- if left == target:
278
- # Avoid self-assignment
279
- return f"scoreboard players operation {selector} {base_target} += {right_selector} {right_var}"
280
- elif is_left_literal:
281
- # Left is literal, right is variable
282
- return f"scoreboard players set {selector} {base_target} {left}\nscoreboard players operation {selector} {base_target} += {right_selector} {right_var}"
283
- else:
284
- # Both are variables
285
- return f"scoreboard players operation {selector} {base_target} = {left_selector} {left_var}\nscoreboard players operation {selector} {base_target} += {right_selector} {right_var}"
286
-
287
- def process_expression(self, expr, target_var: str, selector: str = "@s") -> ProcessedExpression:
288
- """Main entry point for processing any expression"""
289
- print(f"DEBUG: process_expression called: target_var='{target_var}', selector='{selector}', expr_type='{type(expr).__name__}'")
290
- # Extract base variable name from target if it's scoped
291
- base_target_var = target_var
292
- if '<' in target_var and target_var.endswith('>'):
293
- base_target_var = target_var.split('<', 1)[0]
294
-
295
- if not hasattr(expr, '__class__'):
296
- # Simple value
297
- commands = [f"scoreboard players set {selector} {base_target_var} {expr}"]
298
- return ProcessedExpression(commands, "", [])
299
-
300
- class_name = expr.__class__.__name__
301
-
302
- if class_name == 'BinaryExpression':
303
- return self.process_binary_expression(expr, base_target_var, selector)
304
- elif class_name == 'LiteralExpression':
305
- # Handle literal expressions (numbers only)
306
- try:
307
- value = int(expr.value)
308
- commands = [f"scoreboard players set {selector} {base_target_var} {value}"]
309
- except (ValueError, TypeError):
310
- # If not a number, set to 0
311
- commands = [f"scoreboard players set {selector} {base_target_var} 0"]
312
- return ProcessedExpression(commands, "", [])
313
- elif class_name == 'VariableExpression':
314
- # Variable reference - copy from scoreboard
315
- # Check if the variable name contains scope information
316
- if hasattr(expr, 'scope_selector') and expr.scope_selector:
317
- # Use the scope selector from the AST node
318
- source_selector = expr.scope_selector
319
- source_var = expr.name
320
- elif '<' in expr.name and expr.name.endswith('>'):
321
- # Parse scoped variable
322
- var_selector, var_name = self.parse_scoped_variable(expr.name)
323
- source_selector = var_selector
324
- source_var = var_name
325
- else:
326
- # Use default selector
327
- source_selector = selector
328
- source_var = expr.name
329
- commands = [f"scoreboard players operation {selector} {base_target_var} = {source_selector} {source_var}"]
330
- return ProcessedExpression(commands, "", [])
331
- elif class_name == 'VariableSubstitutionExpression':
332
- # Variable substitution ($variable$ or $variable<selector>$) - read from scoreboard
333
- if hasattr(expr, 'scope_selector') and expr.scope_selector:
334
- # Use the specified scope selector
335
- source_selector = expr.scope_selector
336
- else:
337
- # Use the default selector
338
- source_selector = selector
339
-
340
- commands = [f"scoreboard players operation {selector} {base_target_var} = {source_selector} {expr.variable_name}"]
341
- return ProcessedExpression(commands, "", [])
342
- elif hasattr(expr, 'left') and hasattr(expr, 'right') and hasattr(expr, 'operator'):
343
- # This is a binary expression that wasn't caught by BinaryExpression class
344
- return self.process_binary_expression(expr, base_target_var, selector)
345
- else:
346
- # Unknown expression type - set to 0
347
- commands = [f"scoreboard players set {selector} {base_target_var} 0"]
348
- return ProcessedExpression(commands, "", [])
349
-
350
-
351
- # Global instance for use in other modules
352
- expression_processor = ExpressionProcessor()