fix parse error panicing in function args
This commit is contained in:
parent
b7d50f8222
commit
d0cee40524
|
@ -967,20 +967,10 @@ 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 let Some(variable_type) = scope.get_variable(identifier.span.str()) {
|
if scope.get_variable(identifier.span.str()).is_none() {
|
||||||
// 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(),
|
||||||
});
|
});
|
||||||
|
@ -1026,6 +1016,9 @@ 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(),
|
||||||
|
|
|
@ -344,6 +344,7 @@ 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,
|
||||||
|
|
|
@ -1010,6 +1010,7 @@ 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,
|
||||||
|
|
|
@ -412,7 +412,7 @@ impl Transpiler {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut compiled_args = Vec::<Parameter>::new();
|
let mut compiled_args = Vec::<(Parameter, Span)>::new();
|
||||||
let mut errs = Vec::new();
|
let mut errs = Vec::new();
|
||||||
|
|
||||||
for (expression, is_comptime) in arguments
|
for (expression, is_comptime) in arguments
|
||||||
|
@ -571,11 +571,13 @@ impl Transpiler {
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
compiled_args.push(value);
|
compiled_args.push((value, expression.span()));
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
compiled_args
|
compiled_args.push((
|
||||||
.push(Parameter::Static(MacroString::String(String::new())));
|
Parameter::Static(MacroString::String(String::new())),
|
||||||
|
expression.span(),
|
||||||
|
));
|
||||||
errs.push(err.clone());
|
errs.push(err.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -584,111 +586,164 @@ 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 (require_dyn_params, mut setup_cmds, move_cmds, static_params) = parameters.clone().into_iter().zip(compiled_args).fold(
|
let mut require_dyn_params = false;
|
||||||
(false, Vec::new(), Vec::new(), BTreeMap::new()),
|
let mut setup_cmds = Vec::new();
|
||||||
|(mut require_dyn_params, mut acc_setup, mut acc_move, mut statics), (param, data)| {
|
let mut move_cmds = Vec::new();
|
||||||
|
let mut statics = BTreeMap::new();
|
||||||
|
|
||||||
|
for (param, (data, span)) in parameters.clone().into_iter().zip(compiled_args) {
|
||||||
match param.variable_type() {
|
match param.variable_type() {
|
||||||
FunctionVariableType::Macro(_) => {
|
FunctionVariableType::Macro(_) => {
|
||||||
let arg_name = crate::util::identifier_to_macro(param.identifier().span.str());
|
let arg_name =
|
||||||
|
crate::util::identifier_to_macro(param.identifier().span.str());
|
||||||
match data {
|
match data {
|
||||||
Parameter::Comptime => {}
|
Parameter::Comptime => {}
|
||||||
Parameter::Static(s) => {
|
Parameter::Static(s) => {
|
||||||
match s {
|
match s {
|
||||||
MacroString::String(value) => statics.insert(
|
MacroString::String(value) => statics.insert(
|
||||||
arg_name.to_string(),
|
arg_name.to_string(),
|
||||||
MacroString::String(crate::util::escape_str(&value).to_string())
|
MacroString::String(
|
||||||
|
crate::util::escape_str(&value).to_string(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
MacroString::MacroString(parts) => {
|
MacroString::MacroString(parts) => {
|
||||||
let parts = parts.into_iter().map(|part| {
|
let parts = parts
|
||||||
match part {
|
.into_iter()
|
||||||
MacroStringPart::String(s) => MacroStringPart::String(crate::util::escape_str(&s).to_string()),
|
.map(|part| match part {
|
||||||
MacroStringPart::MacroUsage(m) => MacroStringPart::MacroUsage(m),
|
MacroStringPart::String(s) => {
|
||||||
|
MacroStringPart::String(
|
||||||
|
crate::util::escape_str(&s)
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}).collect();
|
MacroStringPart::MacroUsage(m) => {
|
||||||
statics.insert(arg_name.to_string(), MacroString::MacroString(parts))
|
MacroStringPart::MacroUsage(m)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
statics.insert(
|
||||||
|
arg_name.to_string(),
|
||||||
|
MacroString::MacroString(parts),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Parameter::Storage { prepare_cmds, storage_name, path } => {
|
Parameter::Storage {
|
||||||
|
prepare_cmds,
|
||||||
|
storage_name,
|
||||||
|
path,
|
||||||
|
} => {
|
||||||
require_dyn_params = true;
|
require_dyn_params = true;
|
||||||
acc_setup.extend(prepare_cmds);
|
setup_cmds.extend(prepare_cmds);
|
||||||
acc_move.push(Command::Raw(
|
move_cmds.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!(
|
||||||
|
"shu_arguments_{}",
|
||||||
|
function_location.replace(['/', ':'], "_")
|
||||||
|
);
|
||||||
let param_str = param.identifier().span.str();
|
let param_str = param.identifier().span.str();
|
||||||
let target = crate::util::identifier_to_scoreboard_target(param_str);
|
let target =
|
||||||
|
crate::util::identifier_to_scoreboard_target(param_str);
|
||||||
|
|
||||||
match data {
|
match data {
|
||||||
Parameter::Comptime => {}
|
Parameter::Comptime => {}
|
||||||
Parameter::Static(s) => {
|
Parameter::Static(s) => match s.as_str() {
|
||||||
match s.as_str() {
|
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
if s.parse::<i32>().is_ok() {
|
if s.parse::<i32>().is_ok() {
|
||||||
acc_move.push(Command::Raw(format!(r"scoreboard players set {target} {objective} {s}")));
|
move_cmds.push(Command::Raw(format!(r"scoreboard players set {target} {objective} {s}")));
|
||||||
} else {
|
} else {
|
||||||
panic!("non-integer static argument")
|
let err = TranspileError::MismatchedTypes(
|
||||||
|
MismatchedTypes {
|
||||||
|
expression: span,
|
||||||
|
expected_type: ExpectedType::Integer,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
handler.receive(Box::new(err.clone()));
|
||||||
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(parts) => {
|
Err(parts) => {
|
||||||
acc_move.push(Command::UsesMacro(MacroString::MacroString(
|
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 {
|
||||||
Parameter::Storage { prepare_cmds, storage_name, path } => {
|
prepare_cmds,
|
||||||
acc_setup.extend(prepare_cmds);
|
storage_name,
|
||||||
acc_move.push(Command::Execute(Execute::Store(
|
path,
|
||||||
|
} => {
|
||||||
|
setup_cmds.extend(prepare_cmds);
|
||||||
|
move_cmds.push(Command::Execute(Execute::Store(
|
||||||
format!("result score {target} {objective}").into(),
|
format!("result score {target} {objective}").into(),
|
||||||
Box::new(Execute::Run(Box::new(Command::Raw(format!("data get storage {storage_name} {path}")))))
|
Box::new(Execute::Run(Box::new(Command::Raw(
|
||||||
|
format!("data get storage {storage_name} {path}"),
|
||||||
|
)))),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
FunctionVariableType::Boolean(_) => {
|
FunctionVariableType::Boolean(_) => {
|
||||||
require_dyn_params = true;
|
require_dyn_params = true;
|
||||||
let target_storage_name = format!("shulkerscript:arguments_{}", function_location.replace(['/', ':'], "_"));
|
let target_storage_name = format!(
|
||||||
|
"shulkerscript:arguments_{}",
|
||||||
|
function_location.replace(['/', ':'], "_")
|
||||||
|
);
|
||||||
let param_str = param.identifier().span.str();
|
let param_str = param.identifier().span.str();
|
||||||
let target_path = crate::util::identifier_to_scoreboard_target(param_str);
|
let target_path =
|
||||||
|
crate::util::identifier_to_scoreboard_target(param_str);
|
||||||
|
|
||||||
match data {
|
match data {
|
||||||
Parameter::Comptime => {}
|
Parameter::Comptime => {}
|
||||||
Parameter::Static(s) => {
|
Parameter::Static(s) => match s.as_str() {
|
||||||
match s.as_str() {
|
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
if let Ok(b) = s.parse::<bool>() {
|
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" })));
|
move_cmds.push(Command::Raw(format!("data modify storage {target_storage_name} {target_path} set value {}", if b { "1b" } else { "0b" })));
|
||||||
} else {
|
} else {
|
||||||
panic!("non-integer static argument")
|
let err = TranspileError::MismatchedTypes(
|
||||||
|
MismatchedTypes {
|
||||||
|
expression: span,
|
||||||
|
expected_type: ExpectedType::Boolean,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
handler.receive(Box::new(err.clone()));
|
||||||
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(parts) => {
|
Err(parts) => {
|
||||||
acc_move.push(Command::UsesMacro(MacroString::MacroString(
|
move_cmds.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(_) => {
|
FunctionVariableType::Value(_) => {
|
||||||
// handled before in `transpile_comptime_function_arguments`
|
// handled before in `transpile_comptime_function_arguments`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(require_dyn_params, acc_setup, acc_move, statics)},
|
}
|
||||||
);
|
|
||||||
|
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(
|
||||||
|
@ -749,14 +804,13 @@ impl Transpiler {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let function_args = parameters
|
let function_args =
|
||||||
|
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))
|
.map(|(k, v)| (k.identifier().span.str().to_string(), v))
|
||||||
.collect();
|
.collect();
|
||||||
Ok(TranspiledFunctionArguments::Static(
|
Ok(TranspiledFunctionArguments::Static(
|
||||||
|
|
|
@ -69,6 +69,7 @@ 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,
|
||||||
|
|
|
@ -329,6 +329,13 @@ 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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue