use strsim to suggest similar identifiers in UnknownIdentifier error
This commit is contained in:
parent
d9f2d99c3a
commit
ef7bf95447
|
@ -456,9 +456,10 @@ impl Assignment {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
let err = error::Error::UnknownIdentifier(UnknownIdentifier::from_semantic_scope(
|
||||||
identifier: self.destination().span(),
|
self.destination().span(),
|
||||||
});
|
scope,
|
||||||
|
));
|
||||||
handler.receive(err.clone());
|
handler.receive(err.clone());
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
@ -574,9 +575,9 @@ impl Primary {
|
||||||
match self {
|
match self {
|
||||||
Self::Identifier(ident) => {
|
Self::Identifier(ident) => {
|
||||||
if scope.get_variable(ident.span.str()).is_none() {
|
if scope.get_variable(ident.span.str()).is_none() {
|
||||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
let err = error::Error::UnknownIdentifier(
|
||||||
identifier: ident.span.clone(),
|
UnknownIdentifier::from_semantic_scope(ident.span.clone(), scope),
|
||||||
});
|
);
|
||||||
handler.receive(err.clone());
|
handler.receive(err.clone());
|
||||||
Err(err)
|
Err(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -589,9 +590,12 @@ impl Primary {
|
||||||
let var = scope.get_variable(call.identifier().span.str());
|
let var = scope.get_variable(call.identifier().span.str());
|
||||||
var.map_or_else(
|
var.map_or_else(
|
||||||
|| {
|
|| {
|
||||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
let err = error::Error::UnknownIdentifier(
|
||||||
identifier: call.identifier().span.clone(),
|
UnknownIdentifier::from_semantic_scope(
|
||||||
});
|
call.identifier().span.clone(),
|
||||||
|
scope,
|
||||||
|
),
|
||||||
|
);
|
||||||
handler.receive(err.clone());
|
handler.receive(err.clone());
|
||||||
Err(err)
|
Err(err)
|
||||||
},
|
},
|
||||||
|
@ -661,8 +665,8 @@ impl Primary {
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::MemberAccess(_) => {
|
Self::MemberAccess(member_access) => {
|
||||||
// TODO:
|
member_access.parent().analyze_semantics(scope, handler)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Self::Parenthesized(expr) => expr.analyze_semantics(scope, handler),
|
Self::Parenthesized(expr) => expr.analyze_semantics(scope, handler),
|
||||||
|
@ -971,9 +975,12 @@ impl TemplateStringLiteral {
|
||||||
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 scope.get_variable(identifier.span.str()).is_none() {
|
||||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
let err = error::Error::UnknownIdentifier(
|
||||||
identifier: identifier.span.clone(),
|
UnknownIdentifier::from_semantic_scope(
|
||||||
});
|
identifier.span.clone(),
|
||||||
|
scope,
|
||||||
|
),
|
||||||
|
);
|
||||||
handler.receive(err.clone());
|
handler.receive(err.clone());
|
||||||
errs.push(err);
|
errs.push(err);
|
||||||
}
|
}
|
||||||
|
@ -999,9 +1006,12 @@ impl TemplateStringLiteral {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
let err = error::Error::UnknownIdentifier(
|
||||||
identifier: identifier.span.clone(),
|
UnknownIdentifier::from_semantic_scope(
|
||||||
});
|
identifier.span.clone(),
|
||||||
|
scope,
|
||||||
|
),
|
||||||
|
);
|
||||||
handler.receive(err.clone());
|
handler.receive(err.clone());
|
||||||
errs.push(err);
|
errs.push(err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::{collections::HashMap, sync::RwLock};
|
use std::{collections::HashMap, sync::RwLock};
|
||||||
|
|
||||||
|
use crate::{base::source_file::Span, transpile::error::UnknownIdentifier};
|
||||||
|
|
||||||
/// Type of variable
|
/// Type of variable
|
||||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||||
pub enum VariableType {
|
pub enum VariableType {
|
||||||
|
@ -95,3 +97,29 @@ impl<'a> SemanticScope<'a> {
|
||||||
self.parent
|
self.parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UnknownIdentifier {
|
||||||
|
pub(super) fn from_semantic_scope(identifier: Span, scope: &SemanticScope<'_>) -> Self {
|
||||||
|
use itertools::Itertools as _;
|
||||||
|
|
||||||
|
let own_name = identifier.str();
|
||||||
|
let alternatives = scope
|
||||||
|
.get_all_variables()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(name, _)| {
|
||||||
|
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, name))
|
||||||
|
})
|
||||||
|
.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 {
|
||||||
|
identifier,
|
||||||
|
alternatives,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -303,11 +303,46 @@ impl std::error::Error for AssignmentError {}
|
||||||
pub struct UnknownIdentifier {
|
pub struct UnknownIdentifier {
|
||||||
/// The unknown identifier.
|
/// The unknown identifier.
|
||||||
#[get = "pub"]
|
#[get = "pub"]
|
||||||
pub identifier: Span,
|
pub(crate) identifier: Span,
|
||||||
|
/// Alternatives to the current identifier
|
||||||
|
#[get = "pub"]
|
||||||
|
pub(crate) alternatives: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnknownIdentifier {
|
||||||
|
#[cfg(feature = "shulkerbox")]
|
||||||
|
pub(crate) fn from_scope(
|
||||||
|
identifier: Span,
|
||||||
|
scope: &std::sync::Arc<super::variables::Scope>,
|
||||||
|
) -> Self {
|
||||||
|
use itertools::Itertools as _;
|
||||||
|
|
||||||
|
let own_name = identifier.str();
|
||||||
|
let alternatives = scope
|
||||||
|
.get_all_variables()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(name, _)| {
|
||||||
|
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, name))
|
||||||
|
})
|
||||||
|
.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 {
|
||||||
|
identifier,
|
||||||
|
alternatives,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
"{}",
|
"{}",
|
||||||
|
@ -317,10 +352,23 @@ impl Display for UnknownIdentifier {
|
||||||
)
|
)
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
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}`");
|
||||||
|
}
|
||||||
|
Some(message + "?")
|
||||||
|
};
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"\n{}",
|
"\n{}",
|
||||||
SourceCodeDisplay::new(&self.identifier, Option::<u8>::None)
|
SourceCodeDisplay::new(&self.identifier, help_message.as_ref())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1460,9 +1460,10 @@ impl Transpiler {
|
||||||
|
|
||||||
self.move_data(&from, target, primary, handler)
|
self.move_data(&from, target, primary, handler)
|
||||||
} else {
|
} else {
|
||||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||||
identifier: ident.span.clone(),
|
ident.span.clone(),
|
||||||
});
|
scope,
|
||||||
|
));
|
||||||
handler.receive(Box::new(err.clone()));
|
handler.receive(Box::new(err.clone()));
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
|
@ -1587,9 +1588,10 @@ impl Transpiler {
|
||||||
|
|
||||||
self.move_data(&from, target, primary, handler)
|
self.move_data(&from, target, primary, handler)
|
||||||
} else {
|
} else {
|
||||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||||
identifier: ident.span.clone(),
|
ident.span.clone(),
|
||||||
});
|
scope,
|
||||||
|
));
|
||||||
handler.receive(Box::new(err.clone()));
|
handler.receive(Box::new(err.clone()));
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
|
@ -1740,9 +1742,10 @@ impl Transpiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||||
identifier: ident.span.clone(),
|
ident.span.clone(),
|
||||||
});
|
scope,
|
||||||
|
));
|
||||||
handler.receive(Box::new(err.clone()));
|
handler.receive(Box::new(err.clone()));
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
|
@ -1816,9 +1819,10 @@ impl Transpiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||||
identifier: ident.span.clone(),
|
ident.span.clone(),
|
||||||
});
|
scope,
|
||||||
|
));
|
||||||
handler.receive(Box::new(err.clone()));
|
handler.receive(Box::new(err.clone()));
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -455,9 +455,7 @@ impl Transpiler {
|
||||||
let var =
|
let var =
|
||||||
scope.get_variable(ident.span.str()).ok_or_else(|| {
|
scope.get_variable(ident.span.str()).ok_or_else(|| {
|
||||||
let err =
|
let err =
|
||||||
TranspileError::UnknownIdentifier(UnknownIdentifier {
|
TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(ident.span(), scope));
|
||||||
identifier: ident.span(),
|
|
||||||
});
|
|
||||||
handler.receive(Box::new(err.clone()));
|
handler.receive(Box::new(err.clone()));
|
||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
|
|
|
@ -156,9 +156,9 @@ fn print_function(
|
||||||
))),
|
))),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(TranspileError::UnknownIdentifier(UnknownIdentifier {
|
Err(TranspileError::UnknownIdentifier(
|
||||||
identifier: ident.span(),
|
UnknownIdentifier::from_scope(ident.span(), scope),
|
||||||
}))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,9 +289,9 @@ fn print_function(
|
||||||
))),
|
))),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(TranspileError::UnknownIdentifier(UnknownIdentifier {
|
Err(TranspileError::UnknownIdentifier(
|
||||||
identifier: ident.span(),
|
UnknownIdentifier::from_scope(ident.span(), scope),
|
||||||
}))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -295,9 +295,9 @@ mod enabled {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
return Err(TranspileError::UnknownIdentifier(UnknownIdentifier {
|
return Err(TranspileError::UnknownIdentifier(
|
||||||
identifier: identifier.span(),
|
UnknownIdentifier::from_scope(identifier.span(), scope),
|
||||||
}));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -552,9 +552,10 @@ impl Transpiler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||||
identifier: ident.span.clone(),
|
ident.span.clone(),
|
||||||
});
|
scope,
|
||||||
|
));
|
||||||
handler.receive(Box::new(err.clone()));
|
handler.receive(Box::new(err.clone()));
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
@ -623,9 +624,10 @@ impl Transpiler {
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||||
identifier: ident.span.clone(),
|
ident.span.clone(),
|
||||||
});
|
scope,
|
||||||
|
));
|
||||||
handler.receive(Box::new(err.clone()));
|
handler.receive(Box::new(err.clone()));
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -326,9 +326,7 @@ impl TemplateStringLiteral {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let err =
|
let err =
|
||||||
TranspileError::UnknownIdentifier(UnknownIdentifier {
|
TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(identifier.span(), scope));
|
||||||
identifier: identifier.span(),
|
|
||||||
});
|
|
||||||
handler.receive(Box::new(err.clone()));
|
handler.receive(Box::new(err.clone()));
|
||||||
Err(err)
|
Err(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue