mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
lowering error report
This commit is contained in:
parent
a19f118510
commit
5c2e3048df
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -184,6 +184,7 @@ dependencies = [
|
|||
name = "hir"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"levenshtein",
|
||||
"parser",
|
||||
]
|
||||
|
||||
|
@ -203,6 +204,12 @@ version = "1.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "levenshtein"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
|
||||
|
||||
[[package]]
|
||||
name = "lexer"
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -116,5 +116,36 @@ impl Diagnostics {
|
|||
|
||||
report.finish().print(Source::from(&src)).unwrap();
|
||||
}); // End errors reporting
|
||||
|
||||
let lower_error = self.errors.iter().filter_map(|kind| match kind {
|
||||
Kind::LoweringError(error) => Some(error.clone()),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
lower_error.into_iter()
|
||||
.for_each(|e| {
|
||||
let span = &e.span;
|
||||
let message = &e.message;
|
||||
|
||||
let report = Report::build(ReportKind::Error, (), span.start)
|
||||
.with_message(
|
||||
format!("{}", message)
|
||||
)
|
||||
.with_label(
|
||||
Label::new(span.clone())
|
||||
.with_message(
|
||||
format!("{}", message)
|
||||
)
|
||||
.with_color(Color::Red)
|
||||
);
|
||||
|
||||
if let Some(note) = &e.note {
|
||||
report
|
||||
.with_note(note)
|
||||
.finish().print(Source::from(&src)).unwrap();
|
||||
} else {
|
||||
report.finish().print(Source::from(&src)).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -7,4 +7,5 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
parser = { path = "../parser" }
|
||||
parser = { path = "../parser" }
|
||||
levenshtein = "1.0.5" # Used for error reporting
|
|
@ -29,7 +29,8 @@ pub struct IR {
|
|||
#[derive(Debug)]
|
||||
pub struct LoweringError {
|
||||
pub span: Range<usize>,
|
||||
pub message: String
|
||||
pub message: String,
|
||||
pub note: Option<String>,
|
||||
}
|
||||
|
||||
impl IR {
|
||||
|
@ -82,7 +83,7 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
|||
let name = match &name.0 {
|
||||
Expr::Identifier(s) => s.clone(),
|
||||
// Should never happen because the parser should have caught this
|
||||
_ => return (None, Some(LoweringError { span: name.1.clone(), message: "Expected identifier".to_string() }))
|
||||
_ => return (None, Some(LoweringError { span: name.1.clone(), message: "Expected identifier".to_string(), note: None }))
|
||||
};
|
||||
let mut largs = Vec::new(); // `largs` stand for lowered args
|
||||
// Iterate over args
|
||||
|
@ -101,7 +102,7 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
|||
if_err_return!(value.1);
|
||||
|
||||
let value = value.0.unwrap();
|
||||
let ir_kind = IRKind::Define { name: name.clone(), type_hint: type_hint.clone(), value: Box::new(value) };
|
||||
let ir_kind = IRKind::Define { name: name.clone(), type_hint: gen_type_hint(type_hint), value: Box::new(value) };
|
||||
return (Some(ir_kind), None);
|
||||
},
|
||||
|
||||
|
@ -110,10 +111,14 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
|||
Expr::Identifier(s) => {
|
||||
if INTRINSICS.contains(&s.as_str()) { s.clone() }
|
||||
else {
|
||||
return (None, Some(LoweringError { span: name.1.clone(), message: format!("Unknown intrinsic: {}", s) }));
|
||||
return (None, Some(LoweringError {
|
||||
span: name.1.clone(),
|
||||
message: format!("Unknown intrinsic: `{}`", s),
|
||||
note: Some(format!("Did you mean: {}?", closet_intrinsic(s.to_string())))
|
||||
}));
|
||||
}
|
||||
}
|
||||
_ => return (None, Some(LoweringError { span: name.1.clone(), message: "Expected identifier".to_string() }))
|
||||
_ => return (None, Some(LoweringError { span: name.1.clone(), message: "Expected identifier".to_string(), note: None }))
|
||||
};
|
||||
let mut largs = Vec::new();
|
||||
for arg in &args.0 {
|
||||
|
@ -193,4 +198,18 @@ fn gen_type_hint(type_hint: &str) -> String {
|
|||
"string" => "std::string".to_string(),
|
||||
_ => { dbg!(type_hint); todo!() }
|
||||
}
|
||||
}
|
||||
|
||||
// Get the closet intrinsic name to the given name
|
||||
fn closet_intrinsic(got: String) -> String {
|
||||
let mut closest = String::new();
|
||||
let mut closest_dist = std::usize::MAX;
|
||||
for intrinsic in INTRINSICS.iter() {
|
||||
let dist = levenshtein::levenshtein(got.as_str(), intrinsic);
|
||||
if dist < closest_dist {
|
||||
closest = intrinsic.to_string();
|
||||
closest_dist = dist;
|
||||
}
|
||||
}
|
||||
closest
|
||||
}
|
|
@ -43,9 +43,9 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
|
|||
}).labelled("identifier");
|
||||
|
||||
let literal = filter_map(|span, token| match token {
|
||||
Token::Int(i) => Ok((Expr::Int(i), span)),
|
||||
Token::Int(i) => Ok((Expr::Int(i), span)),
|
||||
Token::Boolean(b) => Ok((Expr::Boolean(b), span)),
|
||||
Token::String(s) => Ok((Expr::String(s), span)),
|
||||
Token::String(s) => Ok((Expr::String(s), span)),
|
||||
_ => Err(Simple::expected_input_found(span, Vec::new(), Some(token))),
|
||||
}).labelled("literal");
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
-- Can't use Int as identifier
|
||||
let 123 = 123;
|
||||
fun main: int = do
|
||||
@writse(); -- Unknown intrinsic
|
||||
end;
|
9
example/readwrite.hz
Normal file
9
example/readwrite.hz
Normal file
|
@ -0,0 +1,9 @@
|
|||
fun main: int = do
|
||||
@write("Enter your name: ");
|
||||
let name: string = "";
|
||||
@read(name);
|
||||
|
||||
@write("Hello ");
|
||||
@write(name);
|
||||
@write("!");
|
||||
end;
|
Loading…
Reference in a new issue