add handling for template strings everywhere

This commit is contained in:
Moritz Hölting 2025-09-02 22:47:37 +02:00
parent 6043a4add5
commit 1b85a2f654
8 changed files with 302 additions and 139 deletions

View File

@ -30,12 +30,12 @@ derive_more = { version = "2.0.1", default-features = false, features = [ "deref
enum-as-inner = "0.6.0" enum-as-inner = "0.6.0"
getset = "0.1.2" getset = "0.1.2"
itertools = "0.14.0" 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" pathdiff = "0.2.3"
serde = { version = "1.0.217", features = ["derive"], optional = true } serde = { version = "1.0.217", features = ["derive"], optional = true }
serde_json = { version = "1.0.138", optional = true } serde_json = { version = "1.0.138", optional = true }
# shulkerbox = { version = "0.1.0", default-features = false, 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" strsim = "0.11.1"
strum = { version = "0.27.0", features = ["derive"] } strum = { version = "0.27.0", features = ["derive"] }
thiserror = "2.0.11" thiserror = "2.0.11"

View File

@ -984,8 +984,11 @@ impl Parser<'_> {
&mut self, &mut self,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> ParseResult<AnyStringLiteral> { ) -> ParseResult<AnyStringLiteral> {
match self.next_significant_token() { match self.stop_at_significant() {
Reading::Atomic(Token::StringLiteral(literal)) => Ok(literal.into()), Reading::Atomic(Token::StringLiteral(literal)) => {
self.forward();
Ok(literal.into())
}
Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == '`' => self Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == '`' => self
.parse_template_string_literal(handler) .parse_template_string_literal(handler)
.map(AnyStringLiteral::TemplateStringLiteral), .map(AnyStringLiteral::TemplateStringLiteral),

View File

@ -812,7 +812,7 @@ impl Parser<'_> {
} }
Reading::Atomic(Token::Keyword(keyword)) if keyword.keyword.starts_execute_block() => { Reading::Atomic(Token::Keyword(keyword)) if keyword.keyword.starts_execute_block() => {
// eat the as keyword // eat the keyword
self.forward(); self.forward();
let argument = match self.stop_at_significant() { let argument = match self.stop_at_significant() {

View File

@ -17,7 +17,7 @@ use crate::{
use super::util::{MacroString, MacroStringPart}; use super::util::{MacroString, MacroStringPart};
type ShulkerboxMacroStringMap = BTreeMap<String, (DataLocation, Vec<Command>, Span)>; pub(crate) type ShulkerboxMacroStringMap = BTreeMap<String, (DataLocation, Vec<Command>, Span)>;
impl MacroString { impl MacroString {
pub fn into_sb(self) -> (ExtMacroString, ShulkerboxMacroStringMap) { pub fn into_sb(self) -> (ExtMacroString, ShulkerboxMacroStringMap) {

View File

@ -2,6 +2,9 @@
use std::fmt::Display; use std::fmt::Display;
#[cfg(feature = "shulkerbox")]
use std::collections::BTreeMap;
#[cfg(feature = "shulkerbox")] #[cfg(feature = "shulkerbox")]
use enum_as_inner::EnumAsInner; use enum_as_inner::EnumAsInner;
@ -25,6 +28,7 @@ use crate::{
Primary, Primary,
}, },
transpile::{ transpile::{
conversions::ShulkerboxMacroStringMap,
error::{FunctionArgumentsNotAllowed, MissingValue}, error::{FunctionArgumentsNotAllowed, MissingValue},
variables::FunctionVariableDataType, variables::FunctionVariableDataType,
TranspileError, TranspileError,
@ -217,10 +221,9 @@ impl StorageType {
pub fn suffix(&self) -> &'static str { pub fn suffix(&self) -> &'static str {
match self { match self {
Self::Boolean | Self::Byte => "b", Self::Boolean | Self::Byte => "b",
Self::Int => "", Self::Int | Self::String => "",
Self::Long => "l", Self::Long => "l",
Self::Double => "d", Self::Double => "d",
Self::String => "",
} }
} }
@ -1291,14 +1294,14 @@ impl Transpiler {
.. ..
} | DataLocation::Tag { .. } } | DataLocation::Tag { .. }
) { ) {
let (mut cmds, cond) = let (mut cmds, prepare_variables, cond) =
self.transpile_primary_expression_as_condition(primary, scope, handler)?; self.transpile_primary_expression_as_condition(primary, scope, handler)?;
let store_cmds = let store_cmds =
self.store_condition_success(cond, target, primary, handler)?; self.store_condition_success(cond, target, primary, handler)?;
cmds.extend(store_cmds); cmds.extend(store_cmds);
Ok(cmds) self.transpile_commands_with_variable_macros(cmds, prepare_variables, handler)
} else { } else {
let err = TranspileError::MismatchedTypes(MismatchedTypes { let err = TranspileError::MismatchedTypes(MismatchedTypes {
expected_type: target.value_type().into(), expected_type: target.value_type().into(),
@ -1375,14 +1378,14 @@ impl Transpiler {
} }
}, },
PrefixOperator::LogicalNot(_) => { PrefixOperator::LogicalNot(_) => {
let (mut cmds, cond) = let (mut cmds, prepare_variables, cond) =
self.transpile_primary_expression_as_condition(primary, scope, handler)?; self.transpile_primary_expression_as_condition(primary, scope, handler)?;
let store_cmds = let store_cmds =
self.store_condition_success(cond, target, primary, handler)?; self.store_condition_success(cond, target, primary, handler)?;
cmds.extend(store_cmds); cmds.extend(store_cmds);
Ok(cmds) self.transpile_commands_with_variable_macros(cmds, prepare_variables, handler)
} }
PrefixOperator::Run(_) => { PrefixOperator::Run(_) => {
let run_cmds = let run_cmds =
@ -1646,13 +1649,13 @@ impl Transpiler {
| BinaryOperator::NotEqual(..) | BinaryOperator::NotEqual(..)
| BinaryOperator::LogicalAnd(..) | BinaryOperator::LogicalAnd(..)
| BinaryOperator::LogicalOr(..) => { | BinaryOperator::LogicalOr(..) => {
let (mut cmds, cond) = let (mut cmds, prepare_variables, cond) =
self.transpile_binary_expression_as_condition(binary, scope, handler)?; self.transpile_binary_expression_as_condition(binary, scope, handler)?;
let store_cmds = self.store_condition_success(cond, target, binary, handler)?; let store_cmds = self.store_condition_success(cond, target, binary, handler)?;
cmds.extend(store_cmds); cmds.extend(store_cmds);
Ok(cmds) self.transpile_commands_with_variable_macros(cmds, prepare_variables, handler)
} }
} }
} }
@ -1663,7 +1666,7 @@ impl Transpiler {
expression: &Expression, expression: &Expression,
scope: &Arc<super::Scope>, scope: &Arc<super::Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<(Vec<Command>, ExtendedCondition)> { ) -> TranspileResult<(Vec<Command>, ShulkerboxMacroStringMap, ExtendedCondition)> {
match expression { match expression {
Expression::Primary(primary) => { Expression::Primary(primary) => {
self.transpile_primary_expression_as_condition(primary, scope, handler) self.transpile_primary_expression_as_condition(primary, scope, handler)
@ -1680,11 +1683,15 @@ impl Transpiler {
primary: &Primary, primary: &Primary,
scope: &Arc<super::Scope>, scope: &Arc<super::Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<(Vec<Command>, ExtendedCondition)> { ) -> TranspileResult<(Vec<Command>, ShulkerboxMacroStringMap, ExtendedCondition)> {
use std::collections::BTreeMap;
match primary { match primary {
Primary::Boolean(boolean) => { Primary::Boolean(boolean) => Ok((
Ok((Vec::new(), ExtendedCondition::Comptime(boolean.value()))) Vec::new(),
} BTreeMap::new(),
ExtendedCondition::Comptime(boolean.value()),
)),
Primary::Integer(_) => { Primary::Integer(_) => {
let err = TranspileError::MismatchedTypes(MismatchedTypes { let err = TranspileError::MismatchedTypes(MismatchedTypes {
expected_type: ExpectedType::Boolean, expected_type: ExpectedType::Boolean,
@ -1695,6 +1702,7 @@ impl Transpiler {
} }
Primary::StringLiteral(s) => Ok(( Primary::StringLiteral(s) => Ok((
Vec::new(), Vec::new(),
BTreeMap::new(),
ExtendedCondition::Runtime(Condition::Atom(s.str_content().to_string().into())), ExtendedCondition::Runtime(Condition::Atom(s.str_content().to_string().into())),
)), )),
Primary::TemplateStringLiteral(template_string) => { Primary::TemplateStringLiteral(template_string) => {
@ -1703,6 +1711,7 @@ impl Transpiler {
.into_sb(); .into_sb();
Ok(( Ok((
Vec::new(), Vec::new(),
prepare_variables,
ExtendedCondition::Runtime(Condition::Atom(macro_string)), ExtendedCondition::Runtime(Condition::Atom(macro_string)),
)) ))
} }
@ -1730,6 +1739,7 @@ impl Transpiler {
Ok(( Ok((
Vec::new(), Vec::new(),
BTreeMap::new(),
ExtendedCondition::Runtime(Condition::Atom( ExtendedCondition::Runtime(Condition::Atom(
format!("function {func_location}").into(), format!("function {func_location}").into(),
)), )),
@ -1742,12 +1752,14 @@ impl Transpiler {
match variable { match variable {
VariableData::BooleanStorage { storage_name, path } => Ok(( VariableData::BooleanStorage { storage_name, path } => Ok((
Vec::new(), Vec::new(),
BTreeMap::new(),
ExtendedCondition::Runtime(Condition::Atom( ExtendedCondition::Runtime(Condition::Atom(
format!("data storage {storage_name} {{{path}: 1b}}").into(), format!("data storage {storage_name} {{{path}: 1b}}").into(),
)), )),
)), )),
VariableData::MacroParameter { macro_name, .. } => Ok(( VariableData::MacroParameter { macro_name, .. } => Ok((
Vec::new(), Vec::new(),
BTreeMap::new(),
ExtendedCondition::Runtime(Condition::Atom( ExtendedCondition::Runtime(Condition::Atom(
shulkerbox::util::MacroString::MacroString(vec![ shulkerbox::util::MacroString::MacroString(vec![
shulkerbox::util::MacroStringPart::MacroUsage( shulkerbox::util::MacroStringPart::MacroUsage(
@ -1806,6 +1818,7 @@ impl Transpiler {
{ {
Ok(( Ok((
Vec::new(), Vec::new(),
BTreeMap::new(),
ExtendedCondition::Runtime(Condition::Atom( ExtendedCondition::Runtime(Condition::Atom(
format!("data storage {storage_name} {{{path}: 1b}}") format!("data storage {storage_name} {{{path}: 1b}}")
.into(), .into(),
@ -1869,7 +1882,7 @@ impl Transpiler {
}, },
|value| match value { |value| match value {
ComptimeValue::Boolean(b) => { ComptimeValue::Boolean(b) => {
Ok((Vec::new(), ExtendedCondition::Comptime(b))) Ok((Vec::new(), BTreeMap::new(), ExtendedCondition::Comptime(b)))
} }
ComptimeValue::Integer(_) => { ComptimeValue::Integer(_) => {
let err = TranspileError::MismatchedTypes(MismatchedTypes { let err = TranspileError::MismatchedTypes(MismatchedTypes {
@ -1881,6 +1894,7 @@ impl Transpiler {
} }
ComptimeValue::String(s) => Ok(( ComptimeValue::String(s) => Ok((
Vec::new(), Vec::new(),
BTreeMap::new(),
ExtendedCondition::Runtime(Condition::Atom( ExtendedCondition::Runtime(Condition::Atom(
shulkerbox::util::MacroString::String(s), shulkerbox::util::MacroString::String(s),
)), )),
@ -1889,6 +1903,7 @@ impl Transpiler {
let (macro_string, prepare_variables) = s.into_sb(); let (macro_string, prepare_variables) = s.into_sb();
Ok(( Ok((
Vec::new(), Vec::new(),
prepare_variables,
ExtendedCondition::Runtime(Condition::Atom(macro_string)), ExtendedCondition::Runtime(Condition::Atom(macro_string)),
)) ))
} }
@ -1896,13 +1911,15 @@ impl Transpiler {
), ),
Primary::Prefix(prefix) => match prefix.operator() { Primary::Prefix(prefix) => match prefix.operator() {
PrefixOperator::LogicalNot(_) => { PrefixOperator::LogicalNot(_) => {
let (cmds, cond) = self.transpile_primary_expression_as_condition( let (cmds, prepare_variables, cond) = self
prefix.operand(), .transpile_primary_expression_as_condition(
scope, prefix.operand(),
handler, scope,
)?; handler,
)?;
Ok(( Ok((
cmds, cmds,
prepare_variables,
match cond { match cond {
ExtendedCondition::Runtime(cond) => { ExtendedCondition::Runtime(cond) => {
ExtendedCondition::Runtime(Condition::Not(Box::new(cond))) ExtendedCondition::Runtime(Condition::Not(Box::new(cond)))
@ -1928,7 +1945,7 @@ impl Transpiler {
scope, scope,
handler, handler,
)?; )?;
Ok((store_cmds, cond)) Ok((store_cmds, BTreeMap::new(), cond))
} }
PrefixOperator::Negate(_) => { PrefixOperator::Negate(_) => {
let err = TranspileError::MismatchedTypes(MismatchedTypes { let err = TranspileError::MismatchedTypes(MismatchedTypes {
@ -1942,18 +1959,22 @@ impl Transpiler {
Primary::Lua(lua) => match lua.eval_comptime(scope, handler)? { Primary::Lua(lua) => match lua.eval_comptime(scope, handler)? {
Ok(ComptimeValue::String(value)) => Ok(( Ok(ComptimeValue::String(value)) => Ok((
Vec::new(), Vec::new(),
BTreeMap::new(),
ExtendedCondition::Runtime(Condition::Atom(value.into())), ExtendedCondition::Runtime(Condition::Atom(value.into())),
)), )),
Ok(ComptimeValue::MacroString(value)) => { Ok(ComptimeValue::MacroString(value)) => {
let (macro_string, prepare_variables) = value.into_sb(); let (macro_string, prepare_variables) = value.into_sb();
Ok(( Ok((
Vec::new(), Vec::new(),
prepare_variables,
ExtendedCondition::Runtime(Condition::Atom(macro_string)), ExtendedCondition::Runtime(Condition::Atom(macro_string)),
)) ))
} }
Ok(ComptimeValue::Boolean(boolean)) => { Ok(ComptimeValue::Boolean(boolean)) => Ok((
Ok((Vec::new(), ExtendedCondition::Comptime(boolean))) Vec::new(),
} BTreeMap::new(),
ExtendedCondition::Comptime(boolean),
)),
_ => { _ => {
let err = TranspileError::MismatchedTypes(MismatchedTypes { let err = TranspileError::MismatchedTypes(MismatchedTypes {
expected_type: ExpectedType::Boolean, expected_type: ExpectedType::Boolean,
@ -1971,7 +1992,7 @@ impl Transpiler {
binary: &Binary, binary: &Binary,
scope: &Arc<super::Scope>, scope: &Arc<super::Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<(Vec<Command>, ExtendedCondition)> { ) -> TranspileResult<(Vec<Command>, ShulkerboxMacroStringMap, ExtendedCondition)> {
match binary.operator() { match binary.operator() {
BinaryOperator::Equal(..) BinaryOperator::Equal(..)
| BinaryOperator::NotEqual(..) | BinaryOperator::NotEqual(..)
@ -1980,7 +2001,9 @@ impl Transpiler {
| BinaryOperator::LessThan(_) | BinaryOperator::LessThan(_)
| BinaryOperator::LessThanOrEqual(..) => self | BinaryOperator::LessThanOrEqual(..) => self
.transpile_comparison_operator(binary, scope, handler) .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(..) => { BinaryOperator::LogicalAnd(..) | BinaryOperator::LogicalOr(..) => {
self.transpile_logic_operator(binary, scope, handler) self.transpile_logic_operator(binary, scope, handler)
} }
@ -2132,7 +2155,7 @@ impl Transpiler {
binary: &Binary, binary: &Binary,
scope: &Arc<super::Scope>, scope: &Arc<super::Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<(Vec<Command>, Condition)> { ) -> TranspileResult<(Vec<Command>, ShulkerboxMacroStringMap, Condition)> {
let invert = matches!(binary.operator(), BinaryOperator::NotEqual(..)); let invert = matches!(binary.operator(), BinaryOperator::NotEqual(..));
// TODO: evaluate comptime values and compare using `matches` and integer ranges // TODO: evaluate comptime values and compare using `matches` and integer ranges
@ -2177,6 +2200,7 @@ impl Transpiler {
Ok(( Ok((
left_cmds.into_iter().chain(right_cmds).collect(), left_cmds.into_iter().chain(right_cmds).collect(),
BTreeMap::new(),
if invert { if invert {
Condition::Not(Box::new(condition)) Condition::Not(Box::new(condition))
} else { } else {
@ -2190,38 +2214,45 @@ impl Transpiler {
binary: &Binary, binary: &Binary,
scope: &Arc<super::Scope>, scope: &Arc<super::Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<(Vec<Command>, ExtendedCondition)> { ) -> TranspileResult<(Vec<Command>, ShulkerboxMacroStringMap, ExtendedCondition)> {
let left = binary.left_operand().as_ref(); let left = binary.left_operand().as_ref();
let right = binary.right_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)?; 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)?; 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) { match (binary.operator(), left_cond, right_cond) {
(BinaryOperator::LogicalAnd(..), ExtendedCondition::Comptime(true), other) (BinaryOperator::LogicalAnd(..), ExtendedCondition::Comptime(true), other)
| (BinaryOperator::LogicalOr(..), ExtendedCondition::Comptime(false), other) => { | (BinaryOperator::LogicalOr(..), ExtendedCondition::Comptime(false), other) => {
Ok((right_cmds, other)) Ok((right_cmds, prep_variables, other))
} }
(BinaryOperator::LogicalAnd(..), other, ExtendedCondition::Comptime(true)) (BinaryOperator::LogicalAnd(..), other, ExtendedCondition::Comptime(true))
| (BinaryOperator::LogicalOr(..), other, ExtendedCondition::Comptime(false)) => { | (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), _)
| (BinaryOperator::LogicalAnd(..), _, ExtendedCondition::Comptime(false)) => { | (BinaryOperator::LogicalAnd(..), _, ExtendedCondition::Comptime(false)) => Ok((
Ok((Vec::new(), ExtendedCondition::Comptime(false))) Vec::new(),
} BTreeMap::new(),
ExtendedCondition::Comptime(false),
)),
(BinaryOperator::LogicalOr(..), ExtendedCondition::Comptime(true), _) (BinaryOperator::LogicalOr(..), ExtendedCondition::Comptime(true), _)
| (BinaryOperator::LogicalOr(..), _, ExtendedCondition::Comptime(true)) => { | (BinaryOperator::LogicalOr(..), _, ExtendedCondition::Comptime(true)) => Ok((
Ok((Vec::new(), ExtendedCondition::Comptime(true))) Vec::new(),
} BTreeMap::new(),
ExtendedCondition::Comptime(true),
)),
( (
BinaryOperator::LogicalAnd(..), BinaryOperator::LogicalAnd(..),
ExtendedCondition::Runtime(left_cond), ExtendedCondition::Runtime(left_cond),
ExtendedCondition::Runtime(right_cond), ExtendedCondition::Runtime(right_cond),
) => Ok(( ) => Ok((
left_cmds.into_iter().chain(right_cmds).collect(), left_cmds.into_iter().chain(right_cmds).collect(),
prep_variables,
ExtendedCondition::Runtime(Condition::And( ExtendedCondition::Runtime(Condition::And(
Box::new(left_cond), Box::new(left_cond),
Box::new(right_cond), Box::new(right_cond),
@ -2233,6 +2264,7 @@ impl Transpiler {
ExtendedCondition::Runtime(right_cond), ExtendedCondition::Runtime(right_cond),
) => Ok(( ) => Ok((
left_cmds.into_iter().chain(right_cmds).collect(), left_cmds.into_iter().chain(right_cmds).collect(),
prep_variables,
ExtendedCondition::Runtime(Condition::Or( ExtendedCondition::Runtime(Condition::Or(
Box::new(left_cond), Box::new(left_cond),
Box::new(right_cond), Box::new(right_cond),
@ -2335,11 +2367,17 @@ impl Transpiler {
} }
| DataLocation::Tag { .. } => { | DataLocation::Tag { .. } => {
let (macro_string, prepare_variables) = value.clone().into_sb(); 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)), ExtendedCondition::Runtime(Condition::Atom(macro_string)),
target, target,
source, source,
handler, handler,
)?;
self.transpile_commands_with_variable_macros(
cmds,
prepare_variables,
handler,
) )
} }
// DataLocation::Storage { storage_name, path, r#type: StorageType::String } => todo!("implement storage string") // DataLocation::Storage { storage_name, path, r#type: StorageType::String } => todo!("implement storage string")

View File

@ -682,8 +682,8 @@ impl Transpiler {
return Err(err); return Err(err);
} }
} }
Err((parts, preparation_variables)) => { Err((parts, prepare_variables)) => {
let (macro_string, preparation_variables) = MacroString::MacroString { let (macro_string, prepare_variables) = MacroString::MacroString {
parts: std::iter::once(MacroStringPart::String( parts: std::iter::once(MacroStringPart::String(
format!( format!(
"scoreboard players set {target} {objective} " "scoreboard players set {target} {objective} "
@ -691,10 +691,16 @@ impl Transpiler {
)) ))
.chain(parts.iter().cloned()) .chain(parts.iter().cloned())
.collect(), .collect(),
prepare_variables: preparation_variables.to_owned(), prepare_variables: prepare_variables.to_owned(),
} }
.into_sb(); .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 { Parameter::Storage {
@ -742,15 +748,21 @@ impl Transpiler {
return Err(err); return Err(err);
} }
} }
Err((parts, preparation_cmds)) => { Err((parts, prepare_cmds)) => {
let (macro_string, preparation_variables) = MacroString::MacroString { let (macro_string, prepare_variables) = MacroString::MacroString {
parts: std::iter::once(MacroStringPart::String(format!("data modify storage {target_storage_name} {target_path} set value "))) parts: std::iter::once(MacroStringPart::String(format!("data modify storage {target_storage_name} {target_path} set value ")))
.chain(parts.iter().cloned()) .chain(parts.iter().cloned())
.collect(), .collect(),
prepare_variables: preparation_cmds.to_owned(), prepare_variables: prepare_cmds.to_owned(),
} }
.into_sb(); .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 { Parameter::Storage {
@ -808,10 +820,10 @@ impl Transpiler {
}), }),
); );
let storage_suffix = function_location.replace(['/', ':'], "_"); let storage_suffix = function_location.replace(['/', ':'], "_");
let statics_cmd = match joined_statics { let statics_cmds = match joined_statics {
MacroString::String(s) => Command::Raw(format!( MacroString::String(s) => vec![Command::Raw(format!(
r"data merge storage shulkerscript:function_arguments_{storage_suffix} {{{s}}}" r"data merge storage shulkerscript:function_arguments_{storage_suffix} {{{s}}}"
)), ))],
MacroString::MacroString { .. } => { MacroString::MacroString { .. } => {
let prefix = MacroString::String(format!( let prefix = MacroString::String(format!(
"data merge storage shulkerscript:function_arguments_{storage_suffix} {{" "data merge storage shulkerscript:function_arguments_{storage_suffix} {{"
@ -823,10 +835,14 @@ impl Transpiler {
MacroString::String("}".to_string()), MacroString::String("}".to_string()),
]) ])
.into_sb(); .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); setup_cmds.extend(move_cmds);
Ok(TranspiledFunctionArguments::Dynamic(setup_cmds)) Ok(TranspiledFunctionArguments::Dynamic(setup_cmds))

View File

@ -589,8 +589,7 @@ fn print_function(
let cmd = format!("tellraw {target} {print_args}"); let cmd = format!("tellraw {target} {print_args}");
let cmd = if contains_macro { let cmd = if contains_macro {
let (macro_string, prepare_variables) = let (macro_string, _) = cmd.parse::<MacroString>().expect("cannot fail").into_sb();
cmd.parse::<MacroString>().expect("cannot fail").into_sb();
Command::UsesMacro(macro_string) Command::UsesMacro(macro_string)
} else { } else {
Command::Raw(cmd) Command::Raw(cmd)

View File

@ -27,6 +27,7 @@ use crate::{
AnnotationAssignment, AnnotationAssignment,
}, },
transpile::{ transpile::{
conversions::ShulkerboxMacroStringMap,
error::IllegalAnnotationContent, error::IllegalAnnotationContent,
expression::DataLocation, expression::DataLocation,
util::{MacroString, MacroStringPart}, util::{MacroString, MacroStringPart},
@ -471,9 +472,18 @@ impl Transpiler {
.comptime_eval(scope, handler) .comptime_eval(scope, handler)
.map(|val| val.to_macro_string()); .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(); 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 { } else {
match ret.expression() { match ret.expression() {
Expression::Primary(Primary::Prefix(prefix)) Expression::Primary(Primary::Prefix(prefix))
@ -481,12 +491,25 @@ impl Transpiler {
{ {
let ret_cmds = let ret_cmds =
self.transpile_run_expression(prefix.operand(), scope, handler)?; self.transpile_run_expression(prefix.operand(), scope, handler)?;
let cmd = if ret_cmds.len() == 1 {
ret_cmds.into_iter().next().unwrap() let cmd = match ret_cmds.last() {
} else { _ if ret_cmds.len() == 1 => ret_cmds.into_iter().next().unwrap(),
Command::Group(Group::new(ret_cmds)) 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)) => { Expression::Primary(Primary::FunctionCall(func)) => {
let ret_cmds = self.transpile_function_call(func, scope, handler)?; let ret_cmds = self.transpile_function_call(func, scope, handler)?;
@ -495,16 +518,21 @@ impl Transpiler {
} else { } else {
Command::Group(Group::new(ret_cmds)) 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)) => { Expression::Primary(Primary::Identifier(ident)) => {
if let Some(var) = scope.get_variable(ident.span.str()) { if let Some(var) = scope.get_variable(ident.span.str()) {
match var.as_ref() { match var.as_ref() {
VariableData::BooleanStorage { storage_name, path } => ( VariableData::BooleanStorage { storage_name, path } => (
Vec::new(), Vec::new(),
datapack::ReturnCommand::Command(Box::new(Command::Raw(format!( vec![Command::Return(datapack::ReturnCommand::Command(Box::new(
"data get storage {storage_name} {path}" Command::Raw(format!("data get storage {storage_name} {path}")),
)))), )))],
), ),
VariableData::ComptimeValue { VariableData::ComptimeValue {
value, value,
@ -518,18 +546,25 @@ impl Transpiler {
Err(err) Err(err)
}, },
|val| { |val| {
let cmd = val.to_string_no_macro().map_or_else( let cmds = if let Some(s) = val.to_string_no_macro() {
|| { vec![Command::Return(datapack::ReturnCommand::Command(
let (macro_string, prepare_variables) = Box::new(Command::Raw(s)),
val.to_macro_string().into_sb(); ))]
Command::UsesMacro(macro_string) } else {
}, let (macro_string, prepare_variables) =
Command::Raw, val.to_macro_string().into_sb();
); self.transpile_commands_with_variable_macros(
Ok(( vec![Command::Return(
Vec::new(), datapack::ReturnCommand::Command(Box::new(
datapack::ReturnCommand::Command(Box::new(cmd)), Command::UsesMacro(macro_string),
)) )),
)],
prepare_variables,
handler,
)?
};
Ok((Vec::new(), cmds))
}, },
)?, )?,
VariableData::MacroParameter { VariableData::MacroParameter {
@ -537,19 +572,21 @@ impl Transpiler {
macro_name, macro_name,
} => ( } => (
Vec::new(), Vec::new(),
datapack::ReturnCommand::Command(Box::new(Command::UsesMacro( vec![Command::Return(datapack::ReturnCommand::Command(Box::new(
shulkerbox::util::MacroString::MacroString(vec![ Command::UsesMacro(shulkerbox::util::MacroString::MacroString(
shulkerbox::util::MacroStringPart::MacroUsage( vec![shulkerbox::util::MacroStringPart::MacroUsage(
macro_name.clone(), macro_name.clone(),
), )],
]), )),
))), )))],
), ),
VariableData::ScoreboardValue { objective, target } => ( VariableData::ScoreboardValue { objective, target } => (
Vec::new(), Vec::new(),
datapack::ReturnCommand::Command(Box::new(Command::Raw(format!( vec![Command::Return(datapack::ReturnCommand::Command(Box::new(
"scoreboard players get {target} {objective}" Command::Raw(format!(
)))), "scoreboard players get {target} {objective}"
)),
)))],
), ),
_ => { _ => {
let err = TranspileError::UnexpectedExpression( let err = TranspileError::UnexpectedExpression(
@ -585,15 +622,12 @@ impl Transpiler {
scope, scope,
handler, handler,
)?; )?;
(cmds, ret_cmd) (cmds, vec![Command::Return(ret_cmd)])
} }
} }
}; };
let cmds = prepare_cmds let cmds = prepare_cmds.into_iter().chain(ret_cmds).collect();
.into_iter()
.chain(std::iter::once(Command::Return(ret_cmd)))
.collect();
Ok(cmds) Ok(cmds)
} }
@ -849,14 +883,15 @@ impl Transpiler {
scope: &Arc<Scope>, scope: &Arc<Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<Vec<Command>> { ) -> TranspileResult<Vec<Command>> {
self.transpile_execute_block_internal(execute, program_identifier, scope, handler) if let Some((mut pre_cmds, prepare_variables, exec)) =
.map(|ex| { self.transpile_execute_block_internal(execute, program_identifier, scope, handler)?
ex.map(|(mut pre_cmds, exec)| { {
pre_cmds.push(exec.into()); pre_cmds.push(exec.into());
pre_cmds
}) self.transpile_commands_with_variable_macros(pre_cmds, prepare_variables, handler)
.unwrap_or_default() } else {
}) Ok(Vec::new())
}
} }
fn transpile_execute_block_internal( fn transpile_execute_block_internal(
@ -865,7 +900,7 @@ impl Transpiler {
program_identifier: &str, program_identifier: &str,
scope: &Arc<Scope>, scope: &Arc<Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<Option<(Vec<Command>, Execute)>> { ) -> TranspileResult<Option<(Vec<Command>, ShulkerboxMacroStringMap, Execute)>> {
match execute { match execute {
ExecuteBlock::HeadTail(head, tail) => { ExecuteBlock::HeadTail(head, tail) => {
let tail = match tail { let tail = match tail {
@ -889,7 +924,7 @@ impl Transpiler {
if commands.is_empty() { if commands.is_empty() {
Ok(None) Ok(None)
} else { } else {
Ok(Some((Vec::new(), Execute::Runs(commands)))) Ok(Some((Vec::new(), BTreeMap::new(), Execute::Runs(commands))))
} }
} }
ExecuteBlockTail::ExecuteBlock(_, execute_block) => self ExecuteBlockTail::ExecuteBlock(_, execute_block) => self
@ -964,7 +999,7 @@ impl Transpiler {
program_identifier: &str, program_identifier: &str,
scope: &Arc<Scope>, scope: &Arc<Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<Option<(Vec<Command>, Execute)>> { ) -> TranspileResult<Option<(Vec<Command>, ShulkerboxMacroStringMap, Execute)>> {
let cond_expression = cond.condition().expression().as_ref(); let cond_expression = cond.condition().expression().as_ref();
let mut errors = Vec::new(); let mut errors = Vec::new();
@ -994,28 +1029,29 @@ impl Transpiler {
if let Ok(ComptimeValue::Boolean(value)) = cond_expression.comptime_eval(scope, handler) { if let Ok(ComptimeValue::Boolean(value)) = cond_expression.comptime_eval(scope, handler) {
if value { if value {
Ok(Some((Vec::new(), then))) Ok(Some((Vec::new(), BTreeMap::new(), then)))
} else { } else {
Ok(el.map(|el| (Vec::new(), el))) Ok(el.map(|el| (Vec::new(), BTreeMap::new(), el)))
} }
} else { } else {
if !errors.is_empty() { if !errors.is_empty() {
return Err(errors.remove(0)); 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)?; self.transpile_expression_as_condition(cond_expression, scope, handler)?;
match cond { match cond {
ExtendedCondition::Runtime(cond) => Ok(Some(( ExtendedCondition::Runtime(cond) => Ok(Some((
pre_cond_cmds, pre_cond_cmds,
prepare_variables,
Execute::If(cond, Box::new(then), el.map(Box::new)), Execute::If(cond, Box::new(then), el.map(Box::new)),
))), ))),
ExtendedCondition::Comptime(cond) => { ExtendedCondition::Comptime(cond) => {
if cond { if cond {
Ok(Some((Vec::new(), then))) Ok(Some((Vec::new(), prepare_variables, then)))
} else { } 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( fn combine_execute_head_tail(
&mut self, &mut self,
head: &ExecuteBlockHead, head: &ExecuteBlockHead,
tail: Option<(Vec<Command>, Execute)>, tail: Option<(Vec<Command>, ShulkerboxMacroStringMap, Execute)>,
program_identifier: &str, program_identifier: &str,
scope: &Arc<Scope>, scope: &Arc<Scope>,
handler: &impl Handler<base::Error>, handler: &impl Handler<base::Error>,
) -> TranspileResult<Option<(Vec<Command>, Execute)>> { ) -> TranspileResult<Option<(Vec<Command>, ShulkerboxMacroStringMap, Execute)>> {
Ok(match head { Ok(match head {
ExecuteBlockHead::Conditional(cond) => { ExecuteBlockHead::Conditional(cond) => {
if let Some((mut pre_cmds, tail)) = tail { if let Some((mut pre_cmds, prepare_variables, tail)) = tail {
self.transpile_conditional( self.transpile_conditional(
cond, cond,
tail, tail,
@ -1042,9 +1078,10 @@ impl Transpiler {
scope, scope,
handler, handler,
)? )?
.map(|(pre_cond_cmds, cond)| { .map(|(pre_cond_cmds, mut prep_variables, cond)| {
pre_cmds.extend(pre_cond_cmds); pre_cmds.extend(pre_cond_cmds);
(pre_cmds, cond) prep_variables.extend(prepare_variables);
(pre_cmds, prep_variables, cond)
}) })
} else { } else {
None None
@ -1055,22 +1092,41 @@ impl Transpiler {
.as_selector() .as_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = selector.into_sb(); 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) => { ExecuteBlockHead::At(at) => {
let selector = at let selector = at
.at_selector() .at_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = selector.into_sb(); 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) => { ExecuteBlockHead::Align(align) => {
let align = align let align = align
.align_selector() .align_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = align.into_sb(); let (macro_string, prepare_variables) = align.into_sb();
tail.map(|(pre_cmds, tail)| { tail.map(|(pre_cmds, mut prep_variables, tail)| {
(pre_cmds, Execute::Align(macro_string, Box::new(tail))) prep_variables.extend(prepare_variables);
(
pre_cmds,
prep_variables,
Execute::Align(macro_string, Box::new(tail)),
)
}) })
} }
ExecuteBlockHead::Anchored(anchored) => { ExecuteBlockHead::Anchored(anchored) => {
@ -1079,8 +1135,13 @@ impl Transpiler {
.anchored_selector() .anchored_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = anchor.into_sb(); let (macro_string, prepare_variables) = anchor.into_sb();
tail.map(|(pre_cmds, tail)| { tail.map(|(pre_cmds, mut prep_variables, tail)| {
(pre_cmds, Execute::Anchored(macro_string, Box::new(tail))) prep_variables.extend(prepare_variables);
(
pre_cmds,
prep_variables,
Execute::Anchored(macro_string, Box::new(tail)),
)
}) })
} }
ExecuteBlockHead::In(r#in) => { ExecuteBlockHead::In(r#in) => {
@ -1088,7 +1149,14 @@ impl Transpiler {
.in_selector() .in_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = dimension.into_sb(); 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) => { ExecuteBlockHead::Positioned(positioned) => {
let position = let position =
@ -1096,8 +1164,13 @@ impl Transpiler {
.positioned_selector() .positioned_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = position.into_sb(); let (macro_string, prepare_variables) = position.into_sb();
tail.map(|(pre_cmds, tail)| { tail.map(|(pre_cmds, mut prep_variables, tail)| {
(pre_cmds, Execute::Positioned(macro_string, Box::new(tail))) prep_variables.extend(prepare_variables);
(
pre_cmds,
prep_variables,
Execute::Positioned(macro_string, Box::new(tail)),
)
}) })
} }
ExecuteBlockHead::Rotated(rotated) => { ExecuteBlockHead::Rotated(rotated) => {
@ -1106,8 +1179,13 @@ impl Transpiler {
.rotated_selector() .rotated_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = rotation.into_sb(); let (macro_string, prepare_variables) = rotation.into_sb();
tail.map(|(pre_cmds, tail)| { tail.map(|(pre_cmds, mut prep_variables, tail)| {
(pre_cmds, Execute::Rotated(macro_string, Box::new(tail))) prep_variables.extend(prepare_variables);
(
pre_cmds,
prep_variables,
Execute::Rotated(macro_string, Box::new(tail)),
)
}) })
} }
ExecuteBlockHead::Facing(facing) => { ExecuteBlockHead::Facing(facing) => {
@ -1116,8 +1194,13 @@ impl Transpiler {
.facing_selector() .facing_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = facing.into_sb(); let (macro_string, prepare_variables) = facing.into_sb();
tail.map(|(pre_cmds, tail)| { tail.map(|(pre_cmds, mut prep_variables, tail)| {
(pre_cmds, Execute::Facing(macro_string, Box::new(tail))) prep_variables.extend(prepare_variables);
(
pre_cmds,
prep_variables,
Execute::Facing(macro_string, Box::new(tail)),
)
}) })
} }
ExecuteBlockHead::AsAt(as_at) => { ExecuteBlockHead::AsAt(as_at) => {
@ -1125,22 +1208,41 @@ impl Transpiler {
.asat_selector() .asat_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = selector.into_sb(); 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) => { ExecuteBlockHead::On(on) => {
let dimension = on let dimension = on
.on_selector() .on_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = dimension.into_sb(); 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) => { ExecuteBlockHead::Store(store) => {
let store = store let store = store
.store_selector() .store_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = store.into_sb(); let (macro_string, prepare_variables) = store.into_sb();
tail.map(|(pre_cmds, tail)| { tail.map(|(pre_cmds, mut prep_variables, tail)| {
(pre_cmds, Execute::Store(macro_string, Box::new(tail))) prep_variables.extend(prepare_variables);
(
pre_cmds,
prep_variables,
Execute::Store(macro_string, Box::new(tail)),
)
}) })
} }
ExecuteBlockHead::Summon(summon) => { ExecuteBlockHead::Summon(summon) => {
@ -1149,8 +1251,13 @@ impl Transpiler {
.summon_selector() .summon_selector()
.to_macro_string(Some(self), scope, handler)?; .to_macro_string(Some(self), scope, handler)?;
let (macro_string, prepare_variables) = entity.into_sb(); let (macro_string, prepare_variables) = entity.into_sb();
tail.map(|(pre_cmds, tail)| { tail.map(|(pre_cmds, mut prep_variables, tail)| {
(pre_cmds, Execute::Summon(macro_string, Box::new(tail))) prep_variables.extend(prepare_variables);
(
pre_cmds,
prep_variables,
Execute::Summon(macro_string, Box::new(tail)),
)
}) })
} }
}) })
@ -1197,9 +1304,9 @@ impl Transpiler {
} else { } else {
prepare_cmds.push(Command::Group( prepare_cmds.push(Command::Group(
Group::new(cmds) Group::new(cmds)
.always_create_function(true) .with_always_create_function(true)
.block_pass_macros(macro_names) .with_block_pass_macros(macro_names)
.data_storage_name(storage_name), .with_data_storage_name(storage_name),
)); ));
Ok(prepare_cmds) Ok(prepare_cmds)