Skip to content

Error recovery using lexer parser separation #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 21 commits into
base: 0.6.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ yansi = "0.5"
walkdir = "2"
typed-builder = "0.11"
indexmap = "1"
sequence_trie = { git = "https://github.com/jac3km4/rust_sequence_trie", rev = "a056b4c", features = ["hashbrown"] }
sequence_trie = { git = "https://github.com/jac3km4/rust_sequence_trie", rev = "a056b4c", features = [
"hashbrown",
] }
simple-interner = { version = "0.3", features = ["hashbrown"] }
peg = "0.8"
nom = "7.1"
nom_locate = "4.0"
paste = "1"
bumpalo = "3.11"
num = "0.4"
104 changes: 104 additions & 0 deletions compiler/src/comb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use std::ops::RangeTo;

use nom::error::ParseError;
use nom::{IResult, Offset, Slice};

/// Matches while open, close, or inner. Returns the matched range.
/// Input is matched, recursively descending, until open and close are balanced.
pub fn many_till_balanced1<I, O1, O2, E>(
mut open: impl FnMut(I) -> IResult<I, O1, E>,
mut inner: impl FnMut(I) -> IResult<I, I, E>,
mut close: impl FnMut(I) -> IResult<I, O2, E>,
) -> impl FnMut(I) -> IResult<I, I, E>
where
I: Clone + Offset + Slice<RangeTo<usize>>,
E: ParseError<I>,
{
move |start: I| {
let mut open_count = 0usize;
let mut close_count = 0usize;
let mut rem = start.clone();
let mut end = start.clone();
loop {
if let Ok((rem2, _)) = open(rem.clone()) {
open_count += 1;
rem = rem2;
} else if let Ok((rem2, _)) = close(rem.clone()) {
close_count += 1;
rem = rem2;
} else if let Ok((rem2, _)) = inner(rem.clone()) {
rem = rem2;
} else {
break;
}
if open_count == close_count {
end = rem.clone();
break;
}
}
let len = end.offset(&start);
if len == 0 {
Err(nom::Err::Error(E::from_error_kind(start, nom::error::ErrorKind::Many1)))
} else {
Ok((rem, start.slice(..len)))
}
}
}

pub fn delimited_list0<I, O1, O2, E>(
mut open: impl FnMut(I) -> IResult<I, O1, E>,
mut separator: impl FnMut(I) -> IResult<I, O1, E>,
mut inner: impl FnMut(I) -> IResult<I, O2, E>,
mut close: impl FnMut(I) -> IResult<I, O1, E>,
) -> impl FnMut(I) -> IResult<I, (O1, Vec<(O2, O1)>), E>
where
I: Clone,
E: ParseError<I>,
{
move |is| {
let (mut i, ss) = open(is)?;

let mut parts = vec![];
while let Ok((ip, ep)) = inner(i.clone()) {
if let Ok((ip, sp)) = separator(ip.clone()) {
parts.push((ep, sp));
i = ip;
continue;
} else if let Ok((ip, se)) = close(ip) {
parts.push((ep, se));
i = ip;
break;
}
// missing close match
return Err(nom::Err::Error(E::from_error_kind(
i,
nom::error::ErrorKind::TagClosure,
)));
}
return Ok((i, (ss, parts)));
}
}

pub fn variant<I, T, E>(expected: T) -> impl FnMut(I) -> IResult<I, I, E>
where
I: Clone,
T: Parsable<I, E> + PartialEq,
E: ParseError<I>,
{
move |i| {
let (i, (o, value)) = T::parse(i)?;
if value == expected {
Ok((i, o))
} else {
Err(nom::Err::Error(E::from_error_kind(i, nom::error::ErrorKind::Verify)))
}
}
}

pub trait Parsable<I, E>: Sized
where
I: Clone,
E: ParseError<I>,
{
fn parse(i: I) -> IResult<I, (I, Self), E>;
}
Loading