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);
|
||||
}
|
||||
} else {
|
||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: self.destination().span(),
|
||||
});
|
||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier::from_semantic_scope(
|
||||
self.destination().span(),
|
||||
scope,
|
||||
));
|
||||
handler.receive(err.clone());
|
||||
return Err(err);
|
||||
}
|
||||
|
@ -574,9 +575,9 @@ impl Primary {
|
|||
match self {
|
||||
Self::Identifier(ident) => {
|
||||
if scope.get_variable(ident.span.str()).is_none() {
|
||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span.clone(),
|
||||
});
|
||||
let err = error::Error::UnknownIdentifier(
|
||||
UnknownIdentifier::from_semantic_scope(ident.span.clone(), scope),
|
||||
);
|
||||
handler.receive(err.clone());
|
||||
Err(err)
|
||||
} else {
|
||||
|
@ -589,9 +590,12 @@ impl Primary {
|
|||
let var = scope.get_variable(call.identifier().span.str());
|
||||
var.map_or_else(
|
||||
|| {
|
||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: call.identifier().span.clone(),
|
||||
});
|
||||
let err = error::Error::UnknownIdentifier(
|
||||
UnknownIdentifier::from_semantic_scope(
|
||||
call.identifier().span.clone(),
|
||||
scope,
|
||||
),
|
||||
);
|
||||
handler.receive(err.clone());
|
||||
Err(err)
|
||||
},
|
||||
|
@ -661,8 +665,8 @@ impl Primary {
|
|||
Err(err)
|
||||
}
|
||||
}
|
||||
Self::MemberAccess(_) => {
|
||||
// TODO:
|
||||
Self::MemberAccess(member_access) => {
|
||||
member_access.parent().analyze_semantics(scope, handler)?;
|
||||
Ok(())
|
||||
}
|
||||
Self::Parenthesized(expr) => expr.analyze_semantics(scope, handler),
|
||||
|
@ -971,9 +975,12 @@ impl TemplateStringLiteral {
|
|||
match expression.as_ref() {
|
||||
Expression::Primary(Primary::Identifier(identifier)) => {
|
||||
if scope.get_variable(identifier.span.str()).is_none() {
|
||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: identifier.span.clone(),
|
||||
});
|
||||
let err = error::Error::UnknownIdentifier(
|
||||
UnknownIdentifier::from_semantic_scope(
|
||||
identifier.span.clone(),
|
||||
scope,
|
||||
),
|
||||
);
|
||||
handler.receive(err.clone());
|
||||
errs.push(err);
|
||||
}
|
||||
|
@ -999,9 +1006,12 @@ impl TemplateStringLiteral {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let err = error::Error::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: identifier.span.clone(),
|
||||
});
|
||||
let err = error::Error::UnknownIdentifier(
|
||||
UnknownIdentifier::from_semantic_scope(
|
||||
identifier.span.clone(),
|
||||
scope,
|
||||
),
|
||||
);
|
||||
handler.receive(err.clone());
|
||||
errs.push(err);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::{collections::HashMap, sync::RwLock};
|
||||
|
||||
use crate::{base::source_file::Span, transpile::error::UnknownIdentifier};
|
||||
|
||||
/// Type of variable
|
||||
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
|
||||
pub enum VariableType {
|
||||
|
@ -95,3 +97,29 @@ impl<'a> SemanticScope<'a> {
|
|||
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 {
|
||||
/// The unknown identifier.
|
||||
#[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 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use std::fmt::Write as _;
|
||||
|
||||
write!(
|
||||
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!(
|
||||
f,
|
||||
"\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)
|
||||
} else {
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span.clone(),
|
||||
});
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||
ident.span.clone(),
|
||||
scope,
|
||||
));
|
||||
handler.receive(Box::new(err.clone()));
|
||||
Err(err)
|
||||
}
|
||||
|
@ -1587,9 +1588,10 @@ impl Transpiler {
|
|||
|
||||
self.move_data(&from, target, primary, handler)
|
||||
} else {
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span.clone(),
|
||||
});
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||
ident.span.clone(),
|
||||
scope,
|
||||
));
|
||||
handler.receive(Box::new(err.clone()));
|
||||
Err(err)
|
||||
}
|
||||
|
@ -1740,9 +1742,10 @@ impl Transpiler {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span.clone(),
|
||||
});
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||
ident.span.clone(),
|
||||
scope,
|
||||
));
|
||||
handler.receive(Box::new(err.clone()));
|
||||
Err(err)
|
||||
}
|
||||
|
@ -1816,9 +1819,10 @@ impl Transpiler {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span.clone(),
|
||||
});
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||
ident.span.clone(),
|
||||
scope,
|
||||
));
|
||||
handler.receive(Box::new(err.clone()));
|
||||
Err(err)
|
||||
}
|
||||
|
|
|
@ -455,9 +455,7 @@ impl Transpiler {
|
|||
let var =
|
||||
scope.get_variable(ident.span.str()).ok_or_else(|| {
|
||||
let err =
|
||||
TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span(),
|
||||
});
|
||||
TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(ident.span(), scope));
|
||||
handler.receive(Box::new(err.clone()));
|
||||
err
|
||||
})?;
|
||||
|
|
|
@ -156,9 +156,9 @@ fn print_function(
|
|||
))),
|
||||
}
|
||||
} else {
|
||||
Err(TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span(),
|
||||
}))
|
||||
Err(TranspileError::UnknownIdentifier(
|
||||
UnknownIdentifier::from_scope(ident.span(), scope),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,9 +289,9 @@ fn print_function(
|
|||
))),
|
||||
}
|
||||
} else {
|
||||
Err(TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span(),
|
||||
}))
|
||||
Err(TranspileError::UnknownIdentifier(
|
||||
UnknownIdentifier::from_scope(ident.span(), scope),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -295,9 +295,9 @@ mod enabled {
|
|||
}));
|
||||
}
|
||||
None => {
|
||||
return Err(TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: identifier.span(),
|
||||
}));
|
||||
return Err(TranspileError::UnknownIdentifier(
|
||||
UnknownIdentifier::from_scope(identifier.span(), scope),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -552,9 +552,10 @@ impl Transpiler {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span.clone(),
|
||||
});
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||
ident.span.clone(),
|
||||
scope,
|
||||
));
|
||||
handler.receive(Box::new(err.clone()));
|
||||
return Err(err);
|
||||
}
|
||||
|
@ -623,9 +624,10 @@ impl Transpiler {
|
|||
Err(err)
|
||||
}
|
||||
None => {
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: ident.span.clone(),
|
||||
});
|
||||
let err = TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(
|
||||
ident.span.clone(),
|
||||
scope,
|
||||
));
|
||||
handler.receive(Box::new(err.clone()));
|
||||
Err(err)
|
||||
}
|
||||
|
|
|
@ -326,9 +326,7 @@ impl TemplateStringLiteral {
|
|||
}
|
||||
} else {
|
||||
let err =
|
||||
TranspileError::UnknownIdentifier(UnknownIdentifier {
|
||||
identifier: identifier.span(),
|
||||
});
|
||||
TranspileError::UnknownIdentifier(UnknownIdentifier::from_scope(identifier.span(), scope));
|
||||
handler.receive(Box::new(err.clone()));
|
||||
Err(err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue