Revise parse::ast::Defs

Add Nested, drop CustomType and TypeAlias
This commit is contained in:
Richard Feldman 2019-12-04 21:33:04 -05:00
parent 1a88c03b95
commit 19885d32c1
3 changed files with 40 additions and 82 deletions

View file

@ -5,23 +5,24 @@ use crate::parse::ast::Def;
use bumpalo::collections::String; use bumpalo::collections::String;
pub fn fmt_def<'a>(buf: &mut String<'a>, def: &'a Def<'a>, indent: u16) { pub fn fmt_def<'a>(buf: &mut String<'a>, def: &'a Def<'a>, indent: u16) {
use crate::parse::ast::Def::*;
match def { match def {
Def::Annotation(_, _) => panic!("TODO have format_def support Annotation"), Annotation(_, _) => panic!("TODO have format_def support Annotation"),
Def::Body(loc_pattern, loc_expr) => { Body(loc_pattern, loc_expr) => {
fmt_pattern(buf, &loc_pattern.value, indent, true); fmt_pattern(buf, &loc_pattern.value, indent, true);
buf.push_str(" = "); buf.push_str(" = ");
fmt_expr(buf, &loc_expr.value, indent, false); fmt_expr(buf, &loc_expr.value, indent, false);
} }
Def::CustomType(_, _) => panic!("TODO have format_def support CustomType"), SpaceBefore(sub_def, spaces) => {
Def::TypeAlias(_, _) => panic!("TODO have format_def support TypeAlias"),
Def::SpaceBefore(sub_def, spaces) => {
fmt_spaces(buf, spaces.iter(), indent); fmt_spaces(buf, spaces.iter(), indent);
fmt_def(buf, sub_def, indent); fmt_def(buf, sub_def, indent);
} }
Def::SpaceAfter(sub_def, spaces) => { SpaceAfter(sub_def, spaces) => {
fmt_def(buf, sub_def, indent); fmt_def(buf, sub_def, indent);
fmt_spaces(buf, spaces.iter(), indent); fmt_spaces(buf, spaces.iter(), indent);
} }
Nested(def) => fmt_def(buf, def, indent),
} }
} }

View file

@ -184,17 +184,16 @@ pub enum Def<'a> {
// annotation; if not, and if it's followed by a Body, then the annotation // annotation; if not, and if it's followed by a Body, then the annotation
// applies to that expr! (TODO: verify that the pattern for both annotation and body match.) // applies to that expr! (TODO: verify that the pattern for both annotation and body match.)
// No need to track that relationship in any data structure. // No need to track that relationship in any data structure.
Body(Loc<Pattern<'a>>, &'a Loc<Expr<'a>>), Body(&'a Loc<Pattern<'a>>, &'a Loc<Expr<'a>>),
// TODO also in canonicalization, if there is a CustomType or TypeAlias
// inside an Expr, give an error like "hey you need to move this to the
// top level" - it'll parse fine, we just won't accept it there.
CustomType(Loc<TypeAnnotation<'a>>, Vec<'a, Loc<TypeAnnotation<'a>>>),
TypeAlias(Loc<TypeAnnotation<'a>>, Loc<TypeAnnotation<'a>>),
// Blank Space (e.g. comments, spaces, newlines) before or after a def. // Blank Space (e.g. comments, spaces, newlines) before or after a def.
// We preserve this for the formatter; canonicalization ignores it. // We preserve this for the formatter; canonicalization ignores it.
SpaceBefore(&'a Def<'a>, &'a [CommentOrNewline<'a>]), SpaceBefore(&'a Def<'a>, &'a [CommentOrNewline<'a>]),
SpaceAfter(&'a Def<'a>, &'a [CommentOrNewline<'a>]), SpaceAfter(&'a Def<'a>, &'a [CommentOrNewline<'a>]),
/// This is used only to avoid cloning when reordering expressions (e.g. in desugar()).
/// It lets us take a (&Def) and create a plain (Def) from it.
Nested(&'a Def<'a>),
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]

View file

@ -413,77 +413,35 @@ pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
// Indented more beyond the original indent. // Indented more beyond the original indent.
let indented_more = min_indent + 1; let indented_more = min_indent + 1;
one_of!( // Constant or annotation
// Constant or annotation map_with_arena!(
map_with_arena!( and!(
and!( // A pattern followed by '=' or ':'
// A pattern followed by '=' or ':' space0_after(loc_closure_param(min_indent), min_indent),
space0_after(loc_closure_param(min_indent), min_indent), either!(
either!( // Constant
// Constant skip_first!(
skip_first!( equals_for_def(),
equals_for_def(), // Spaces after the '=' (at a normal indentation level) and then the expr.
// Spaces after the '=' (at a normal indentation level) and then the expr. // The expr itself must be indented more than the pattern and '='
// The expr itself must be indented more than the pattern and '=' space0_before(
space0_before( loc!(move |arena, state| parse_expr(indented_more, arena, state)),
loc!(move |arena, state| parse_expr(indented_more, arena, state)), min_indent,
min_indent,
)
),
// Annotation
skip_first!(
char(':'),
// 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), indented_more)
) )
)
),
|arena: &'a Bump, (loc_pattern, expr_or_ann)| match expr_or_ann {
Either::First(loc_expr) => Def::Body(loc_pattern, arena.alloc(loc_expr)),
Either::Second(loc_ann) => Def::Annotation(loc_pattern, loc_ann),
}
),
// Type alias or custom type (uppercase ident followed by `:` or `:=` and type annotation)
map!(
and!(
skip_second!(
// TODO FIXME this may need special logic to parse the first part of the type,
// then parse the rest with increased indentation. The current implementation
// may not correctly handle scenarios like this:
//
// Result
// ok err :=
//
// ...which should actually be something like:
//
// Result
// ok err :=
//
// This seems likely enough to be broken that it's worth trying to reproduce
// and then fix! (Or, if everything is somehow fine, delete this comment.)
space0_after(type_annotation::located(min_indent), min_indent),
char(':')
), ),
either!( // Annotation
// Custom type skip_first!(
skip_first!( char(':'),
// The `=` in `:=` (at this point we already consumed the `:`) // Spaces after the ':' (at a normal indentation level) and then the type.
char('='), // The type itself must be indented more than the pattern and ':'
one_or_more!(space0_before( space0_before(type_annotation::located(indented_more), indented_more)
type_annotation::located(min_indent),
min_indent,
))
),
// Alias
space0_before(type_annotation::located(min_indent), min_indent)
) )
), )
|(loc_type_name, rest)| match rest { ),
Either::First(loc_ann) => Def::CustomType(loc_type_name, loc_ann), |arena: &'a Bump, (loc_pattern, expr_or_ann)| match expr_or_ann {
Either::Second(anns) => Def::TypeAlias(loc_type_name, anns), Either::First(loc_expr) => Def::Body(arena.alloc(loc_pattern), arena.alloc(loc_expr)),
} Either::Second(loc_ann) => Def::Annotation(loc_pattern, loc_ann),
) }
) )
} }
@ -541,8 +499,8 @@ fn parse_def_expr<'a>(
), ),
move |arena, state, (loc_first_body, (mut defs, loc_ret))| { move |arena, state, (loc_first_body, (mut defs, loc_ret))| {
let first_def: Def<'a> = let first_def: Def<'a> =
// TODO if Parser were FnOnce instead of Fn, this might not need .clone()? // TODO is there some way to eliminate this .clone() here?
Def::Body(loc_first_pattern.clone(), arena.alloc(loc_first_body)); Def::Body(arena.alloc(loc_first_pattern.clone()), arena.alloc(loc_first_body));
let loc_first_def = Located { let loc_first_def = Located {
value: first_def, value: first_def,