list alternative identifiers using oxford_join
This commit is contained in:
parent
1b85a2f654
commit
218f488e76
|
@ -31,6 +31,7 @@ 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.11.3", features = ["lua54", "vendored"], optional = true }
|
mlua = { version = "0.11.3", features = ["lua54", "vendored"], optional = true }
|
||||||
|
oxford_join = { version = "0.7.1", 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 }
|
||||||
|
|
|
@ -11,17 +11,12 @@ use crate::{
|
||||||
},
|
},
|
||||||
lexical::token::StringLiteral,
|
lexical::token::StringLiteral,
|
||||||
syntax::syntax_tree::expression::Expression,
|
syntax::syntax_tree::expression::Expression,
|
||||||
transpile::error::{
|
transpile::error::{AssignmentError, IllegalIndexing, MismatchedTypes, UnknownIdentifier},
|
||||||
AssignmentError, IllegalIndexing, MismatchedTypes, MissingFunctionDeclaration,
|
|
||||||
UnknownIdentifier,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, thiserror::Error)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, thiserror::Error)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error(transparent)]
|
|
||||||
MissingFunctionDeclaration(#[from] MissingFunctionDeclaration),
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
UnexpectedExpression(#[from] UnexpectedExpression),
|
UnexpectedExpression(#[from] UnexpectedExpression),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
|
use oxford_join::OxfordJoin as _;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
base::{
|
base::{
|
||||||
|
@ -12,14 +13,12 @@ use crate::{
|
||||||
semantic::error::{ConflictingFunctionNames, InvalidFunctionArguments, UnexpectedExpression},
|
semantic::error::{ConflictingFunctionNames, InvalidFunctionArguments, UnexpectedExpression},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{expression::ExpectedType, FunctionData};
|
use super::expression::ExpectedType;
|
||||||
|
|
||||||
/// Errors that can occur during transpilation.
|
/// Errors that can occur during transpilation.
|
||||||
#[allow(clippy::module_name_repetitions, missing_docs)]
|
#[allow(clippy::module_name_repetitions, missing_docs)]
|
||||||
#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
|
#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
|
||||||
pub enum TranspileError {
|
pub enum TranspileError {
|
||||||
#[error(transparent)]
|
|
||||||
MissingFunctionDeclaration(#[from] MissingFunctionDeclaration),
|
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
UnexpectedExpression(#[from] UnexpectedExpression),
|
UnexpectedExpression(#[from] UnexpectedExpression),
|
||||||
#[error("Lua code evaluation is disabled.")]
|
#[error("Lua code evaluation is disabled.")]
|
||||||
|
@ -53,101 +52,6 @@ pub enum TranspileError {
|
||||||
/// The result of a transpilation operation.
|
/// The result of a transpilation operation.
|
||||||
pub type TranspileResult<T> = Result<T, TranspileError>;
|
pub type TranspileResult<T> = Result<T, TranspileError>;
|
||||||
|
|
||||||
/// An error that occurs when a function declaration is missing.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Getters)]
|
|
||||||
pub struct MissingFunctionDeclaration {
|
|
||||||
/// The span of the identifier that is missing.
|
|
||||||
#[get = "pub"]
|
|
||||||
span: Span,
|
|
||||||
/// Possible alternatives for the missing function declaration.
|
|
||||||
#[get = "pub"]
|
|
||||||
alternatives: Vec<FunctionData>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MissingFunctionDeclaration {
|
|
||||||
#[cfg(feature = "shulkerbox")]
|
|
||||||
pub(super) fn from_scope(
|
|
||||||
identifier_span: Span,
|
|
||||||
scope: &std::sync::Arc<super::variables::Scope>,
|
|
||||||
) -> Self {
|
|
||||||
use itertools::Itertools as _;
|
|
||||||
|
|
||||||
let own_name = identifier_span.str();
|
|
||||||
let alternatives = scope
|
|
||||||
.get_all_variables()
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(name, value)| {
|
|
||||||
let super::variables::VariableData::Function {
|
|
||||||
function_data: data,
|
|
||||||
..
|
|
||||||
} = value.as_ref()
|
|
||||||
else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let normalized_distance = strsim::normalized_damerau_levenshtein(own_name, name);
|
|
||||||
(normalized_distance > 0.8 || strsim::damerau_levenshtein(own_name, name) < 3)
|
|
||||||
.then_some((normalized_distance, data))
|
|
||||||
})
|
|
||||||
.sorted_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(std::cmp::Ordering::Equal))
|
|
||||||
.map(|(_, data)| data)
|
|
||||||
.take(8)
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
alternatives,
|
|
||||||
span: identifier_span,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for MissingFunctionDeclaration {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
use std::fmt::Write as _;
|
|
||||||
|
|
||||||
let message = format!(
|
|
||||||
"no matching function declaration found for invocation of function `{}`",
|
|
||||||
self.span.str()
|
|
||||||
);
|
|
||||||
write!(f, "{}", Message::new(Severity::Error, message))?;
|
|
||||||
|
|
||||||
let help_message = if self.alternatives.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let mut message = String::from("did you mean ");
|
|
||||||
for (i, alternative) in self.alternatives.iter().enumerate() {
|
|
||||||
if i > 0 {
|
|
||||||
message.push_str(", ");
|
|
||||||
}
|
|
||||||
let _ = write!(message, "`{}`", alternative.identifier_span.str());
|
|
||||||
}
|
|
||||||
Some(message + "?")
|
|
||||||
};
|
|
||||||
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"\n{}",
|
|
||||||
SourceCodeDisplay::new(&self.span, help_message.as_ref())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::error::Error for MissingFunctionDeclaration {}
|
|
||||||
|
|
||||||
impl std::hash::Hash for MissingFunctionDeclaration {
|
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.span.hash(state);
|
|
||||||
for alternative in &self.alternatives {
|
|
||||||
alternative.identifier_span.hash(state);
|
|
||||||
alternative.namespace.hash(state);
|
|
||||||
alternative.parameters.hash(state);
|
|
||||||
alternative.public.hash(state);
|
|
||||||
alternative.statements.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error that occurs when a function declaration is missing.
|
/// An error that occurs when a function declaration is missing.
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -341,8 +245,6 @@ impl UnknownIdentifier {
|
||||||
|
|
||||||
impl Display for UnknownIdentifier {
|
impl Display for UnknownIdentifier {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
use std::fmt::Write as _;
|
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}",
|
"{}",
|
||||||
|
@ -355,14 +257,15 @@ impl Display for UnknownIdentifier {
|
||||||
let help_message = if self.alternatives.is_empty() {
|
let help_message = if self.alternatives.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let mut message = String::from("did you mean ");
|
let message = String::from("did you mean ");
|
||||||
for (i, alternative) in self.alternatives.iter().enumerate() {
|
let inner = self
|
||||||
if i > 0 {
|
.alternatives
|
||||||
message.push_str(", ");
|
.iter()
|
||||||
}
|
.map(|s| format!("`{s}`"))
|
||||||
let _ = write!(message, "`{alternative}`");
|
.collect::<Vec<_>>();
|
||||||
}
|
let inner = inner.oxford_or();
|
||||||
Some(message + "?")
|
|
||||||
|
Some(message + &inner + "?")
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
|
|
|
@ -22,7 +22,7 @@ use crate::{
|
||||||
statement::Statement,
|
statement::Statement,
|
||||||
},
|
},
|
||||||
transpile::{
|
transpile::{
|
||||||
error::{IllegalAnnotationContent, MissingFunctionDeclaration},
|
error::IllegalAnnotationContent,
|
||||||
util::{MacroString, MacroStringPart},
|
util::{MacroString, MacroStringPart},
|
||||||
variables::FunctionVariableDataType,
|
variables::FunctionVariableDataType,
|
||||||
},
|
},
|
||||||
|
@ -57,9 +57,10 @@ impl Transpiler {
|
||||||
let function = scope.get_variable(identifier_span.str());
|
let function = scope.get_variable(identifier_span.str());
|
||||||
|
|
||||||
let function_data = function.ok_or_else(|| {
|
let function_data = function.ok_or_else(|| {
|
||||||
let err = TranspileError::MissingFunctionDeclaration(
|
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||||
MissingFunctionDeclaration::from_scope(identifier_span.clone(), scope),
|
identifier_span.clone(),
|
||||||
);
|
scope,
|
||||||
|
));
|
||||||
handler.receive(Box::new(err.clone()));
|
handler.receive(Box::new(err.clone()));
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
|
@ -91,14 +92,8 @@ impl Transpiler {
|
||||||
|
|
||||||
let function_location = function_path
|
let function_location = function_path
|
||||||
.get()
|
.get()
|
||||||
.ok_or_else(|| {
|
.expect("set in prepare_transpile_function if not previously set")
|
||||||
let err = TranspileError::MissingFunctionDeclaration(
|
.to_string();
|
||||||
MissingFunctionDeclaration::from_scope(identifier_span.clone(), scope),
|
|
||||||
);
|
|
||||||
handler.receive(Box::new(err.clone()));
|
|
||||||
err
|
|
||||||
})
|
|
||||||
.map(String::to_owned)?;
|
|
||||||
|
|
||||||
let args = self.transpile_function_arguments(
|
let args = self.transpile_function_arguments(
|
||||||
function_data,
|
function_data,
|
||||||
|
|
Loading…
Reference in New Issue