parameterize Parser on an Error type

This commit is contained in:
Folkert 2021-02-07 22:08:28 +01:00
parent da28486184
commit 148fffe969
17 changed files with 372 additions and 271 deletions

View file

@ -2,9 +2,9 @@ use crate::ast::CommentOrNewline::{self, *};
use crate::ast::{Attempting, Spaceable};
use crate::parser::{
self, and, ascii_char, ascii_string, backtrackable, optional, parse_utf8, peek_utf8_char, then,
unexpected, unexpected_eof, FailReason, Parser,
unexpected, unexpected_eof, Parser,
Progress::{self, *},
State,
State, SyntaxError,
};
use bumpalo::collections::string::String;
use bumpalo::collections::vec::Vec;
@ -15,12 +15,15 @@ use roc_region::all::Located;
/// Returns a Located<Expr> where the location is around the Expr, ignoring the spaces.
/// If any newlines or comments were found, the Expr will be wrapped in a SpaceBefore and/or
/// SpaceAfter as appropriate.
pub fn space0_around<'a, P, S>(parser: P, min_indent: u16) -> impl Parser<'a, Located<S>>
pub fn space0_around<'a, P, S>(
parser: P,
min_indent: u16,
) -> impl Parser<'a, Located<S>, SyntaxError>
where
S: Spaceable<'a>,
S: 'a,
S: Sized,
P: Parser<'a, Located<S>>,
P: Parser<'a, Located<S>, SyntaxError>,
P: 'a,
{
parser::map_with_arena(
@ -62,11 +65,14 @@ where
/// Returns a Located<Expr> where the location is around the Expr, ignoring the spaces.
/// If any newlines or comments were found, the Expr will be wrapped in a SpaceBefore and/or
/// SpaceAfter as appropriate.
pub fn space1_around<'a, P, S>(parser: P, min_indent: u16) -> impl Parser<'a, Located<S>>
pub fn space1_around<'a, P, S>(
parser: P,
min_indent: u16,
) -> impl Parser<'a, Located<S>, SyntaxError>
where
S: Spaceable<'a>,
S: 'a,
P: Parser<'a, Located<S>>,
P: Parser<'a, Located<S>, SyntaxError>,
P: 'a,
{
parser::map_with_arena(
@ -100,11 +106,14 @@ where
/// Parses the given expression with 0 or more (spaces/comments/newlines) before it.
/// Returns a Located<Expr> where the location is around the Expr, ignoring the spaces.
/// The Expr will be wrapped in a SpaceBefore if there were any newlines or comments found.
pub fn space0_before<'a, P, S>(parser: P, min_indent: u16) -> impl Parser<'a, Located<S>>
pub fn space0_before<'a, P, S>(
parser: P,
min_indent: u16,
) -> impl Parser<'a, Located<S>, SyntaxError>
where
S: Spaceable<'a>,
S: 'a,
P: Parser<'a, Located<S>>,
P: Parser<'a, Located<S>, SyntaxError>,
P: 'a,
{
parser::map_with_arena(
@ -124,11 +133,14 @@ where
/// Parses the given expression with 1 or more (spaces/comments/newlines) before it.
/// Returns a Located<Expr> where the location is around the Expr, ignoring the spaces.
/// The Expr will be wrapped in a SpaceBefore if there were any newlines or comments found.
pub fn space1_before<'a, P, S>(parser: P, min_indent: u16) -> impl Parser<'a, Located<S>>
pub fn space1_before<'a, P, S>(
parser: P,
min_indent: u16,
) -> impl Parser<'a, Located<S>, SyntaxError>
where
S: Spaceable<'a>,
S: 'a,
P: Parser<'a, Located<S>>,
P: Parser<'a, Located<S>, SyntaxError>,
P: 'a,
{
parser::map_with_arena(
@ -148,11 +160,14 @@ where
/// Parses the given expression with 0 or more (spaces/comments/newlines) after it.
/// Returns a Located<Expr> where the location is around the Expr, ignoring the spaces.
/// The Expr will be wrapped in a SpaceAfter if there were any newlines or comments found.
pub fn space0_after<'a, P, S>(parser: P, min_indent: u16) -> impl Parser<'a, Located<S>>
pub fn space0_after<'a, P, S>(
parser: P,
min_indent: u16,
) -> impl Parser<'a, Located<S>, SyntaxError>
where
S: Spaceable<'a>,
S: 'a,
P: Parser<'a, Located<S>>,
P: Parser<'a, Located<S>, SyntaxError>,
P: 'a,
{
parser::map_with_arena(
@ -172,11 +187,14 @@ where
/// Parses the given expression with 1 or more (spaces/comments/newlines) after it.
/// Returns a Located<Expr> where the location is around the Expr, ignoring the spaces.
/// The Expr will be wrapped in a SpaceAfter if there were any newlines or comments found.
pub fn space1_after<'a, P, S>(parser: P, min_indent: u16) -> impl Parser<'a, Located<S>>
pub fn space1_after<'a, P, S>(
parser: P,
min_indent: u16,
) -> impl Parser<'a, Located<S>, SyntaxError>
where
S: Spaceable<'a>,
S: 'a,
P: Parser<'a, Located<S>>,
P: Parser<'a, Located<S>, SyntaxError>,
P: 'a,
{
parser::map_with_arena(
@ -194,12 +212,12 @@ where
}
/// Zero or more (spaces/comments/newlines).
pub fn space0<'a>(min_indent: u16) -> impl Parser<'a, &'a [CommentOrNewline<'a>]> {
pub fn space0<'a>(min_indent: u16) -> impl Parser<'a, &'a [CommentOrNewline<'a>], SyntaxError> {
spaces(false, min_indent)
}
/// One or more (spaces/comments/newlines).
pub fn space1<'a>(min_indent: u16) -> impl Parser<'a, &'a [CommentOrNewline<'a>]> {
pub fn space1<'a>(min_indent: u16) -> impl Parser<'a, &'a [CommentOrNewline<'a>], SyntaxError> {
// TODO try benchmarking a short-circuit for the typical case: see if there is
// exactly one space followed by char that isn't [' ', '\n', or '#'], and
// if so, return empty slice. The case where there's exactly 1 space should
@ -214,7 +232,7 @@ enum LineState {
DocComment,
}
pub fn line_comment<'a>() -> impl Parser<'a, &'a str> {
pub fn line_comment<'a>() -> impl Parser<'a, &'a str, SyntaxError> {
then(
and!(ascii_char(b'#'), optional(ascii_string("# "))),
|arena: &'a Bump, state: State<'a>, _, (_, opt_doc)| {
@ -242,7 +260,7 @@ pub fn line_comment<'a>() -> impl Parser<'a, &'a str> {
}
#[inline(always)]
pub fn spaces_exactly<'a>(spaces_expected: u16) -> impl Parser<'a, ()> {
pub fn spaces_exactly<'a>(spaces_expected: u16) -> impl Parser<'a, (), SyntaxError> {
move |arena: &'a Bump, state: State<'a>| {
if spaces_expected == 0 {
return Ok((NoProgress, (), state));
@ -269,10 +287,10 @@ pub fn spaces_exactly<'a>(spaces_expected: u16) -> impl Parser<'a, ()> {
));
}
Err(FailReason::BadUtf8) => {
Err(SyntaxError::BadUtf8) => {
// If we hit an invalid UTF-8 character, bail out immediately.
let progress = Progress::progress_when(spaces_seen != 0);
return state.fail(arena, progress, FailReason::BadUtf8);
return state.fail(arena, progress, SyntaxError::BadUtf8);
}
Err(_) => {
if spaces_seen == 0 {
@ -306,7 +324,7 @@ pub fn spaces_exactly<'a>(spaces_expected: u16) -> impl Parser<'a, ()> {
fn spaces<'a>(
require_at_least_one: bool,
min_indent: u16,
) -> impl Parser<'a, &'a [CommentOrNewline<'a>]> {
) -> impl Parser<'a, &'a [CommentOrNewline<'a>], SyntaxError> {
move |arena: &'a Bump, state: State<'a>| {
let original_state = state.clone();
let mut space_list = Vec::new_in(arena);
@ -478,10 +496,10 @@ fn spaces<'a>(
}
}
}
Err(FailReason::BadUtf8) => {
Err(SyntaxError::BadUtf8) => {
// If we hit an invalid UTF-8 character, bail out immediately.
let progress = Progress::from_lengths(start_bytes_len, state.bytes.len());
return state.fail(arena, progress, FailReason::BadUtf8);
return state.fail(arena, progress, SyntaxError::BadUtf8);
}
Err(_) => {
if require_at_least_one && bytes_parsed == 0 {