minecraft-datapack-language 16.0.15__py3-none-any.whl → 16.0.17__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/mdl_compiler.py +91 -1
- minecraft_datapack_language/mdl_lexer.py +8 -2
- minecraft_datapack_language/mdl_parser.py +32 -3
- {minecraft_datapack_language-16.0.15.dist-info → minecraft_datapack_language-16.0.17.dist-info}/METADATA +1 -1
- {minecraft_datapack_language-16.0.15.dist-info → minecraft_datapack_language-16.0.17.dist-info}/RECORD +10 -10
- {minecraft_datapack_language-16.0.15.dist-info → minecraft_datapack_language-16.0.17.dist-info}/WHEEL +0 -0
- {minecraft_datapack_language-16.0.15.dist-info → minecraft_datapack_language-16.0.17.dist-info}/entry_points.txt +0 -0
- {minecraft_datapack_language-16.0.15.dist-info → minecraft_datapack_language-16.0.17.dist-info}/licenses/LICENSE +0 -0
- {minecraft_datapack_language-16.0.15.dist-info → minecraft_datapack_language-16.0.17.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.17'
|
32
|
+
__version_tuple__ = version_tuple = (16, 0, 17)
|
33
33
|
|
34
34
|
__commit_id__ = commit_id = None
|
@@ -824,7 +824,7 @@ class MDLCompiler:
|
|
824
824
|
Returns one of: '>', '>=', '<', '<=', '==', '!=' or None if unknown.
|
825
825
|
"""
|
826
826
|
# Direct symbol passthrough
|
827
|
-
if op_in in ('>', '>=', '<', '<=', '==', '!='):
|
827
|
+
if op_in in ('>', '>=', '<', '<=', '==', '!=', '&&', '||', '!'):
|
828
828
|
return op_in
|
829
829
|
# TokenType instances
|
830
830
|
try:
|
@@ -840,6 +840,13 @@ class MDLCompiler:
|
|
840
840
|
return '=='
|
841
841
|
if op_in == TokenType.NOT_EQUAL:
|
842
842
|
return '!='
|
843
|
+
# Logical
|
844
|
+
if getattr(TokenType, 'AND', None) and op_in == TokenType.AND:
|
845
|
+
return '&&'
|
846
|
+
if getattr(TokenType, 'OR', None) and op_in == TokenType.OR:
|
847
|
+
return '||'
|
848
|
+
if getattr(TokenType, 'NOT', None) and op_in == TokenType.NOT:
|
849
|
+
return '!'
|
843
850
|
except Exception:
|
844
851
|
pass
|
845
852
|
# String names from bindings or parser
|
@@ -857,6 +864,12 @@ class MDLCompiler:
|
|
857
864
|
return '=='
|
858
865
|
if upper == 'NOT_EQUAL' or upper == 'NE':
|
859
866
|
return '!='
|
867
|
+
if upper in ('AND', '&&'):
|
868
|
+
return '&&'
|
869
|
+
if upper in ('OR', '||'):
|
870
|
+
return '||'
|
871
|
+
if upper in ('NOT', '!'):
|
872
|
+
return '!'
|
860
873
|
return None
|
861
874
|
|
862
875
|
def _expression_to_condition(self, expression: Any) -> str:
|
@@ -887,6 +900,17 @@ class MDLCompiler:
|
|
887
900
|
e = e.expression
|
888
901
|
return e
|
889
902
|
|
903
|
+
# Handle logical operators by compiling to a boolean temp scoreboard var
|
904
|
+
unwrapped = unwrap(expression)
|
905
|
+
op_sym_unwrapped = None
|
906
|
+
# Import here to avoid top-level cycle
|
907
|
+
from .ast_nodes import UnaryExpression as _UnaryExpr
|
908
|
+
if isinstance(unwrapped, BinaryExpression) or isinstance(unwrapped, _UnaryExpr):
|
909
|
+
op_sym_unwrapped = self._normalize_operator(getattr(unwrapped, 'operator', None))
|
910
|
+
if op_sym_unwrapped in ('&&', '||', '!'):
|
911
|
+
bool_var = self._compile_boolean_expression(unwrapped)
|
912
|
+
return (f"score @s {bool_var} matches 1..", False)
|
913
|
+
|
890
914
|
if isinstance(expression, BinaryExpression):
|
891
915
|
left = unwrap(expression.left)
|
892
916
|
right = unwrap(expression.right)
|
@@ -945,9 +969,75 @@ class MDLCompiler:
|
|
945
969
|
if op_sym == "!=":
|
946
970
|
# Use equals with inversion
|
947
971
|
return (f"score {lscope} {lobj} = {rscope} {robj}", True)
|
972
|
+
|
973
|
+
# General scoreboard vs scoreboard (covers temps produced by BinaryExpression)
|
974
|
+
if op_sym:
|
975
|
+
try:
|
976
|
+
left_val = self._expression_to_value(left)
|
977
|
+
right_val = self._expression_to_value(right)
|
978
|
+
except Exception:
|
979
|
+
left_val = None
|
980
|
+
right_val = None
|
981
|
+
if isinstance(left_val, str) and left_val.startswith("score ") and isinstance(right_val, str) and right_val.startswith("score "):
|
982
|
+
lparts = left_val.split()
|
983
|
+
rparts = right_val.split()
|
984
|
+
if len(lparts) >= 3 and len(rparts) >= 3:
|
985
|
+
lscope, lobj = lparts[1], lparts[2]
|
986
|
+
rscope, robj = rparts[1], rparts[2]
|
987
|
+
if op_sym == "!=":
|
988
|
+
return (f"score {lscope} {lobj} = {rscope} {robj}", True)
|
989
|
+
comp = op_sym if op_sym != "==" else "="
|
990
|
+
return (f"score {lscope} {lobj} {comp} {rscope} {robj}", False)
|
948
991
|
|
949
992
|
# Fallback: treat as generic condition string
|
950
993
|
return (self._expression_to_condition(expression), False)
|
994
|
+
|
995
|
+
def _compile_boolean_expression(self, expression: Any, out_var: Optional[str] = None) -> str:
|
996
|
+
"""Compile a logical expression into a temporary boolean scoreboard variable (1 true, 0 false).
|
997
|
+
Returns the objective name for the boolean temp variable.
|
998
|
+
"""
|
999
|
+
from .ast_nodes import BinaryExpression as Bin, UnaryExpression as Un, ParenthesizedExpression as Par
|
1000
|
+
if out_var is None:
|
1001
|
+
out_var = self._generate_temp_variable_name()
|
1002
|
+
# Ensure initialized to 0
|
1003
|
+
self._store_temp_command(f"scoreboard players set @s {out_var} 0")
|
1004
|
+
|
1005
|
+
def emit_set_true_when(cond_expr: Any):
|
1006
|
+
cond_str, inv = self._build_condition(cond_expr)
|
1007
|
+
prefix = "unless" if inv else "if"
|
1008
|
+
self._store_temp_command(f"execute {prefix} {cond_str} run scoreboard players set @s {out_var} 1")
|
1009
|
+
|
1010
|
+
expr = expression
|
1011
|
+
# Parentheses
|
1012
|
+
if isinstance(expr, Par):
|
1013
|
+
return self._compile_boolean_expression(expr.expression, out_var)
|
1014
|
+
# Unary NOT
|
1015
|
+
if isinstance(expr, Un):
|
1016
|
+
op = self._normalize_operator(expr.operator)
|
1017
|
+
if op == '!':
|
1018
|
+
inner_var = self._compile_boolean_expression(expr.operand)
|
1019
|
+
# out = NOT inner
|
1020
|
+
self._store_temp_command(f"execute unless score @s {inner_var} matches 1.. run scoreboard players set @s {out_var} 1")
|
1021
|
+
return out_var
|
1022
|
+
# Binary logical
|
1023
|
+
if isinstance(expr, Bin):
|
1024
|
+
op = self._normalize_operator(expr.operator)
|
1025
|
+
if op == '&&':
|
1026
|
+
left_var = self._compile_boolean_expression(expr.left)
|
1027
|
+
right_var = self._compile_boolean_expression(expr.right)
|
1028
|
+
# Set true only when both true
|
1029
|
+
self._store_temp_command(f"execute if score @s {left_var} matches 1.. if score @s {right_var} matches 1.. run scoreboard players set @s {out_var} 1")
|
1030
|
+
return out_var
|
1031
|
+
if op == '||':
|
1032
|
+
left_var = self._compile_boolean_expression(expr.left)
|
1033
|
+
right_var = self._compile_boolean_expression(expr.right)
|
1034
|
+
# Set true when either true
|
1035
|
+
self._store_temp_command(f"execute if score @s {left_var} matches 1.. run scoreboard players set @s {out_var} 1")
|
1036
|
+
self._store_temp_command(f"execute if score @s {right_var} matches 1.. run scoreboard players set @s {out_var} 1")
|
1037
|
+
return out_var
|
1038
|
+
# Base comparator or non-logical: set true if base condition holds
|
1039
|
+
emit_set_true_when(expr)
|
1040
|
+
return out_var
|
951
1041
|
|
952
1042
|
def _compile_expression_to_temp(self, expression: BinaryExpression, temp_var: str):
|
953
1043
|
"""Compile a complex expression to a temporary variable using valid Minecraft commands."""
|
@@ -59,6 +59,9 @@ class TokenType:
|
|
59
59
|
LESS = "LESS" # <
|
60
60
|
GREATER_EQUAL = "GREATER_EQUAL" # >=
|
61
61
|
LESS_EQUAL = "LESS_EQUAL" # <=
|
62
|
+
AND = "AND" # &&
|
63
|
+
OR = "OR" # ||
|
64
|
+
NOT = "NOT" # ! (logical not)
|
62
65
|
|
63
66
|
# Delimiters
|
64
67
|
SEMICOLON = "SEMICOLON" # ;
|
@@ -552,7 +555,7 @@ class MDLLexer:
|
|
552
555
|
if self.current + 1 < len(self.source):
|
553
556
|
two_char = self.source[self.current:self.current + 2]
|
554
557
|
|
555
|
-
if two_char in ['==', '!=', '>=', '<=', '..']:
|
558
|
+
if two_char in ['==', '!=', '>=', '<=', '..', '&&', '||']:
|
556
559
|
self.current += 2
|
557
560
|
self.column += 2
|
558
561
|
|
@@ -561,7 +564,9 @@ class MDLLexer:
|
|
561
564
|
'!=': TokenType.NOT_EQUAL,
|
562
565
|
'>=': TokenType.GREATER_EQUAL,
|
563
566
|
'<=': TokenType.LESS_EQUAL,
|
564
|
-
'..': TokenType.RANGE
|
567
|
+
'..': TokenType.RANGE,
|
568
|
+
'&&': TokenType.AND,
|
569
|
+
'||': TokenType.OR
|
565
570
|
}[two_char]
|
566
571
|
|
567
572
|
self.tokens.append(Token(token_type, two_char, self.line, self.column - 2))
|
@@ -576,6 +581,7 @@ class MDLLexer:
|
|
576
581
|
'=': TokenType.ASSIGN,
|
577
582
|
'>': TokenType.GREATER,
|
578
583
|
'<': TokenType.LESS,
|
584
|
+
'!': TokenType.NOT,
|
579
585
|
';': TokenType.SEMICOLON,
|
580
586
|
',': TokenType.COMMA,
|
581
587
|
':': TokenType.COLON,
|
@@ -465,7 +465,27 @@ class MDLParser:
|
|
465
465
|
|
466
466
|
def _parse_expression(self) -> Any:
|
467
467
|
"""Parse an expression with operator precedence."""
|
468
|
-
return self.
|
468
|
+
return self._parse_or()
|
469
|
+
|
470
|
+
def _parse_or(self) -> Any:
|
471
|
+
"""Parse logical OR (||) with left associativity."""
|
472
|
+
expr = self._parse_and()
|
473
|
+
while not self._is_at_end() and self._peek().type == TokenType.OR:
|
474
|
+
operator = self._peek().type
|
475
|
+
self._advance()
|
476
|
+
right = self._parse_and()
|
477
|
+
expr = BinaryExpression(left=expr, operator=operator, right=right)
|
478
|
+
return expr
|
479
|
+
|
480
|
+
def _parse_and(self) -> Any:
|
481
|
+
"""Parse logical AND (&&) with left associativity."""
|
482
|
+
expr = self._parse_comparison()
|
483
|
+
while not self._is_at_end() and self._peek().type == TokenType.AND:
|
484
|
+
operator = self._peek().type
|
485
|
+
self._advance()
|
486
|
+
right = self._parse_comparison()
|
487
|
+
expr = BinaryExpression(left=expr, operator=operator, right=right)
|
488
|
+
return expr
|
469
489
|
|
470
490
|
def _parse_comparison(self) -> Any:
|
471
491
|
"""Parse comparison expressions (>, <, >=, <=, ==, !=)."""
|
@@ -496,15 +516,24 @@ class MDLParser:
|
|
496
516
|
|
497
517
|
def _parse_factor(self) -> Any:
|
498
518
|
"""Parse multiplication and division factors."""
|
499
|
-
expr = self.
|
519
|
+
expr = self._parse_unary()
|
500
520
|
|
501
521
|
while not self._is_at_end() and self._peek().type in [TokenType.MULTIPLY, TokenType.DIVIDE]:
|
502
522
|
operator = self._peek().type
|
503
523
|
self._advance()
|
504
|
-
right = self.
|
524
|
+
right = self._parse_unary()
|
505
525
|
expr = BinaryExpression(left=expr, operator=operator, right=right)
|
506
526
|
|
507
527
|
return expr
|
528
|
+
|
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]:
|
532
|
+
operator = self._peek().type
|
533
|
+
self._advance()
|
534
|
+
operand = self._parse_unary()
|
535
|
+
return UnaryExpression(operator=operator, operand=operand)
|
536
|
+
return self._parse_primary()
|
508
537
|
|
509
538
|
def _parse_primary(self) -> Any:
|
510
539
|
"""Parse primary expressions (literals, variables, parenthesized expressions)."""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: minecraft-datapack-language
|
3
|
-
Version: 16.0.
|
3
|
+
Version: 16.0.17
|
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=4SuxrqtqwWUwpm2T-Y1T6GX-kvyCaEpo8lvFEXiyIJM,708
|
3
3
|
minecraft_datapack_language/ast_nodes.py,sha256=L5izavSeXDr766vsfRvJrcnflXNJyXcy0WSfyJPq2ZA,4484
|
4
4
|
minecraft_datapack_language/cli.py,sha256=R4QZYtox-Da9B8pr_kCg_9qc9aI-ORTah7kMkhsI5tw,10373
|
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=L1ECOpZUuVe5j_qAn6KdAQwa6BWB8Bk9vId5lUPKaHo,59374
|
7
7
|
minecraft_datapack_language/mdl_errors.py,sha256=r0Gu3KhoX1YLPAVW_iO7Q_fPgaf_Dv9tOGSOdKNSzmw,16114
|
8
|
-
minecraft_datapack_language/mdl_lexer.py,sha256=
|
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=Bwfk1i6PFsMB3Zs7Z6a3fgngPaWPv-KKqQRQUkFRquM,27272
|
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.17.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
14
|
+
minecraft_datapack_language-16.0.17.dist-info/METADATA,sha256=uvJtPRYl3ouhthLXW0TqePW6pg0NveScitUYds1Powo,8344
|
15
|
+
minecraft_datapack_language-16.0.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
minecraft_datapack_language-16.0.17.dist-info/entry_points.txt,sha256=c6vjBeCiyQflvPHBRyBk2nJCSfYt3Oc7Sc9V87ySi_U,108
|
17
|
+
minecraft_datapack_language-16.0.17.dist-info/top_level.txt,sha256=ADtFI476tbKLLxEAA-aJQAfg53MA3k_DOb0KTFiggfw,28
|
18
|
+
minecraft_datapack_language-16.0.17.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|