add handling for template strings everywhere
This commit is contained in:
parent
6043a4add5
commit
1b85a2f654
|
@ -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"
|
||||
|
|
|
@ -984,8 +984,11 @@ impl Parser<'_> {
|
|||
&mut self,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> ParseResult<AnyStringLiteral> {
|
||||
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),
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
|
||||
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 {
|
||||
pub fn into_sb(self) -> (ExtMacroString, ShulkerboxMacroStringMap) {
|
||||
|
|
|
@ -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<super::Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<(Vec<Command>, ExtendedCondition)> {
|
||||
) -> TranspileResult<(Vec<Command>, 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<super::Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<(Vec<Command>, ExtendedCondition)> {
|
||||
) -> TranspileResult<(Vec<Command>, 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<super::Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<(Vec<Command>, ExtendedCondition)> {
|
||||
) -> TranspileResult<(Vec<Command>, 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<super::Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<(Vec<Command>, Condition)> {
|
||||
) -> TranspileResult<(Vec<Command>, 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<super::Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<(Vec<Command>, ExtendedCondition)> {
|
||||
) -> TranspileResult<(Vec<Command>, 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")
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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::<MacroString>().expect("cannot fail").into_sb();
|
||||
let (macro_string, _) = cmd.parse::<MacroString>().expect("cannot fail").into_sb();
|
||||
Command::UsesMacro(macro_string)
|
||||
} else {
|
||||
Command::Raw(cmd)
|
||||
|
|
|
@ -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<Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<Vec<Command>> {
|
||||
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<Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<Option<(Vec<Command>, Execute)>> {
|
||||
) -> TranspileResult<Option<(Vec<Command>, 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<Scope>,
|
||||
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 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<Command>, Execute)>,
|
||||
tail: Option<(Vec<Command>, ShulkerboxMacroStringMap, Execute)>,
|
||||
program_identifier: &str,
|
||||
scope: &Arc<Scope>,
|
||||
handler: &impl Handler<base::Error>,
|
||||
) -> TranspileResult<Option<(Vec<Command>, Execute)>> {
|
||||
) -> TranspileResult<Option<(Vec<Command>, 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)
|
||||
|
|
Loading…
Reference in New Issue