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.
- minecraft_datapack_language/__init__.py +17 -2
- minecraft_datapack_language/_version.py +2 -2
- minecraft_datapack_language/ast_nodes.py +87 -59
- minecraft_datapack_language/mdl_compiler.py +470 -0
- minecraft_datapack_language/mdl_errors.py +14 -0
- minecraft_datapack_language/mdl_lexer.py +624 -0
- minecraft_datapack_language/mdl_parser.py +573 -0
- minecraft_datapack_language-15.4.29.dist-info/METADATA +266 -0
- minecraft_datapack_language-15.4.29.dist-info/RECORD +16 -0
- minecraft_datapack_language/cli.py +0 -159
- minecraft_datapack_language/cli_build.py +0 -1292
- minecraft_datapack_language/cli_check.py +0 -155
- minecraft_datapack_language/cli_colors.py +0 -264
- minecraft_datapack_language/cli_help.py +0 -508
- minecraft_datapack_language/cli_new.py +0 -300
- minecraft_datapack_language/cli_utils.py +0 -276
- minecraft_datapack_language/expression_processor.py +0 -352
- minecraft_datapack_language/linter.py +0 -409
- minecraft_datapack_language/mdl_lexer_js.py +0 -754
- minecraft_datapack_language/mdl_parser_js.py +0 -1049
- minecraft_datapack_language/pack.py +0 -758
- minecraft_datapack_language-15.4.27.dist-info/METADATA +0 -1274
- minecraft_datapack_language-15.4.27.dist-info/RECORD +0 -25
- {minecraft_datapack_language-15.4.27.dist-info → minecraft_datapack_language-15.4.29.dist-info}/WHEEL +0 -0
- {minecraft_datapack_language-15.4.27.dist-info → minecraft_datapack_language-15.4.29.dist-info}/entry_points.txt +0 -0
- {minecraft_datapack_language-15.4.27.dist-info → minecraft_datapack_language-15.4.29.dist-info}/licenses/LICENSE +0 -0
- {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()
|