Record raw strings during parse step

This commit is contained in:
Richard Feldman 2019-09-16 00:25:31 -04:00
parent fa9e074488
commit d54cf81f7b
40 changed files with 4111 additions and 7400 deletions

View file

@ -1,7 +1,7 @@
use bumpalo::collections::vec::Vec;
use bumpalo::Bump;
use parse::ast::Attempting;
use region::Region;
use region::{Located, Region};
use std::char;
// Strategy:
@ -190,6 +190,21 @@ pub trait Parser<'a, Output> {
fn parse(&self, &'a Bump, State<'a>) -> ParseResult<'a, Output>;
}
pub struct BoxedParser<'a, Output> {
parser: &'a (dyn Parser<'a, Output> + 'a),
}
impl<'a, Output> BoxedParser<'a, Output> {
fn new<P>(arena: &'a Bump, parser: P) -> Self
where
P: Parser<'a, Output> + 'a,
{
BoxedParser {
parser: arena.alloc(parser),
}
}
}
impl<'a, F, Output> Parser<'a, Output> for F
where
F: Fn(&'a Bump, State<'a>) -> ParseResult<'a, Output>,
@ -199,6 +214,22 @@ where
}
}
pub fn val<'a, Val>(value: Val) -> impl Parser<'a, Val>
where
Val: Clone,
{
move |_, state| Ok((value.clone(), state))
}
/// Needed for recursive parsers
pub fn lazy<'a, F, P, Val>(get_parser: F) -> impl Parser<'a, Val>
where
F: Fn() -> P,
P: Parser<'a, Val>,
{
move |arena, state| get_parser().parse(arena, state)
}
pub fn map<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
where
P: Parser<'a, Before>,
@ -211,6 +242,18 @@ where
}
}
pub fn map_with_arena<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
where
P: Parser<'a, Before>,
F: Fn(&'a Bump, Before) -> After,
{
move |arena, state| {
parser
.parse(arena, state)
.map(|(output, next_state)| (transform(arena, output), next_state))
}
}
pub fn attempt<'a, P, Val>(attempting: Attempting, parser: P) -> impl Parser<'a, Val>
where
P: Parser<'a, Val>,
@ -226,6 +269,32 @@ where
}
}
pub fn loc<'a, P, Val>(parser: P) -> impl Parser<'a, Located<Val>>
where
P: Parser<'a, Val>,
{
move |arena, state: State<'a>| {
let start_col = state.column;
let start_line = state.line;
match parser.parse(arena, state) {
Ok((value, state)) => {
let end_col = state.column;
let end_line = state.line;
let region = Region {
start_col,
start_line,
end_col,
end_line,
};
Ok((Located { region, value }, state))
}
Err((fail, state)) => Err((fail, state)),
}
}
}
pub fn one_or_more<'a, P, A>(parser: P) -> impl Parser<'a, Vec<'a, A>>
where
P: Parser<'a, A>,
@ -317,6 +386,7 @@ pub fn string<'a>(string: &'static str) -> impl Parser<'a, ()> {
let input = state.input;
let len = string.len();
// TODO do this comparison in one SIMD instruction (on supported systems)
match input.get(0..len) {
Some(next_str) if next_str == string => Ok(((), state.advance_without_indenting(len)?)),
_ => Err(unexpected_eof(len, Attempting::Keyword, state)),
@ -378,6 +448,46 @@ where
// satisfies(any, |ch| ch.is_whitespace())
// }
pub fn and<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, (A, B)>
where
P1: Parser<'a, A>,
P2: Parser<'a, B>,
{
move |arena: &'a Bump, state: State<'a>| {
let original_attempting = state.attempting;
match p1.parse(arena, state) {
Ok((out1, state)) => match p2.parse(arena, state) {
Ok((out2, state)) => Ok(((out1, out2), state)),
Err((fail, state)) => Err((
Fail {
attempting: original_attempting,
..fail
},
state,
)),
},
Err((fail, state)) => Err((
Fail {
attempting: original_attempting,
..fail
},
state,
)),
}
}
}
pub fn optional<'a, P, T>(parser: P) -> impl Parser<'a, Option<T>>
where
P: Parser<'a, T>,
{
move |arena: &'a Bump, state: State<'a>| match parser.parse(arena, state) {
Ok((out1, state)) => Ok((Some(out1), state)),
Err((_, state)) => Ok((None, state)),
}
}
pub fn one_of2<'a, P1, P2, A>(p1: P1, p2: P2) -> impl Parser<'a, A>
where
P1: Parser<'a, A>,