factor out backtracking in def parsing

This commit is contained in:
Folkert 2021-02-04 21:34:28 +01:00
parent 438a2e6f83
commit aac75c6a25

View file

@ -500,38 +500,74 @@ fn equals_for_def<'a>() -> impl Parser<'a, ()> {
/// * A type annotation /// * A type annotation
/// * A type annotation followed on the next line by a pattern, an `=`, and an expression /// * A type annotation followed on the next line by a pattern, an `=`, and an expression
pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> { pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
// we should fix this backtracking! let indented_more = min_indent + 1;
enum DefKind {
DefColon,
DefEqual,
}
let def_colon_or_equals = one_of![
map!(equals_for_def(), |_| DefKind::DefEqual),
map!(ascii_char(b':'), |_| DefKind::DefColon)
];
attempt( attempt(
Attempting::Def, Attempting::Def,
map_with_arena!( then(
either!(backtrackable(annotated_body(min_indent)), body(min_indent)), backtrackable(and!(pattern(min_indent), def_colon_or_equals)),
to_def move |arena, state, _progress, (loc_pattern, def_kind)| match def_kind {
), DefKind::DefColon => {
) // Spaces after the ':' (at a normal indentation level) and then the type.
} // The type itself must be indented more than the pattern and ':'
let (_, ann_type, state) =
space0_before(type_annotation::located(indented_more), min_indent)
.parse(arena, state)?;
fn to_def<'a>( // see if there is a definition (assuming the preceding characters were a type
arena: &'a Bump, // annotation
ann_body_or_body: Either<AnnotationOrAnnotatedBody<'a>, Body<'a>>, let (_, opt_rest, state) = optional(and!(
) -> Def<'a> { spaces_then_comment_or_newline(),
match ann_body_or_body { body_at_indent(min_indent)
Either::First(((ann_pattern, ann_type), None)) => { ))
annotation_or_alias(arena, &ann_pattern.value, ann_pattern.region, ann_type) .parse(arena, state)?;
}
Either::First(( let def = match opt_rest {
(ann_pattern, ann_type), None => annotation_or_alias(
Some((opt_comment, (body_pattern, body_expr))), arena,
)) => Def::AnnotatedBody { &loc_pattern.value,
ann_pattern: arena.alloc(ann_pattern), loc_pattern.region,
ann_type,
),
Some((opt_comment, (body_pattern, body_expr))) => Def::AnnotatedBody {
ann_pattern: arena.alloc(loc_pattern),
ann_type: arena.alloc(ann_type), ann_type: arena.alloc(ann_type),
comment: opt_comment, comment: opt_comment,
body_pattern: arena.alloc(body_pattern), body_pattern: arena.alloc(body_pattern),
body_expr: arena.alloc(body_expr), body_expr: arena.alloc(body_expr),
}, },
Either::Second((body_pattern, body_expr)) => { };
Def::Body(arena.alloc(body_pattern), arena.alloc(body_expr))
Ok((MadeProgress, def, state))
} }
DefKind::DefEqual => {
// Spaces after the '=' (at a normal indentation level) and then the expr.
// The expr itself must be indented more than the pattern and '='
let (_, body_expr, state) = space0_before(
loc!(move |arena, state| { parse_expr(indented_more, arena, state) }),
min_indent,
)
.parse(arena, state)?;
Ok((
MadeProgress,
Def::Body(arena.alloc(loc_pattern), arena.alloc(body_expr)),
state,
))
} }
},
),
)
} }
// PARSER HELPERS // PARSER HELPERS
@ -540,21 +576,6 @@ fn pattern<'a>(min_indent: u16) -> impl Parser<'a, Located<Pattern<'a>>> {
space0_after(loc_closure_param(min_indent), min_indent) space0_after(loc_closure_param(min_indent), min_indent)
} }
fn annotation<'a>(
min_indent: u16,
) -> impl Parser<'a, (Located<Pattern<'a>>, Located<TypeAnnotation<'a>>)> {
let indented_more = min_indent + 1;
and!(
pattern(min_indent),
skip_first!(
ascii_char(b':'),
// Spaces after the ':' (at a normal indentation level) and then the type.
// The type itself must be indented more than the pattern and ':'
space0_before(type_annotation::located(indented_more), min_indent)
)
)
}
fn spaces_then_comment_or_newline<'a>() -> impl Parser<'a, Option<&'a str>> { fn spaces_then_comment_or_newline<'a>() -> impl Parser<'a, Option<&'a str>> {
skip_first!( skip_first!(
zero_or_more!(ascii_char(b' ')), zero_or_more!(ascii_char(b' ')),
@ -570,29 +591,6 @@ fn spaces_then_comment_or_newline<'a>() -> impl Parser<'a, Option<&'a str>> {
type Body<'a> = (Located<Pattern<'a>>, Located<Expr<'a>>); type Body<'a> = (Located<Pattern<'a>>, Located<Expr<'a>>);
fn body<'a>(min_indent: u16) -> impl Parser<'a, Body<'a>> {
let indented_more = min_indent + 1;
and!(
// this backtrackable is required for the case
//
// i = 64
//
// i
//
// so the final i is not considered the start of a def
backtrackable(pattern(min_indent)),
skip_first!(
equals_for_def(),
// Spaces after the '=' (at a normal indentation level) and then the expr.
// The expr itself must be indented more than the pattern and '='
space0_before(
loc!(move |arena, state| { parse_expr(indented_more, arena, state) }),
min_indent,
)
)
)
}
fn body_at_indent<'a>(indent_level: u16) -> impl Parser<'a, Body<'a>> { fn body_at_indent<'a>(indent_level: u16) -> impl Parser<'a, Body<'a>> {
let indented_more = indent_level + 1; let indented_more = indent_level + 1;
and!( and!(
@ -609,21 +607,6 @@ fn body_at_indent<'a>(indent_level: u16) -> impl Parser<'a, Body<'a>> {
) )
} }
type AnnotationOrAnnotatedBody<'a> = (
(Located<Pattern<'a>>, Located<TypeAnnotation<'a>>),
Option<(Option<&'a str>, Body<'a>)>,
);
fn annotated_body<'a>(min_indent: u16) -> impl Parser<'a, AnnotationOrAnnotatedBody<'a>> {
and!(
annotation(min_indent),
optional(and!(
spaces_then_comment_or_newline(),
body_at_indent(min_indent)
))
)
}
fn annotation_or_alias<'a>( fn annotation_or_alias<'a>(
arena: &'a Bump, arena: &'a Bump,
pattern: &Pattern<'a>, pattern: &Pattern<'a>,