Compare commits

..

No commits in common. "d9f2d99c3a5e09488fc85ad792501a209387a89d" and "b7d50f822276a7465833d0b187614086fa64f319" have entirely different histories.

6 changed files with 118 additions and 181 deletions

View File

@ -967,10 +967,20 @@ impl TemplateStringLiteral {
for part in self.parts() { for part in self.parts() {
match part { match part {
TemplateStringLiteralPart::Expression { expression, .. } => { TemplateStringLiteralPart::Expression { expression, .. } => {
expression.analyze_semantics(scope, handler)?;
match expression.as_ref() { match expression.as_ref() {
Expression::Primary(Primary::Identifier(identifier)) => { Expression::Primary(Primary::Identifier(identifier)) => {
if scope.get_variable(identifier.span.str()).is_none() { if let Some(variable_type) = scope.get_variable(identifier.span.str()) {
// TODO: template string correct checks
// if variable_type != VariableType::MacroParameter {
// let err = error::Error::UnexpectedExpression(UnexpectedExpression(
// Box::new(Expression::Primary(Primary::Identifier(
// identifier.clone(),
// ))),
// ));
// handler.receive(err.clone());
// errs.push(err);
// }
} else {
let err = error::Error::UnknownIdentifier(UnknownIdentifier { let err = error::Error::UnknownIdentifier(UnknownIdentifier {
identifier: identifier.span.clone(), identifier: identifier.span.clone(),
}); });
@ -1016,9 +1026,6 @@ impl TemplateStringLiteral {
errs.push(err); errs.push(err);
} }
} }
Expression::Primary(Primary::MemberAccess(member_access)) => {
member_access.parent().analyze_semantics(scope, handler)?;
}
_ => { _ => {
let err = error::Error::UnexpectedExpression(UnexpectedExpression( let err = error::Error::UnexpectedExpression(UnexpectedExpression(
expression.clone(), expression.clone(),

View File

@ -344,7 +344,6 @@ impl Parser<'_> {
/// ///
/// # Errors /// # Errors
/// - cannot parse declaration from current position /// - cannot parse declaration from current position
#[expect(clippy::too_many_lines)]
#[tracing::instrument(level = "trace", skip_all)] #[tracing::instrument(level = "trace", skip_all)]
pub fn parse_declaration( pub fn parse_declaration(
&mut self, &mut self,

View File

@ -1010,7 +1010,6 @@ impl Parser<'_> {
/// ///
/// # Errors /// # Errors
/// - cannot parse variable declaration from current position /// - cannot parse variable declaration from current position
#[expect(clippy::too_many_lines)]
#[tracing::instrument(level = "trace", skip_all)] #[tracing::instrument(level = "trace", skip_all)]
pub fn parse_variable_declaration( pub fn parse_variable_declaration(
&mut self, &mut self,

View File

@ -412,7 +412,7 @@ impl Transpiler {
}, },
} }
let mut compiled_args = Vec::<(Parameter, Span)>::new(); let mut compiled_args = Vec::<Parameter>::new();
let mut errs = Vec::new(); let mut errs = Vec::new();
for (expression, is_comptime) in arguments for (expression, is_comptime) in arguments
@ -571,13 +571,11 @@ impl Transpiler {
match value { match value {
Ok(value) => { Ok(value) => {
compiled_args.push((value, expression.span())); compiled_args.push(value);
} }
Err(err) => { Err(err) => {
compiled_args.push(( compiled_args
Parameter::Static(MacroString::String(String::new())), .push(Parameter::Static(MacroString::String(String::new())));
expression.span(),
));
errs.push(err.clone()); errs.push(err.clone());
} }
} }
@ -586,164 +584,111 @@ impl Transpiler {
return Err(err.clone()); return Err(err.clone());
} }
if compiled_args.iter().any(|(arg, _)| !arg.is_static()) { if compiled_args.iter().any(|arg| !arg.is_static()) {
let mut require_dyn_params = false; let (require_dyn_params, mut setup_cmds, move_cmds, static_params) = parameters.clone().into_iter().zip(compiled_args).fold(
let mut setup_cmds = Vec::new(); (false, Vec::new(), Vec::new(), BTreeMap::new()),
let mut move_cmds = Vec::new(); |(mut require_dyn_params, mut acc_setup, mut acc_move, mut statics), (param, data)| {
let mut statics = BTreeMap::new(); match param.variable_type() {
FunctionVariableType::Macro(_) => {
for (param, (data, span)) in parameters.clone().into_iter().zip(compiled_args) { let arg_name = crate::util::identifier_to_macro(param.identifier().span.str());
match param.variable_type() { match data {
FunctionVariableType::Macro(_) => { Parameter::Comptime => {}
let arg_name = Parameter::Static(s) => {
crate::util::identifier_to_macro(param.identifier().span.str()); match s {
match data { MacroString::String(value) => statics.insert(
Parameter::Comptime => {}
Parameter::Static(s) => {
match s {
MacroString::String(value) => statics.insert(
arg_name.to_string(),
MacroString::String(
crate::util::escape_str(&value).to_string(),
),
),
MacroString::MacroString(parts) => {
let parts = parts
.into_iter()
.map(|part| match part {
MacroStringPart::String(s) => {
MacroStringPart::String(
crate::util::escape_str(&s)
.to_string(),
)
}
MacroStringPart::MacroUsage(m) => {
MacroStringPart::MacroUsage(m)
}
})
.collect();
statics.insert(
arg_name.to_string(), arg_name.to_string(),
MacroString::MacroString(parts), MacroString::String(crate::util::escape_str(&value).to_string())
) ),
} MacroString::MacroString(parts) => {
}; let parts = parts.into_iter().map(|part| {
} match part {
Parameter::Storage { MacroStringPart::String(s) => MacroStringPart::String(crate::util::escape_str(&s).to_string()),
prepare_cmds, MacroStringPart::MacroUsage(m) => MacroStringPart::MacroUsage(m),
storage_name, }
path, }).collect();
} => { statics.insert(arg_name.to_string(), MacroString::MacroString(parts))
require_dyn_params = true; }
setup_cmds.extend(prepare_cmds); };
move_cmds.push(Command::Raw( }
Parameter::Storage { prepare_cmds, storage_name, path } => {
require_dyn_params = true;
acc_setup.extend(prepare_cmds);
acc_move.push(Command::Raw(
format!(r"data modify storage shulkerscript:function_arguments {arg_name} set from storage {storage_name} {path}") format!(r"data modify storage shulkerscript:function_arguments {arg_name} set from storage {storage_name} {path}")
)); ));
}
} }
} }
} FunctionVariableType::Integer(_) => {
FunctionVariableType::Integer(_) => { let objective = format!("shu_arguments_{}", function_location.replace(['/', ':'], "_"));
let objective = format!( let param_str = param.identifier().span.str();
"shu_arguments_{}", let target = crate::util::identifier_to_scoreboard_target(param_str);
function_location.replace(['/', ':'], "_")
);
let param_str = param.identifier().span.str();
let target =
crate::util::identifier_to_scoreboard_target(param_str);
match data { match data {
Parameter::Comptime => {} Parameter::Comptime => {}
Parameter::Static(s) => match s.as_str() { Parameter::Static(s) => {
Ok(s) => { match s.as_str() {
if s.parse::<i32>().is_ok() { Ok(s) => {
move_cmds.push(Command::Raw(format!(r"scoreboard players set {target} {objective} {s}"))); if s.parse::<i32>().is_ok() {
} else { acc_move.push(Command::Raw(format!(r"scoreboard players set {target} {objective} {s}")));
let err = TranspileError::MismatchedTypes( } else {
MismatchedTypes { panic!("non-integer static argument")
expression: span, }
expected_type: ExpectedType::Integer, }
}, Err(parts) => {
); acc_move.push(Command::UsesMacro(MacroString::MacroString(
handler.receive(Box::new(err.clone()));
return Err(err);
}
}
Err(parts) => {
move_cmds.push(Command::UsesMacro(MacroString::MacroString(
std::iter::once(MacroStringPart::String(format!("scoreboard players set {target} {objective} "))) std::iter::once(MacroStringPart::String(format!("scoreboard players set {target} {objective} ")))
.chain(parts.iter().cloned()).collect() .chain(parts.iter().cloned()).collect()
).into())); ).into()));
} }
},
Parameter::Storage {
prepare_cmds,
storage_name,
path,
} => {
setup_cmds.extend(prepare_cmds);
move_cmds.push(Command::Execute(Execute::Store(
format!("result score {target} {objective}").into(),
Box::new(Execute::Run(Box::new(Command::Raw(
format!("data get storage {storage_name} {path}"),
)))),
)));
}
}
}
FunctionVariableType::Boolean(_) => {
require_dyn_params = true;
let target_storage_name = format!(
"shulkerscript:arguments_{}",
function_location.replace(['/', ':'], "_")
);
let param_str = param.identifier().span.str();
let target_path =
crate::util::identifier_to_scoreboard_target(param_str);
match data {
Parameter::Comptime => {}
Parameter::Static(s) => match s.as_str() {
Ok(s) => {
if let Ok(b) = s.parse::<bool>() {
move_cmds.push(Command::Raw(format!("data modify storage {target_storage_name} {target_path} set value {}", if b { "1b" } else { "0b" })));
} else {
let err = TranspileError::MismatchedTypes(
MismatchedTypes {
expression: span,
expected_type: ExpectedType::Boolean,
},
);
handler.receive(Box::new(err.clone()));
return Err(err);
} }
} }
Err(parts) => { Parameter::Storage { prepare_cmds, storage_name, path } => {
move_cmds.push(Command::UsesMacro(MacroString::MacroString( acc_setup.extend(prepare_cmds);
acc_move.push(Command::Execute(Execute::Store(
format!("result score {target} {objective}").into(),
Box::new(Execute::Run(Box::new(Command::Raw(format!("data get storage {storage_name} {path}")))))
)));
}
}
},
FunctionVariableType::Boolean(_) => {
require_dyn_params = true;
let target_storage_name = format!("shulkerscript:arguments_{}", function_location.replace(['/', ':'], "_"));
let param_str = param.identifier().span.str();
let target_path = crate::util::identifier_to_scoreboard_target(param_str);
match data {
Parameter::Comptime => {}
Parameter::Static(s) => {
match s.as_str() {
Ok(s) => {
if let Ok(b) = s.parse::<bool>() {
acc_move.push(Command::Raw(format!("data modify storage {target_storage_name} {target_path} set value {}", if b { "1b" } else { "0b" })));
} else {
panic!("non-integer static argument")
}
}
Err(parts) => {
acc_move.push(Command::UsesMacro(MacroString::MacroString(
std::iter::once(MacroStringPart::String(format!("data modify storage {target_storage_name} {target_path} set value "))) std::iter::once(MacroStringPart::String(format!("data modify storage {target_storage_name} {target_path} set value ")))
.chain(parts.iter().cloned()).collect() .chain(parts.iter().cloned()).collect()
).into())); ).into()));
}
}
}
Parameter::Storage { prepare_cmds, storage_name, path } => {
acc_setup.extend(prepare_cmds);
acc_move.push(Command::Raw(format!("data modify storage {target_storage_name} {target_path} set from storage {storage_name} {path}")));
} }
},
Parameter::Storage {
prepare_cmds,
storage_name,
path,
} => {
setup_cmds.extend(prepare_cmds);
move_cmds.push(Command::Raw(format!("data modify storage {target_storage_name} {target_path} set from storage {storage_name} {path}")));
} }
},
FunctionVariableType::Value(_) => {
// handled before in `transpile_comptime_function_arguments`
} }
} }
FunctionVariableType::Value(_) => { (require_dyn_params, acc_setup, acc_move, statics)},
// handled before in `transpile_comptime_function_arguments` );
}
}
}
let require_dyn_params = require_dyn_params;
let move_cmds = move_cmds;
let static_params = statics;
if require_dyn_params { if require_dyn_params {
let statics_len = static_params.len(); let statics_len = static_params.len();
let joined_statics = super::util::join_macro_strings( let joined_statics = super::util::join_macro_strings(
@ -804,15 +749,16 @@ impl Transpiler {
)) ))
} }
} else { } else {
let function_args = let function_args = parameters
parameters .clone()
.clone() .into_iter()
.into_iter() .zip(
.zip(compiled_args.into_iter().map(|(arg, _)| { compiled_args
arg.into_static().expect("checked in if condition") .into_iter()
})) .map(|arg| arg.into_static().expect("checked in if condition")),
.map(|(k, v)| (k.identifier().span.str().to_string(), v)) )
.collect(); .map(|(k, v)| (k.identifier().span.str().to_string(), v))
.collect();
Ok(TranspiledFunctionArguments::Static( Ok(TranspiledFunctionArguments::Static(
function_args, function_args,
Vec::new(), Vec::new(),

View File

@ -69,7 +69,6 @@ impl Transpiler {
/// ///
/// # Errors /// # Errors
/// - [`TranspileError::MissingFunctionDeclaration`] If a called function is missing /// - [`TranspileError::MissingFunctionDeclaration`] If a called function is missing
#[expect(clippy::too_many_lines)]
#[tracing::instrument(level = "trace", skip_all)] #[tracing::instrument(level = "trace", skip_all)]
pub fn transpile( pub fn transpile(
mut self, mut self,

View File

@ -1,8 +1,7 @@
//! Utility methods for transpiling //! Utility methods for transpiling
use std::{fmt::Display, str::FromStr}; use std::{fmt::Display, str::FromStr, sync::Arc};
#[cfg(feature = "shulkerbox")]
use crate::{ use crate::{
base::{self, source_file::SourceElement as _, Handler}, base::{self, source_file::SourceElement as _, Handler},
syntax::syntax_tree::{ syntax::syntax_tree::{
@ -11,12 +10,11 @@ use crate::{
}, },
transpile::{ transpile::{
error::{TranspileError, UnknownIdentifier}, error::{TranspileError, UnknownIdentifier},
expression::ComptimeValue,
Scope, TranspileResult, VariableData, Scope, TranspileResult, VariableData,
}, },
}; };
#[cfg(feature = "shulkerbox")]
use std::sync::Arc; use super::expression::ComptimeValue;
/// String that can contain macros /// String that can contain macros
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@ -258,7 +256,6 @@ where
} }
} }
#[cfg(feature = "shulkerbox")]
impl AnyStringLiteral { impl AnyStringLiteral {
/// Convert the any string literal to a macro string, using the provided scope to resolve variables /// Convert the any string literal to a macro string, using the provided scope to resolve variables
/// ///
@ -276,7 +273,6 @@ impl AnyStringLiteral {
} }
} }
#[cfg(feature = "shulkerbox")]
impl TemplateStringLiteral { impl TemplateStringLiteral {
/// Convert the template string literal to a macro string, using the provided scope to resolve variables /// Convert the template string literal to a macro string, using the provided scope to resolve variables
/// ///
@ -316,7 +312,7 @@ impl TemplateStringLiteral {
|| "null".into(), || "null".into(),
ComptimeValue::to_macro_string, ComptimeValue::to_macro_string,
); );
match value.as_str() { match value.as_str() {
Ok(s) => Ok(MacroStringPart::String(s.into_owned())), Ok(s) => Ok(MacroStringPart::String(s.into_owned())),
Err(_) => todo!("comptime value resulting in macro string with macros") Err(_) => todo!("comptime value resulting in macro string with macros")
@ -333,13 +329,6 @@ impl TemplateStringLiteral {
Err(err) Err(err)
} }
} }
Expression::Primary(Primary::MemberAccess(member_access)) => {
let value = member_access.parent().comptime_member_access(member_access, scope, handler).inspect_err(|err| {
handler.receive(Box::new(TranspileError::NotComptime(err.clone())));
})?.to_macro_string();
value.as_str().map_or_else(|_| todo!("comptime value resulting in macro string with macros"), |s| Ok(MacroStringPart::String(s.into_owned())))
}
_ => todo!("other expressions in template strings"), _ => todo!("other expressions in template strings"),
} }
} }
@ -349,9 +338,7 @@ impl TemplateStringLiteral {
Ok(macro_string) Ok(macro_string)
} else { } else {
Ok(MacroString::String( Ok(MacroString::String(self.as_str(scope, handler)?.into_owned()))
self.as_str(scope, handler)?.into_owned(),
))
} }
} }
} }