Skip to content

Commit

Permalink
remove ariadne, improve general error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
vincenthz committed Feb 5, 2024
1 parent 77872bf commit 8e12521
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 95 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ members = [
"werbolg-lang-lispy",
"werbolg-ir-write",
"werbolg-tests",
"werbolg-example1",
"werbolg-tales",
]
2 changes: 1 addition & 1 deletion werbolg-example1/src/lang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub enum Lang {
Rusty,
}

pub fn parse(lang: Lang, file: &FileUnit) -> Result<ir::Module, ParseError> {
pub fn parse(lang: Lang, file: &FileUnit) -> Result<ir::Module, Vec<ParseError>> {
match lang {
Lang::Lispy => {
#[cfg(feature = "lang-lispy")]
Expand Down
31 changes: 26 additions & 5 deletions werbolg-lang-lispy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,35 @@ use alloc::{boxed::Box, format, string::String, vec::Vec};
use ast::Ast;
use werbolg_core::{self as ir, spans_merge, Span, Spanned};

pub fn module(fileunit: &FileUnit) -> Result<ir::Module, ParseError> {
fn partition_map<I, T, E>(it: I) -> (Vec<T>, Vec<E>)
where
I: Iterator<Item = Result<T, E>>,
{
let mut ts = Vec::new();
let mut es = Vec::new();

for i in it {
match i {
Ok(t) => ts.push(t),
Err(e) => es.push(e),
}
}

(ts, es)
}

pub fn module(fileunit: &FileUnit) -> Result<ir::Module, Vec<ParseError>> {
let lex = parse::Lexer::new(&fileunit.content);
let parser = parse::Parser::new(lex);

let statements = parser
.into_iter()
.map(|re| re.map_err(remap_err).and_then(|e| statement(e)))
.collect::<Result<Vec<_>, _>>()?;
let (statements, errs) = partition_map(parser.into_iter());
if !errs.is_empty() {
return Err(errs.into_iter().map(remap_err).collect());
}
let (statements, errs) = partition_map(statements.into_iter().map(statement));
if !errs.is_empty() {
return Err(errs);
}

Ok(ir::Module { statements })
}
Expand Down
1 change: 0 additions & 1 deletion werbolg-lang-rusty/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ariadne = { version = "0.3" }
chumsky = { version = "0.9", features = [] }
logos = { version = "0.13" }
werbolg-lang-common = { path = "../werbolg-lang-common" }
Expand Down
58 changes: 54 additions & 4 deletions werbolg-lang-rusty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,63 @@ mod ast;
mod parse;
mod token;

use alloc::{boxed::Box, vec, vec::Vec};
use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
use werbolg_core::{self as ir, Spanned, Statement};

use werbolg_lang_common::{FileUnit, ParseError};
use werbolg_lang_common::{FileUnit, ParseError, ParseErrorKind};

pub fn module(fileunit: &FileUnit) -> Result<ir::Module, ParseError> {
let m = parse::module(&fileunit.content).map_err(|_| todo!())?;
fn simple_to_perr(e: chumsky::error::Simple<String>) -> ParseError {
match e.reason() {
chumsky::error::SimpleReason::Unclosed { span: _, delimiter } => ParseError {
context: None,
location: e.span(),
description: format!("Unclosed delimiter {}", delimiter),
note: Some(format!("delimiter must be closed before")),
kind: ParseErrorKind::Unknown,
},
chumsky::error::SimpleReason::Unexpected => {
let found = if e.found().is_some() {
"Unexpected token in input"
} else {
"Unexpected end of input"
};
let expected = if e.expected().len() == 0 {
String::from("Something else")
} else {
e.expected()
.map(|expected| match expected {
Some(expected) => String::from(expected),
None => String::from("end of input"),
})
.collect::<Vec<_>>()
.join(", ")
};
let description = format!("{}, expected {}", found, expected);
ParseError {
context: None,
location: e.span(),
description,
note: None,
kind: ParseErrorKind::Unknown,
}
}

chumsky::error::SimpleReason::Custom(msg) => ParseError {
context: None,
location: e.span(),
description: format!("{}", msg),
note: None,
kind: ParseErrorKind::Unknown,
},
}
}

pub fn module(fileunit: &FileUnit) -> Result<ir::Module, Vec<ParseError>> {
let m = parse::module(&fileunit.content).map_err(|errs| {
errs.into_iter()
.map(|err| simple_to_perr(err))
.collect::<Vec<_>>()
})?;

let statements = m
.into_iter()
Expand Down
76 changes: 5 additions & 71 deletions werbolg-lang-rusty/src/parse.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// this is chumsky nanorust example without the evaluation

use alloc::{boxed::Box, format, string::String, string::ToString, vec::Vec};
use ariadne::{Color, Fmt, Label, Report, ReportKind, Source};
use alloc::{boxed::Box, string::String, string::ToString, vec::Vec};
use chumsky::{prelude::*, stream::Stream};
use core::fmt;

Expand Down Expand Up @@ -389,7 +388,7 @@ fn funcs_parser() -> impl Parser<Token, Vec<(String, Span, Func)>, Error = Simpl
.then_ignore(end())
}

pub fn module(src: &str) -> Result<Vec<(String, Span, Func)>, ()> {
pub fn module(src: &str) -> Result<Vec<(String, Span, Func)>, Vec<Simple<String>>> {
let (tokens, errs) = lexer().parse_recovery(src);

let parse_errs = if let Some(tokens) = tokens {
Expand All @@ -405,74 +404,9 @@ pub fn module(src: &str) -> Result<Vec<(String, Span, Func)>, ()> {
Vec::new()
};

errs.into_iter()
Err(errs
.into_iter()
.map(|e| e.map(|c| c.to_string()))
.chain(parse_errs.into_iter().map(|e| e.map(|tok| tok.to_string())))
.for_each(|e| {
let report = Report::build(ReportKind::Error, (), e.span().start);

let report = match e.reason() {
chumsky::error::SimpleReason::Unclosed { span, delimiter } => report
.with_message(format!(
"Unclosed delimiter {}",
delimiter.fg(Color::Yellow)
))
.with_label(
Label::new(span.clone())
.with_message(format!(
"Unclosed delimiter {}",
delimiter.fg(Color::Yellow)
))
.with_color(Color::Yellow),
)
.with_label(
Label::new(e.span())
.with_message(format!(
"Must be closed before this {}",
e.found()
.unwrap_or(&"end of file".to_string())
.fg(Color::Red)
))
.with_color(Color::Red),
),
chumsky::error::SimpleReason::Unexpected => report
.with_message(format!(
"{}, expected {}",
if e.found().is_some() {
"Unexpected token in input"
} else {
"Unexpected end of input"
},
if e.expected().len() == 0 {
"something else".to_string()
} else {
e.expected()
.map(|expected| match expected {
Some(expected) => expected.to_string(),
None => "end of input".to_string(),
})
.collect::<Vec<_>>()
.join(", ")
}
))
.with_label(
Label::new(e.span())
.with_message(format!(
"Unexpected token {}",
e.found()
.unwrap_or(&"end of file".to_string())
.fg(Color::Red)
))
.with_color(Color::Red),
),
chumsky::error::SimpleReason::Custom(msg) => report.with_message(msg).with_label(
Label::new(e.span())
.with_message(format!("{}", msg.fg(Color::Red)))
.with_color(Color::Red),
),
};

report.finish().print(Source::from(&src)).unwrap();
});
Err(())
.collect())
}
27 changes: 18 additions & 9 deletions werbolg-tales/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,26 @@ pub fn run_frontend(
let source = get_file(&path)?;

let parsing_res = match params.frontend {
Frontend::Rusty => werbolg_lang_rusty::module(&source.file_unit),
Frontend::Lispy => werbolg_lang_lispy::module(&source.file_unit),
Some(Frontend::Rusty) => werbolg_lang_rusty::module(&source.file_unit),
Some(Frontend::Lispy) => werbolg_lang_lispy::module(&source.file_unit),
None => {
// work similar to auto detect
let parse1 = werbolg_lang_rusty::module(&source.file_unit);
let parse2 = werbolg_lang_lispy::module(&source.file_unit);

parse1.or_else(|_e1| parse2)
}
};
let module = match parsing_res {
Err(e) => {
let report = Report::new(ReportKind::Error, format!("Parse Error: {:?}", e))
.lines_before(1)
.lines_after(1)
.highlight(e.location, format!("parse error here"));

report_print(&source, report)?;
Err(es) => {
for e in es.into_iter() {
let report = Report::new(ReportKind::Error, format!("Parse Error: {:?}", e))
.lines_before(1)
.lines_after(1)
.highlight(e.location, format!("parse error here"));

report_print(&source, report)?;
}
return Err(format!("parse error").into());
}
Ok(module) => module,
Expand Down
3 changes: 1 addition & 2 deletions werbolg-tales/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ fn main() -> Result<(), Box<dyn Error>> {
Flag::Frontend(f) => Some(*f),
_ => None,
})
.last()
.unwrap_or(Frontend::Rusty);
.last();

let params = TalesParams {
dump_ir,
Expand Down
2 changes: 1 addition & 1 deletion werbolg-tales/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub struct TalesParams {
pub dump_instr: bool,
pub exec_step_trace: bool,
pub step_address: Vec<u64>,
pub frontend: Frontend,
pub frontend: Option<Frontend>,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
Expand Down

0 comments on commit 8e12521

Please sign in to comment.