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"
|
name = "hir"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"levenshtein",
|
||||||
"parser",
|
"parser",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -203,6 +204,12 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "levenshtein"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lexer"
|
name = "lexer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -116,5 +116,36 @@ impl Diagnostics {
|
||||||
|
|
||||||
report.finish().print(Source::from(&src)).unwrap();
|
report.finish().print(Source::from(&src)).unwrap();
|
||||||
}); // End errors reporting
|
}); // 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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
parser = { path = "../parser" }
|
parser = { path = "../parser" }
|
||||||
|
levenshtein = "1.0.5" # Used for error reporting
|
|
@ -29,7 +29,8 @@ pub struct IR {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LoweringError {
|
pub struct LoweringError {
|
||||||
pub span: Range<usize>,
|
pub span: Range<usize>,
|
||||||
pub message: String
|
pub message: String,
|
||||||
|
pub note: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IR {
|
impl IR {
|
||||||
|
@ -82,7 +83,7 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
||||||
let name = match &name.0 {
|
let name = match &name.0 {
|
||||||
Expr::Identifier(s) => s.clone(),
|
Expr::Identifier(s) => s.clone(),
|
||||||
// Should never happen because the parser should have caught this
|
// 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
|
let mut largs = Vec::new(); // `largs` stand for lowered args
|
||||||
// Iterate over args
|
// Iterate over args
|
||||||
|
@ -101,7 +102,7 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
||||||
if_err_return!(value.1);
|
if_err_return!(value.1);
|
||||||
|
|
||||||
let value = value.0.unwrap();
|
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);
|
return (Some(ir_kind), None);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -110,10 +111,14 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
|
||||||
Expr::Identifier(s) => {
|
Expr::Identifier(s) => {
|
||||||
if INTRINSICS.contains(&s.as_str()) { s.clone() }
|
if INTRINSICS.contains(&s.as_str()) { s.clone() }
|
||||||
else {
|
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();
|
let mut largs = Vec::new();
|
||||||
for arg in &args.0 {
|
for arg in &args.0 {
|
||||||
|
@ -193,4 +198,18 @@ fn gen_type_hint(type_hint: &str) -> String {
|
||||||
"string" => "std::string".to_string(),
|
"string" => "std::string".to_string(),
|
||||||
_ => { dbg!(type_hint); todo!() }
|
_ => { 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");
|
}).labelled("identifier");
|
||||||
|
|
||||||
let literal = filter_map(|span, token| match token {
|
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::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))),
|
_ => Err(Simple::expected_input_found(span, Vec::new(), Some(token))),
|
||||||
}).labelled("literal");
|
}).labelled("literal");
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
-- Can't use Int as identifier
|
fun main: int = do
|
||||||
let 123 = 123;
|
@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