Revise Def structure

This commit is contained in:
Richard Feldman 2019-10-26 15:31:39 -04:00
parent 2d11659b57
commit f738d9db80
6 changed files with 79 additions and 45 deletions

View file

@ -1252,7 +1252,7 @@ fn can_defs<'a>(
env: &mut Env,
subs: &mut Subs,
scope: Scope,
defs: &'a bumpalo::collections::Vec<'a, (&'a [ast::CommentOrNewline<'a>], Def<'a>)>,
defs: &'a bumpalo::collections::Vec<'a, (&'a [ast::CommentOrNewline<'a>], &'a Def<'a>)>,
expected: Expected<Type>,
loc_ret: &'a Located<ast::Expr<'a>>,
) -> (Expr, Output) {
@ -1262,9 +1262,10 @@ fn can_defs<'a>(
// was shadowing, which will be handled later.
let assigned_idents: Vec<(Ident, (Symbol, Region))> = idents_from_patterns(
defs.clone().iter().flat_map(|(_, def)| match def {
Def::AnnotationOnly(_region) => None,
Def::BodyOnly(loc_pattern, _expr) => Some(loc_pattern),
Def::AnnotatedBody(_loc_annotation, loc_pattern, _expr) => Some(loc_pattern),
Def::Annotation(_, _) => None,
Def::Body(loc_pattern, _) => Some(loc_pattern),
Def::TypeAlias(_, _) => None,
Def::CustomType(_, _) => None,
}),
&scope,
);
@ -1279,12 +1280,33 @@ fn can_defs<'a>(
// Used in constraint generation
let rigid_info = Info::with_capacity(defs.len());
let mut flex_info = Info::with_capacity(defs.len());
let mut iter = defs.iter().peekable();
for (_, def) in defs {
while let Some((_, def)) = iter.next() {
// Each assignment gets to have all the idents in scope that are assigned in this
// block. Order of assignments doesn't matter, thanks to referential transparency!
let (opt_loc_pattern, (loc_can_expr, can_output)) = match def {
Def::AnnotationOnly(loc_annotation) => {
Def::Annotation(loc_pattern, loc_annotation) => {
// TODO implement this:
//
// Is this a standalone annotation, or is it annotating the
// next def? This is annotating the next def iff:
//
// 1. There is a next def.
// 2. It is a Def::Body.
// 3. Its Pattern contains at least one SpaceBefore.
// 4. The count of all Newlines across all of its SpaceBefores is exactly 1.
//
// This tells us we're an annotation in the following scenario:
//
// foo : String
// foo = "blah"
//
// Knowing that, we then need to incorporate the annotation's type constraints
// into the next def's. To do this, we extract the next def from the iterator
// immediately, then canonicalize it to get its Variable, then use that
// Variable to generate the extra constraints.
let value = Expr::RuntimeError(NoImplementation);
let loc_expr = Located {
value,
@ -1293,7 +1315,7 @@ fn can_defs<'a>(
(None, (loc_expr, Output::new(True)))
}
Def::BodyOnly(loc_pattern, loc_expr) => {
Def::Body(loc_pattern, loc_expr) => {
// Make types for the pattern and the body expr.
let expr_var = subs.mk_flex_var();
let expr_type = Type::Variable(expr_var);
@ -1345,8 +1367,11 @@ fn can_defs<'a>(
(Some(loc_pattern), (loc_can_expr, output))
}
Def::AnnotatedBody(_loc_annotation, _loc_pattern, _loc_expr) => {
panic!("TODO handle annotated def")
Def::CustomType(_, _) => {
panic!("TODO error - custom types can only be defined at the toplevel")
}
Def::TypeAlias(_, _) => {
panic!("TODO error - type aliases can only be defined at the toplevel")
}
};

View file

@ -231,15 +231,12 @@ pub fn desugar<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a Loca
for (_, def) in pairs {
let def = match def {
Def::AnnotationOnly(ann) => Def::AnnotationOnly(ann.clone()),
Def::BodyOnly(pattern, loc_expr) => {
Def::BodyOnly(pattern.clone(), desugar(arena, loc_expr))
Def::Body(pattern, loc_expr) => {
&*arena.alloc(Def::Body(pattern.clone(), desugar(arena, loc_expr)))
}
Def::AnnotatedBody(annotation, pattern, loc_body) => Def::AnnotatedBody(
annotation.clone(),
pattern.clone(),
desugar(arena, loc_body),
),
Def::Annotation(_, _) => def,
Def::CustomType(_, _) => def,
Def::TypeAlias(_, _) => def,
};
desugared_defs.push((Vec::new_in(arena).into_bump_slice(), def));

View file

@ -97,7 +97,7 @@ pub enum Expr<'a> {
Closure(&'a Vec<'a, Loc<Pattern<'a>>>, &'a Loc<Expr<'a>>),
/// Multiple defs in a row
Defs(
Vec<'a, (&'a [CommentOrNewline<'a>], Def<'a>)>,
Vec<'a, (&'a [CommentOrNewline<'a>], &'a Def<'a>)>,
&'a Loc<Expr<'a>>,
),
@ -540,20 +540,17 @@ pub fn format<'a>(
}
pub fn format_def<'a>(arena: &'a Bump, def: &'a Def<'a>, indent: u16) -> String<'a> {
use self::Def::*;
let mut buf = String::new_in(arena);
match def {
Def::AnnotationOnly(_region) => panic!("TODO have format_def support AnnotationOnly"),
BodyOnly(loc_pattern, loc_expr) => {
Def::Annotation(_, _) => panic!("TODO have format_def support Annotation"),
Def::Body(loc_pattern, loc_expr) => {
buf.push_str(&format_pattern(arena, &loc_pattern.value, indent, true));
buf.push_str(" = ");
buf.push_str(&format(arena, &loc_expr.value, indent, false));
}
AnnotatedBody(_loc_annotation, _loc_pattern, _loc_expr) => {
panic!("TODO have format_def support AnnotationOnly")
}
Def::CustomType(_, _) => panic!("TODO have format_def support CustomType"),
Def::TypeAlias(_, _) => panic!("TODO have format_def support TypeAlias"),
}
buf

View file

@ -35,10 +35,10 @@ use parse::blankspace::{
use parse::ident::{ident, Ident, MaybeQualified};
use parse::number_literal::number_literal;
use parse::parser::{
and, attempt, between, char, either, loc, map, map_with_arena, not, not_followed_by, one_of16,
one_of2, one_of5, one_of9, one_or_more, optional, sep_by0, skip_first, skip_second, string,
then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason, ParseResult, Parser,
State,
allocated, and, attempt, between, char, either, loc, map, map_with_arena, not, not_followed_by,
one_of16, one_of2, one_of5, one_of9, one_or_more, optional, sep_by0, skip_first, skip_second,
string, then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason, ParseResult,
Parser, State,
};
use region::Located;
@ -569,7 +569,10 @@ fn parse_def_expr<'a>(
loc(move |arena, state| parse_expr(indented_more, arena, state)),
and(
// Optionally parse additional defs.
zero_or_more(and(space1(original_indent), def(original_indent))),
zero_or_more(and(
space1(original_indent),
allocated(def(original_indent)),
)),
// Parse the final expression that will be returned.
// It should be indented the same amount as the original.
space1_before(
@ -585,13 +588,13 @@ fn parse_def_expr<'a>(
} else {
let first_def: Def<'a> =
// TODO if Parser were FnOnce instead of Fn, this might not need .clone()?
Def::BodyOnly(loc_first_pattern.clone(), arena.alloc(loc_first_body));
Def::Body(loc_first_pattern.clone(), arena.alloc(loc_first_body));
// Add the first def to the end of the defs. (It's fine that we
// reorder the first one to the end, because canonicalize will
// re-sort all of these based on dependencies anyway. Only
// their regions will ever be visible to the user.)
defs.push((&[], first_def));
defs.push((&[], arena.alloc(first_def)));
Ok((Expr::Defs(defs, arena.alloc(loc_ret)), state))
}
@ -969,7 +972,7 @@ pub fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
pub fn type_annotation<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>> {
move |_, _| {
panic!("TODO");
panic!("TODO parse type_annotation");
}
}

View file

@ -177,6 +177,18 @@ where
}
}
pub fn allocated<'a, P, Val>(parser: P) -> impl Parser<'a, &'a Val>
where
P: Parser<'a, Val>,
Val: 'a,
{
move |arena, state: State<'a>| {
let (answer, state) = parser.parse(arena, state)?;
Ok((&*arena.alloc(answer), state))
}
}
pub fn not_followed_by<'a, P, ByParser, By, Val>(parser: P, by: ByParser) -> impl Parser<'a, Val>
where
ByParser: Parser<'a, By>,

View file

@ -701,10 +701,10 @@ mod test_parse {
fn one_def() {
let arena = Bump::new();
let newlines = bumpalo::vec![in &arena; Newline, Newline];
let def = Def::BodyOnly(
let def = &*arena.alloc(Def::Body(
Located::new(1, 1, 0, 1, Identifier("x")),
arena.alloc(Located::new(1, 1, 2, 3, Int("5"))),
);
));
let defs = bumpalo::vec![in &arena; (Vec::new_in(&arena).into_bump_slice(), def)];
let ret = Expr::SpaceBefore(arena.alloc(Int("42")), newlines.into_bump_slice());
let loc_ret = Located::new(3, 3, 0, 2, ret);
@ -730,10 +730,10 @@ mod test_parse {
fn one_spaced_def() {
let arena = Bump::new();
let newlines = bumpalo::vec![in &arena; Newline, Newline];
let def = Def::BodyOnly(
let def = &*arena.alloc(Def::Body(
Located::new(1, 1, 0, 1, Identifier("x")),
arena.alloc(Located::new(1, 1, 4, 5, Int("5"))),
);
));
let defs = bumpalo::vec![in &arena; (Vec::new_in(&arena).into_bump_slice(), def)];
let ret = Expr::SpaceBefore(arena.alloc(Int("42")), newlines.into_bump_slice());
let loc_ret = Located::new(3, 3, 0, 2, ret);
@ -760,14 +760,14 @@ mod test_parse {
let arena = Bump::new();
let newlines = bumpalo::vec![in &arena; Newline, Newline];
let newline = bumpalo::vec![in &arena; Newline];
let def1 = Def::BodyOnly(
let def1 = &*arena.alloc(Def::Body(
Located::new(1, 1, 0, 1, Identifier("x")),
arena.alloc(Located::new(1, 1, 4, 5, Int("5"))),
);
let def2 = Def::BodyOnly(
));
let def2 = &*arena.alloc(Def::Body(
Located::new(2, 2, 0, 1, Identifier("y")),
arena.alloc(Located::new(2, 2, 4, 5, Int("6"))),
);
));
// NOTE: The first def always gets reordered to the end (because it
// gets added by .push(), since that's more efficient and since
// canonicalization is going to re-sort these all anyway.)
@ -805,14 +805,14 @@ mod test_parse {
Located::new(1, 1, 2, 3, Identifier("x")),
Located::new(1, 1, 5, 6, Identifier("y"))
];
let def1 = Def::BodyOnly(
let def1 = &*arena.alloc(Def::Body(
Located::new(1, 1, 0, 8, RecordDestructure(fields)),
arena.alloc(Located::new(1, 1, 11, 12, Int("5"))),
);
let def2 = Def::BodyOnly(
));
let def2 = &*arena.alloc(Def::Body(
Located::new(2, 2, 0, 1, Identifier("y")),
arena.alloc(Located::new(2, 2, 4, 5, Int("6"))),
);
));
// NOTE: The first def always gets reordered to the end (because it
// gets added by .push(), since that's more efficient and since
// canonicalization is going to re-sort these all anyway.)