diff --git a/Cargo.toml b/Cargo.toml index a243bd4..4275e2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,12 +30,12 @@ derive_more = { version = "2.0.1", default-features = false, features = [ "deref enum-as-inner = "0.6.0" getset = "0.1.2" itertools = "0.14.0" -mlua = { version = "0.10.2", features = ["lua54", "vendored"], optional = true } +mlua = { version = "0.11.3", features = ["lua54", "vendored"], optional = true } pathdiff = "0.2.3" serde = { version = "1.0.217", features = ["derive"], optional = true } serde_json = { version = "1.0.138", optional = true } # shulkerbox = { version = "0.1.0", default-features = false, optional = true } -shulkerbox = { git = "https://github.com/moritz-hoelting/shulkerbox", rev = "89709834da6f39840caa9c6a2eadbdececdc7d44", default-features = false, optional = true } +shulkerbox = { git = "https://github.com/moritz-hoelting/shulkerbox", rev = "d4689c696a35328c041bcbbfd203abd5818c46d3", default-features = false, optional = true } strsim = "0.11.1" strum = { version = "0.27.0", features = ["derive"] } thiserror = "2.0.11" diff --git a/src/syntax/syntax_tree/expression.rs b/src/syntax/syntax_tree/expression.rs index af4c7fa..be0d1ee 100644 --- a/src/syntax/syntax_tree/expression.rs +++ b/src/syntax/syntax_tree/expression.rs @@ -984,8 +984,11 @@ impl Parser<'_> { &mut self, handler: &impl Handler, ) -> ParseResult { - match self.next_significant_token() { - Reading::Atomic(Token::StringLiteral(literal)) => Ok(literal.into()), + match self.stop_at_significant() { + Reading::Atomic(Token::StringLiteral(literal)) => { + self.forward(); + Ok(literal.into()) + } Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == '`' => self .parse_template_string_literal(handler) .map(AnyStringLiteral::TemplateStringLiteral), diff --git a/src/syntax/syntax_tree/statement/execute_block.rs b/src/syntax/syntax_tree/statement/execute_block.rs index d5cf981..fd14f9a 100644 --- a/src/syntax/syntax_tree/statement/execute_block.rs +++ b/src/syntax/syntax_tree/statement/execute_block.rs @@ -812,7 +812,7 @@ impl Parser<'_> { } Reading::Atomic(Token::Keyword(keyword)) if keyword.keyword.starts_execute_block() => { - // eat the as keyword + // eat the keyword self.forward(); let argument = match self.stop_at_significant() { diff --git a/src/transpile/conversions.rs b/src/transpile/conversions.rs index 3eb01e6..a912149 100644 --- a/src/transpile/conversions.rs +++ b/src/transpile/conversions.rs @@ -17,7 +17,7 @@ use crate::{ use super::util::{MacroString, MacroStringPart}; -type ShulkerboxMacroStringMap = BTreeMap, Span)>; +pub(crate) type ShulkerboxMacroStringMap = BTreeMap, Span)>; impl MacroString { pub fn into_sb(self) -> (ExtMacroString, ShulkerboxMacroStringMap) { diff --git a/src/transpile/expression.rs b/src/transpile/expression.rs index e6c69ea..04afc2d 100644 --- a/src/transpile/expression.rs +++ b/src/transpile/expression.rs @@ -2,6 +2,9 @@ use std::fmt::Display; +#[cfg(feature = "shulkerbox")] +use std::collections::BTreeMap; + #[cfg(feature = "shulkerbox")] use enum_as_inner::EnumAsInner; @@ -25,6 +28,7 @@ use crate::{ Primary, }, transpile::{ + conversions::ShulkerboxMacroStringMap, error::{FunctionArgumentsNotAllowed, MissingValue}, variables::FunctionVariableDataType, TranspileError, @@ -217,10 +221,9 @@ impl StorageType { pub fn suffix(&self) -> &'static str { match self { Self::Boolean | Self::Byte => "b", - Self::Int => "", + Self::Int | Self::String => "", Self::Long => "l", Self::Double => "d", - Self::String => "", } } @@ -1291,14 +1294,14 @@ impl Transpiler { .. } | DataLocation::Tag { .. } ) { - let (mut cmds, cond) = + let (mut cmds, prepare_variables, cond) = self.transpile_primary_expression_as_condition(primary, scope, handler)?; let store_cmds = self.store_condition_success(cond, target, primary, handler)?; cmds.extend(store_cmds); - Ok(cmds) + self.transpile_commands_with_variable_macros(cmds, prepare_variables, handler) } else { let err = TranspileError::MismatchedTypes(MismatchedTypes { expected_type: target.value_type().into(), @@ -1375,14 +1378,14 @@ impl Transpiler { } }, PrefixOperator::LogicalNot(_) => { - let (mut cmds, cond) = + let (mut cmds, prepare_variables, cond) = self.transpile_primary_expression_as_condition(primary, scope, handler)?; let store_cmds = self.store_condition_success(cond, target, primary, handler)?; cmds.extend(store_cmds); - Ok(cmds) + self.transpile_commands_with_variable_macros(cmds, prepare_variables, handler) } PrefixOperator::Run(_) => { let run_cmds = @@ -1646,13 +1649,13 @@ impl Transpiler { | BinaryOperator::NotEqual(..) | BinaryOperator::LogicalAnd(..) | BinaryOperator::LogicalOr(..) => { - let (mut cmds, cond) = + let (mut cmds, prepare_variables, cond) = self.transpile_binary_expression_as_condition(binary, scope, handler)?; let store_cmds = self.store_condition_success(cond, target, binary, handler)?; cmds.extend(store_cmds); - Ok(cmds) + self.transpile_commands_with_variable_macros(cmds, prepare_variables, handler) } } } @@ -1663,7 +1666,7 @@ impl Transpiler { expression: &Expression, scope: &Arc, handler: &impl Handler, - ) -> TranspileResult<(Vec, ExtendedCondition)> { + ) -> TranspileResult<(Vec, ShulkerboxMacroStringMap, ExtendedCondition)> { match expression { Expression::Primary(primary) => { self.transpile_primary_expression_as_condition(primary, scope, handler) @@ -1680,11 +1683,15 @@ impl Transpiler { primary: &Primary, scope: &Arc, handler: &impl Handler, - ) -> TranspileResult<(Vec, ExtendedCondition)> { + ) -> TranspileResult<(Vec, ShulkerboxMacroStringMap, ExtendedCondition)> { + use std::collections::BTreeMap; + match primary { - Primary::Boolean(boolean) => { - Ok((Vec::new(), ExtendedCondition::Comptime(boolean.value()))) - } + Primary::Boolean(boolean) => Ok(( + Vec::new(), + BTreeMap::new(), + ExtendedCondition::Comptime(boolean.value()), + )), Primary::Integer(_) => { let err = TranspileError::MismatchedTypes(MismatchedTypes { expected_type: ExpectedType::Boolean, @@ -1695,6 +1702,7 @@ impl Transpiler { } Primary::StringLiteral(s) => Ok(( Vec::new(), + BTreeMap::new(), ExtendedCondition::Runtime(Condition::Atom(s.str_content().to_string().into())), )), Primary::TemplateStringLiteral(template_string) => { @@ -1703,6 +1711,7 @@ impl Transpiler { .into_sb(); Ok(( Vec::new(), + prepare_variables, ExtendedCondition::Runtime(Condition::Atom(macro_string)), )) } @@ -1730,6 +1739,7 @@ impl Transpiler { Ok(( Vec::new(), + BTreeMap::new(), ExtendedCondition::Runtime(Condition::Atom( format!("function {func_location}").into(), )), @@ -1742,12 +1752,14 @@ impl Transpiler { match variable { VariableData::BooleanStorage { storage_name, path } => Ok(( Vec::new(), + BTreeMap::new(), ExtendedCondition::Runtime(Condition::Atom( format!("data storage {storage_name} {{{path}: 1b}}").into(), )), )), VariableData::MacroParameter { macro_name, .. } => Ok(( Vec::new(), + BTreeMap::new(), ExtendedCondition::Runtime(Condition::Atom( shulkerbox::util::MacroString::MacroString(vec![ shulkerbox::util::MacroStringPart::MacroUsage( @@ -1806,6 +1818,7 @@ impl Transpiler { { Ok(( Vec::new(), + BTreeMap::new(), ExtendedCondition::Runtime(Condition::Atom( format!("data storage {storage_name} {{{path}: 1b}}") .into(), @@ -1869,7 +1882,7 @@ impl Transpiler { }, |value| match value { ComptimeValue::Boolean(b) => { - Ok((Vec::new(), ExtendedCondition::Comptime(b))) + Ok((Vec::new(), BTreeMap::new(), ExtendedCondition::Comptime(b))) } ComptimeValue::Integer(_) => { let err = TranspileError::MismatchedTypes(MismatchedTypes { @@ -1881,6 +1894,7 @@ impl Transpiler { } ComptimeValue::String(s) => Ok(( Vec::new(), + BTreeMap::new(), ExtendedCondition::Runtime(Condition::Atom( shulkerbox::util::MacroString::String(s), )), @@ -1889,6 +1903,7 @@ impl Transpiler { let (macro_string, prepare_variables) = s.into_sb(); Ok(( Vec::new(), + prepare_variables, ExtendedCondition::Runtime(Condition::Atom(macro_string)), )) } @@ -1896,13 +1911,15 @@ impl Transpiler { ), Primary::Prefix(prefix) => match prefix.operator() { PrefixOperator::LogicalNot(_) => { - let (cmds, cond) = self.transpile_primary_expression_as_condition( - prefix.operand(), - scope, - handler, - )?; + let (cmds, prepare_variables, cond) = self + .transpile_primary_expression_as_condition( + prefix.operand(), + scope, + handler, + )?; Ok(( cmds, + prepare_variables, match cond { ExtendedCondition::Runtime(cond) => { ExtendedCondition::Runtime(Condition::Not(Box::new(cond))) @@ -1928,7 +1945,7 @@ impl Transpiler { scope, handler, )?; - Ok((store_cmds, cond)) + Ok((store_cmds, BTreeMap::new(), cond)) } PrefixOperator::Negate(_) => { let err = TranspileError::MismatchedTypes(MismatchedTypes { @@ -1942,18 +1959,22 @@ impl Transpiler { Primary::Lua(lua) => match lua.eval_comptime(scope, handler)? { Ok(ComptimeValue::String(value)) => Ok(( Vec::new(), + BTreeMap::new(), ExtendedCondition::Runtime(Condition::Atom(value.into())), )), Ok(ComptimeValue::MacroString(value)) => { let (macro_string, prepare_variables) = value.into_sb(); Ok(( Vec::new(), + prepare_variables, ExtendedCondition::Runtime(Condition::Atom(macro_string)), )) } - Ok(ComptimeValue::Boolean(boolean)) => { - Ok((Vec::new(), ExtendedCondition::Comptime(boolean))) - } + Ok(ComptimeValue::Boolean(boolean)) => Ok(( + Vec::new(), + BTreeMap::new(), + ExtendedCondition::Comptime(boolean), + )), _ => { let err = TranspileError::MismatchedTypes(MismatchedTypes { expected_type: ExpectedType::Boolean, @@ -1971,7 +1992,7 @@ impl Transpiler { binary: &Binary, scope: &Arc, handler: &impl Handler, - ) -> TranspileResult<(Vec, ExtendedCondition)> { + ) -> TranspileResult<(Vec, ShulkerboxMacroStringMap, ExtendedCondition)> { match binary.operator() { BinaryOperator::Equal(..) | BinaryOperator::NotEqual(..) @@ -1980,7 +2001,9 @@ impl Transpiler { | BinaryOperator::LessThan(_) | BinaryOperator::LessThanOrEqual(..) => self .transpile_comparison_operator(binary, scope, handler) - .map(|(cmds, cond)| (cmds, ExtendedCondition::Runtime(cond))), + .map(|(cmds, prepare_variables, cond)| { + (cmds, prepare_variables, ExtendedCondition::Runtime(cond)) + }), BinaryOperator::LogicalAnd(..) | BinaryOperator::LogicalOr(..) => { self.transpile_logic_operator(binary, scope, handler) } @@ -2132,7 +2155,7 @@ impl Transpiler { binary: &Binary, scope: &Arc, handler: &impl Handler, - ) -> TranspileResult<(Vec, Condition)> { + ) -> TranspileResult<(Vec, ShulkerboxMacroStringMap, Condition)> { let invert = matches!(binary.operator(), BinaryOperator::NotEqual(..)); // TODO: evaluate comptime values and compare using `matches` and integer ranges @@ -2177,6 +2200,7 @@ impl Transpiler { Ok(( left_cmds.into_iter().chain(right_cmds).collect(), + BTreeMap::new(), if invert { Condition::Not(Box::new(condition)) } else { @@ -2190,38 +2214,45 @@ impl Transpiler { binary: &Binary, scope: &Arc, handler: &impl Handler, - ) -> TranspileResult<(Vec, ExtendedCondition)> { + ) -> TranspileResult<(Vec, ShulkerboxMacroStringMap, ExtendedCondition)> { let left = binary.left_operand().as_ref(); let right = binary.right_operand().as_ref(); - let (left_cmds, left_cond) = + let (left_cmds, mut left_prep_variables, left_cond) = self.transpile_expression_as_condition(left, scope, handler)?; - let (right_cmds, right_cond) = + let (right_cmds, right_prep_variables, right_cond) = self.transpile_expression_as_condition(right, scope, handler)?; + left_prep_variables.extend(right_prep_variables); + let prep_variables = left_prep_variables; match (binary.operator(), left_cond, right_cond) { (BinaryOperator::LogicalAnd(..), ExtendedCondition::Comptime(true), other) | (BinaryOperator::LogicalOr(..), ExtendedCondition::Comptime(false), other) => { - Ok((right_cmds, other)) + Ok((right_cmds, prep_variables, other)) } (BinaryOperator::LogicalAnd(..), other, ExtendedCondition::Comptime(true)) | (BinaryOperator::LogicalOr(..), other, ExtendedCondition::Comptime(false)) => { - Ok((left_cmds, other)) + Ok((left_cmds, prep_variables, other)) } (BinaryOperator::LogicalAnd(..), ExtendedCondition::Comptime(false), _) - | (BinaryOperator::LogicalAnd(..), _, ExtendedCondition::Comptime(false)) => { - Ok((Vec::new(), ExtendedCondition::Comptime(false))) - } + | (BinaryOperator::LogicalAnd(..), _, ExtendedCondition::Comptime(false)) => Ok(( + Vec::new(), + BTreeMap::new(), + ExtendedCondition::Comptime(false), + )), (BinaryOperator::LogicalOr(..), ExtendedCondition::Comptime(true), _) - | (BinaryOperator::LogicalOr(..), _, ExtendedCondition::Comptime(true)) => { - Ok((Vec::new(), ExtendedCondition::Comptime(true))) - } + | (BinaryOperator::LogicalOr(..), _, ExtendedCondition::Comptime(true)) => Ok(( + Vec::new(), + BTreeMap::new(), + ExtendedCondition::Comptime(true), + )), ( BinaryOperator::LogicalAnd(..), ExtendedCondition::Runtime(left_cond), ExtendedCondition::Runtime(right_cond), ) => Ok(( left_cmds.into_iter().chain(right_cmds).collect(), + prep_variables, ExtendedCondition::Runtime(Condition::And( Box::new(left_cond), Box::new(right_cond), @@ -2233,6 +2264,7 @@ impl Transpiler { ExtendedCondition::Runtime(right_cond), ) => Ok(( left_cmds.into_iter().chain(right_cmds).collect(), + prep_variables, ExtendedCondition::Runtime(Condition::Or( Box::new(left_cond), Box::new(right_cond), @@ -2335,11 +2367,17 @@ impl Transpiler { } | DataLocation::Tag { .. } => { let (macro_string, prepare_variables) = value.clone().into_sb(); - self.store_condition_success( + let cmds = self.store_condition_success( ExtendedCondition::Runtime(Condition::Atom(macro_string)), target, source, handler, + )?; + + self.transpile_commands_with_variable_macros( + cmds, + prepare_variables, + handler, ) } // DataLocation::Storage { storage_name, path, r#type: StorageType::String } => todo!("implement storage string") diff --git a/src/transpile/function.rs b/src/transpile/function.rs index 02e92cf..b2422b5 100644 --- a/src/transpile/function.rs +++ b/src/transpile/function.rs @@ -682,8 +682,8 @@ impl Transpiler { return Err(err); } } - Err((parts, preparation_variables)) => { - let (macro_string, preparation_variables) = MacroString::MacroString { + Err((parts, prepare_variables)) => { + let (macro_string, prepare_variables) = MacroString::MacroString { parts: std::iter::once(MacroStringPart::String( format!( "scoreboard players set {target} {objective} " @@ -691,10 +691,16 @@ impl Transpiler { )) .chain(parts.iter().cloned()) .collect(), - prepare_variables: preparation_variables.to_owned(), + prepare_variables: prepare_variables.to_owned(), } .into_sb(); - move_cmds.push(Command::UsesMacro(macro_string)); + let cmds = self + .transpile_commands_with_variable_macros( + vec![Command::UsesMacro(macro_string)], + prepare_variables, + handler, + )?; + move_cmds.extend(cmds); } }, Parameter::Storage { @@ -742,15 +748,21 @@ impl Transpiler { return Err(err); } } - Err((parts, preparation_cmds)) => { - let (macro_string, preparation_variables) = MacroString::MacroString { + Err((parts, prepare_cmds)) => { + let (macro_string, prepare_variables) = MacroString::MacroString { parts: std::iter::once(MacroStringPart::String(format!("data modify storage {target_storage_name} {target_path} set value "))) .chain(parts.iter().cloned()) .collect(), - prepare_variables: preparation_cmds.to_owned(), + prepare_variables: prepare_cmds.to_owned(), } .into_sb(); - move_cmds.push(Command::UsesMacro(macro_string)); + let cmds = self + .transpile_commands_with_variable_macros( + vec![Command::UsesMacro(macro_string)], + prepare_variables, + handler, + )?; + move_cmds.extend(cmds); } }, Parameter::Storage { @@ -808,10 +820,10 @@ impl Transpiler { }), ); let storage_suffix = function_location.replace(['/', ':'], "_"); - let statics_cmd = match joined_statics { - MacroString::String(s) => Command::Raw(format!( + let statics_cmds = match joined_statics { + MacroString::String(s) => vec![Command::Raw(format!( r"data merge storage shulkerscript:function_arguments_{storage_suffix} {{{s}}}" - )), + ))], MacroString::MacroString { .. } => { let prefix = MacroString::String(format!( "data merge storage shulkerscript:function_arguments_{storage_suffix} {{" @@ -823,10 +835,14 @@ impl Transpiler { MacroString::String("}".to_string()), ]) .into_sb(); - Command::UsesMacro(macro_string) + self.transpile_commands_with_variable_macros( + vec![Command::UsesMacro(macro_string)], + prepare_variables, + handler, + )? } }; - setup_cmds.push(statics_cmd); + setup_cmds.extend(statics_cmds); setup_cmds.extend(move_cmds); Ok(TranspiledFunctionArguments::Dynamic(setup_cmds)) diff --git a/src/transpile/internal_functions.rs b/src/transpile/internal_functions.rs index d107c36..66a7947 100644 --- a/src/transpile/internal_functions.rs +++ b/src/transpile/internal_functions.rs @@ -589,8 +589,7 @@ fn print_function( let cmd = format!("tellraw {target} {print_args}"); let cmd = if contains_macro { - let (macro_string, prepare_variables) = - cmd.parse::().expect("cannot fail").into_sb(); + let (macro_string, _) = cmd.parse::().expect("cannot fail").into_sb(); Command::UsesMacro(macro_string) } else { Command::Raw(cmd) diff --git a/src/transpile/transpiler.rs b/src/transpile/transpiler.rs index 19d2ab7..af1f51a 100644 --- a/src/transpile/transpiler.rs +++ b/src/transpile/transpiler.rs @@ -27,6 +27,7 @@ use crate::{ AnnotationAssignment, }, transpile::{ + conversions::ShulkerboxMacroStringMap, error::IllegalAnnotationContent, expression::DataLocation, util::{MacroString, MacroStringPart}, @@ -471,9 +472,18 @@ impl Transpiler { .comptime_eval(scope, handler) .map(|val| val.to_macro_string()); - let (prepare_cmds, ret_cmd) = if let Ok(val) = comptime_val { + let (prepare_cmds, ret_cmds) = if let Ok(val) = comptime_val { let (macro_string, prepare_variables) = val.into_sb(); - (Vec::new(), datapack::ReturnCommand::Value(macro_string)) + + let cmds = self.transpile_commands_with_variable_macros( + vec![Command::Return(datapack::ReturnCommand::Value( + macro_string, + ))], + prepare_variables, + handler, + )?; + + (Vec::new(), cmds) } else { match ret.expression() { Expression::Primary(Primary::Prefix(prefix)) @@ -481,12 +491,25 @@ impl Transpiler { { let ret_cmds = self.transpile_run_expression(prefix.operand(), scope, handler)?; - let cmd = if ret_cmds.len() == 1 { - ret_cmds.into_iter().next().unwrap() - } else { - Command::Group(Group::new(ret_cmds)) + + let cmd = match ret_cmds.last() { + _ if ret_cmds.len() == 1 => ret_cmds.into_iter().next().unwrap(), + Some(Command::Group(group)) if group.block_pass_macros().is_some() => { + let block_macros = + group.block_pass_macros().expect("checked above").clone(); + Command::Group( + Group::new(ret_cmds).with_block_pass_macros(block_macros), + ) + } + _ => Command::Group(Group::new(ret_cmds)), }; - (Vec::new(), datapack::ReturnCommand::Command(Box::new(cmd))) + + ( + Vec::new(), + vec![Command::Return(datapack::ReturnCommand::Command(Box::new( + cmd, + )))], + ) } Expression::Primary(Primary::FunctionCall(func)) => { let ret_cmds = self.transpile_function_call(func, scope, handler)?; @@ -495,16 +518,21 @@ impl Transpiler { } else { Command::Group(Group::new(ret_cmds)) }; - (Vec::new(), datapack::ReturnCommand::Command(Box::new(cmd))) + ( + Vec::new(), + vec![Command::Return(datapack::ReturnCommand::Command(Box::new( + cmd, + )))], + ) } Expression::Primary(Primary::Identifier(ident)) => { if let Some(var) = scope.get_variable(ident.span.str()) { match var.as_ref() { VariableData::BooleanStorage { storage_name, path } => ( Vec::new(), - datapack::ReturnCommand::Command(Box::new(Command::Raw(format!( - "data get storage {storage_name} {path}" - )))), + vec![Command::Return(datapack::ReturnCommand::Command(Box::new( + Command::Raw(format!("data get storage {storage_name} {path}")), + )))], ), VariableData::ComptimeValue { value, @@ -518,18 +546,25 @@ impl Transpiler { Err(err) }, |val| { - let cmd = val.to_string_no_macro().map_or_else( - || { - let (macro_string, prepare_variables) = - val.to_macro_string().into_sb(); - Command::UsesMacro(macro_string) - }, - Command::Raw, - ); - Ok(( - Vec::new(), - datapack::ReturnCommand::Command(Box::new(cmd)), - )) + let cmds = if let Some(s) = val.to_string_no_macro() { + vec![Command::Return(datapack::ReturnCommand::Command( + Box::new(Command::Raw(s)), + ))] + } else { + let (macro_string, prepare_variables) = + val.to_macro_string().into_sb(); + self.transpile_commands_with_variable_macros( + vec![Command::Return( + datapack::ReturnCommand::Command(Box::new( + Command::UsesMacro(macro_string), + )), + )], + prepare_variables, + handler, + )? + }; + + Ok((Vec::new(), cmds)) }, )?, VariableData::MacroParameter { @@ -537,19 +572,21 @@ impl Transpiler { macro_name, } => ( Vec::new(), - datapack::ReturnCommand::Command(Box::new(Command::UsesMacro( - shulkerbox::util::MacroString::MacroString(vec![ - shulkerbox::util::MacroStringPart::MacroUsage( + vec![Command::Return(datapack::ReturnCommand::Command(Box::new( + Command::UsesMacro(shulkerbox::util::MacroString::MacroString( + vec![shulkerbox::util::MacroStringPart::MacroUsage( macro_name.clone(), - ), - ]), - ))), + )], + )), + )))], ), VariableData::ScoreboardValue { objective, target } => ( Vec::new(), - datapack::ReturnCommand::Command(Box::new(Command::Raw(format!( - "scoreboard players get {target} {objective}" - )))), + vec![Command::Return(datapack::ReturnCommand::Command(Box::new( + Command::Raw(format!( + "scoreboard players get {target} {objective}" + )), + )))], ), _ => { let err = TranspileError::UnexpectedExpression( @@ -585,15 +622,12 @@ impl Transpiler { scope, handler, )?; - (cmds, ret_cmd) + (cmds, vec![Command::Return(ret_cmd)]) } } }; - let cmds = prepare_cmds - .into_iter() - .chain(std::iter::once(Command::Return(ret_cmd))) - .collect(); + let cmds = prepare_cmds.into_iter().chain(ret_cmds).collect(); Ok(cmds) } @@ -849,14 +883,15 @@ impl Transpiler { scope: &Arc, handler: &impl Handler, ) -> TranspileResult> { - self.transpile_execute_block_internal(execute, program_identifier, scope, handler) - .map(|ex| { - ex.map(|(mut pre_cmds, exec)| { - pre_cmds.push(exec.into()); - pre_cmds - }) - .unwrap_or_default() - }) + if let Some((mut pre_cmds, prepare_variables, exec)) = + self.transpile_execute_block_internal(execute, program_identifier, scope, handler)? + { + pre_cmds.push(exec.into()); + + self.transpile_commands_with_variable_macros(pre_cmds, prepare_variables, handler) + } else { + Ok(Vec::new()) + } } fn transpile_execute_block_internal( @@ -865,7 +900,7 @@ impl Transpiler { program_identifier: &str, scope: &Arc, handler: &impl Handler, - ) -> TranspileResult, Execute)>> { + ) -> TranspileResult, ShulkerboxMacroStringMap, Execute)>> { match execute { ExecuteBlock::HeadTail(head, tail) => { let tail = match tail { @@ -889,7 +924,7 @@ impl Transpiler { if commands.is_empty() { Ok(None) } else { - Ok(Some((Vec::new(), Execute::Runs(commands)))) + Ok(Some((Vec::new(), BTreeMap::new(), Execute::Runs(commands)))) } } ExecuteBlockTail::ExecuteBlock(_, execute_block) => self @@ -964,7 +999,7 @@ impl Transpiler { program_identifier: &str, scope: &Arc, handler: &impl Handler, - ) -> TranspileResult, Execute)>> { + ) -> TranspileResult, ShulkerboxMacroStringMap, Execute)>> { let cond_expression = cond.condition().expression().as_ref(); let mut errors = Vec::new(); @@ -994,28 +1029,29 @@ impl Transpiler { if let Ok(ComptimeValue::Boolean(value)) = cond_expression.comptime_eval(scope, handler) { if value { - Ok(Some((Vec::new(), then))) + Ok(Some((Vec::new(), BTreeMap::new(), then))) } else { - Ok(el.map(|el| (Vec::new(), el))) + Ok(el.map(|el| (Vec::new(), BTreeMap::new(), el))) } } else { if !errors.is_empty() { return Err(errors.remove(0)); } - let (pre_cond_cmds, cond) = + let (pre_cond_cmds, prepare_variables, cond) = self.transpile_expression_as_condition(cond_expression, scope, handler)?; match cond { ExtendedCondition::Runtime(cond) => Ok(Some(( pre_cond_cmds, + prepare_variables, Execute::If(cond, Box::new(then), el.map(Box::new)), ))), ExtendedCondition::Comptime(cond) => { if cond { - Ok(Some((Vec::new(), then))) + Ok(Some((Vec::new(), prepare_variables, then))) } else { - Ok(el.map(|el| (Vec::new(), el))) + Ok(el.map(|el| (Vec::new(), prepare_variables, el))) } } } @@ -1026,14 +1062,14 @@ impl Transpiler { fn combine_execute_head_tail( &mut self, head: &ExecuteBlockHead, - tail: Option<(Vec, Execute)>, + tail: Option<(Vec, ShulkerboxMacroStringMap, Execute)>, program_identifier: &str, scope: &Arc, handler: &impl Handler, - ) -> TranspileResult, Execute)>> { + ) -> TranspileResult, ShulkerboxMacroStringMap, Execute)>> { Ok(match head { ExecuteBlockHead::Conditional(cond) => { - if let Some((mut pre_cmds, tail)) = tail { + if let Some((mut pre_cmds, prepare_variables, tail)) = tail { self.transpile_conditional( cond, tail, @@ -1042,9 +1078,10 @@ impl Transpiler { scope, handler, )? - .map(|(pre_cond_cmds, cond)| { + .map(|(pre_cond_cmds, mut prep_variables, cond)| { pre_cmds.extend(pre_cond_cmds); - (pre_cmds, cond) + prep_variables.extend(prepare_variables); + (pre_cmds, prep_variables, cond) }) } else { None @@ -1055,22 +1092,41 @@ impl Transpiler { .as_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = selector.into_sb(); - tail.map(|(pre_cmds, tail)| (pre_cmds, Execute::As(macro_string, Box::new(tail)))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::As(macro_string, Box::new(tail)), + ) + }) } ExecuteBlockHead::At(at) => { let selector = at .at_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = selector.into_sb(); - tail.map(|(pre_cmds, tail)| (pre_cmds, Execute::At(macro_string, Box::new(tail)))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::At(macro_string, Box::new(tail)), + ) + }) } ExecuteBlockHead::Align(align) => { let align = align .align_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = align.into_sb(); - tail.map(|(pre_cmds, tail)| { - (pre_cmds, Execute::Align(macro_string, Box::new(tail))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::Align(macro_string, Box::new(tail)), + ) }) } ExecuteBlockHead::Anchored(anchored) => { @@ -1079,8 +1135,13 @@ impl Transpiler { .anchored_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = anchor.into_sb(); - tail.map(|(pre_cmds, tail)| { - (pre_cmds, Execute::Anchored(macro_string, Box::new(tail))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::Anchored(macro_string, Box::new(tail)), + ) }) } ExecuteBlockHead::In(r#in) => { @@ -1088,7 +1149,14 @@ impl Transpiler { .in_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = dimension.into_sb(); - tail.map(|(pre_cmds, tail)| (pre_cmds, Execute::In(macro_string, Box::new(tail)))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::In(macro_string, Box::new(tail)), + ) + }) } ExecuteBlockHead::Positioned(positioned) => { let position = @@ -1096,8 +1164,13 @@ impl Transpiler { .positioned_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = position.into_sb(); - tail.map(|(pre_cmds, tail)| { - (pre_cmds, Execute::Positioned(macro_string, Box::new(tail))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::Positioned(macro_string, Box::new(tail)), + ) }) } ExecuteBlockHead::Rotated(rotated) => { @@ -1106,8 +1179,13 @@ impl Transpiler { .rotated_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = rotation.into_sb(); - tail.map(|(pre_cmds, tail)| { - (pre_cmds, Execute::Rotated(macro_string, Box::new(tail))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::Rotated(macro_string, Box::new(tail)), + ) }) } ExecuteBlockHead::Facing(facing) => { @@ -1116,8 +1194,13 @@ impl Transpiler { .facing_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = facing.into_sb(); - tail.map(|(pre_cmds, tail)| { - (pre_cmds, Execute::Facing(macro_string, Box::new(tail))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::Facing(macro_string, Box::new(tail)), + ) }) } ExecuteBlockHead::AsAt(as_at) => { @@ -1125,22 +1208,41 @@ impl Transpiler { .asat_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = selector.into_sb(); - tail.map(|(pre_cmds, tail)| (pre_cmds, Execute::AsAt(macro_string, Box::new(tail)))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::AsAt(macro_string, Box::new(tail)), + ) + }) } ExecuteBlockHead::On(on) => { let dimension = on .on_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = dimension.into_sb(); - tail.map(|(pre_cmds, tail)| (pre_cmds, Execute::On(macro_string, Box::new(tail)))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::On(macro_string, Box::new(tail)), + ) + }) } ExecuteBlockHead::Store(store) => { let store = store .store_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = store.into_sb(); - tail.map(|(pre_cmds, tail)| { - (pre_cmds, Execute::Store(macro_string, Box::new(tail))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::Store(macro_string, Box::new(tail)), + ) }) } ExecuteBlockHead::Summon(summon) => { @@ -1149,8 +1251,13 @@ impl Transpiler { .summon_selector() .to_macro_string(Some(self), scope, handler)?; let (macro_string, prepare_variables) = entity.into_sb(); - tail.map(|(pre_cmds, tail)| { - (pre_cmds, Execute::Summon(macro_string, Box::new(tail))) + tail.map(|(pre_cmds, mut prep_variables, tail)| { + prep_variables.extend(prepare_variables); + ( + pre_cmds, + prep_variables, + Execute::Summon(macro_string, Box::new(tail)), + ) }) } }) @@ -1197,9 +1304,9 @@ impl Transpiler { } else { prepare_cmds.push(Command::Group( Group::new(cmds) - .always_create_function(true) - .block_pass_macros(macro_names) - .data_storage_name(storage_name), + .with_always_create_function(true) + .with_block_pass_macros(macro_names) + .with_data_storage_name(storage_name), )); Ok(prepare_cmds)