implement error on conflicting function names and deterministic function generation order

This commit is contained in:
Moritz Hölting 2024-09-20 16:50:40 +02:00
parent 61b8f1ffb9
commit 0133661ad4
2 changed files with 53 additions and 11 deletions

View File

@ -1,6 +1,6 @@
//! Errors that can occur during transpilation. //! Errors that can occur during transpilation.
use std::{collections::HashMap, fmt::Display}; use std::{collections::BTreeMap, fmt::Display};
use getset::Getters; use getset::Getters;
use itertools::Itertools; use itertools::Itertools;
@ -27,6 +27,8 @@ pub enum TranspileError {
LuaDisabled, LuaDisabled,
#[error(transparent)] #[error(transparent)]
LuaRuntimeError(#[from] LuaRuntimeError), LuaRuntimeError(#[from] LuaRuntimeError),
#[error(transparent)]
ConflictingFunctionNames(#[from] ConflictingFunctionNames),
} }
/// The result of a transpilation operation. /// The result of a transpilation operation.
@ -44,7 +46,7 @@ pub struct MissingFunctionDeclaration {
impl MissingFunctionDeclaration { impl MissingFunctionDeclaration {
pub(super) fn from_context( pub(super) fn from_context(
identifier_span: Span, identifier_span: Span,
functions: &HashMap<(String, String), FunctionData>, functions: &BTreeMap<(String, String), FunctionData>,
) -> Self { ) -> Self {
let own_name = identifier_span.str(); let own_name = identifier_span.str();
let own_program_identifier = identifier_span.source_file().identifier(); let own_program_identifier = identifier_span.source_file().identifier();
@ -163,3 +165,30 @@ impl Display for UnexpectedExpression {
} }
impl std::error::Error for UnexpectedExpression {} impl std::error::Error for UnexpectedExpression {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConflictingFunctionNames {
pub definition: Span,
pub name: String,
}
impl Display for ConflictingFunctionNames {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
Message::new(
Severity::Error,
format!("the following function declaration conflicts with an existing function with name `{}`", self.name)
)
)?;
write!(
f,
"\n{}",
SourceCodeDisplay::new(&self.definition, Option::<u8>::None)
)
}
}
impl std::error::Error for ConflictingFunctionNames {}

View File

@ -1,7 +1,11 @@
//! Transpiler for `ShulkerScript` //! Transpiler for `ShulkerScript`
use chksum_md5 as md5; use chksum_md5 as md5;
use std::{collections::HashMap, iter, sync::RwLock}; use std::{
collections::{BTreeMap, HashMap},
iter,
sync::RwLock,
};
use shulkerbox::datapack::{self, Command, Datapack, Execute}; use shulkerbox::datapack::{self, Command, Datapack, Execute};
@ -20,7 +24,7 @@ use crate::{
Statement, Statement,
}, },
}, },
transpile::error::MissingFunctionDeclaration, transpile::error::{ConflictingFunctionNames, MissingFunctionDeclaration},
}; };
use super::error::{TranspileError, TranspileResult, UnexpectedExpression}; use super::error::{TranspileError, TranspileResult, UnexpectedExpression};
@ -30,7 +34,7 @@ use super::error::{TranspileError, TranspileResult, UnexpectedExpression};
pub struct Transpiler { pub struct Transpiler {
datapack: shulkerbox::datapack::Datapack, datapack: shulkerbox::datapack::Datapack,
/// Key: (program identifier, function name) /// Key: (program identifier, function name)
functions: RwLock<HashMap<(String, String), FunctionData>>, functions: RwLock<BTreeMap<(String, String), FunctionData>>,
function_locations: RwLock<HashMap<(String, String), (String, bool)>>, function_locations: RwLock<HashMap<(String, String), (String, bool)>>,
aliases: RwLock<HashMap<(String, String), (String, String)>>, aliases: RwLock<HashMap<(String, String), (String, String)>>,
} }
@ -50,7 +54,7 @@ impl Transpiler {
pub fn new(pack_format: u8) -> Self { pub fn new(pack_format: u8) -> Self {
Self { Self {
datapack: shulkerbox::datapack::Datapack::new(pack_format), datapack: shulkerbox::datapack::Datapack::new(pack_format),
functions: RwLock::new(HashMap::new()), functions: RwLock::new(BTreeMap::new()),
function_locations: RwLock::new(HashMap::new()), function_locations: RwLock::new(HashMap::new()),
aliases: RwLock::new(HashMap::new()), aliases: RwLock::new(HashMap::new()),
} }
@ -80,7 +84,7 @@ impl Transpiler {
let mut always_transpile_functions = Vec::new(); let mut always_transpile_functions = Vec::new();
#[allow(clippy::significant_drop_in_scrutinee)] // #[allow(clippy::significant_drop_in_scrutinee)]
{ {
let functions = self.functions.read().unwrap(); let functions = self.functions.read().unwrap();
for (_, data) in functions.iter() { for (_, data) in functions.iter() {
@ -144,6 +148,7 @@ impl Transpiler {
) )
}) })
.collect(); .collect();
#[allow(clippy::significant_drop_tightening)]
self.functions.write().unwrap().insert( self.functions.write().unwrap().insert(
(program_identifier, name), (program_identifier, name),
FunctionData { FunctionData {
@ -268,10 +273,18 @@ impl Transpiler {
) )
.unwrap_or_else(|| identifier_span.str().to_string()); .unwrap_or_else(|| identifier_span.str().to_string());
let function = self let namespace = self.datapack.namespace_mut(&function_data.namespace);
.datapack
.namespace_mut(&function_data.namespace) if namespace.function(&modified_name).is_some() {
.function_mut(&modified_name); let err = TranspileError::ConflictingFunctionNames(ConflictingFunctionNames {
name: modified_name,
definition: identifier_span.clone(),
});
handler.receive(err.clone());
return Err(err);
}
let function = namespace.function_mut(&modified_name);
function.get_commands_mut().extend(commands); function.get_commands_mut().extend(commands);
let function_location = format!( let function_location = format!(