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, env: &mut Env,
subs: &mut Subs, subs: &mut Subs,
scope: Scope, 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>, expected: Expected<Type>,
loc_ret: &'a Located<ast::Expr<'a>>, loc_ret: &'a Located<ast::Expr<'a>>,
) -> (Expr, Output) { ) -> (Expr, Output) {
@ -1262,9 +1262,10 @@ fn can_defs<'a>(
// was shadowing, which will be handled later. // was shadowing, which will be handled later.
let assigned_idents: Vec<(Ident, (Symbol, Region))> = idents_from_patterns( let assigned_idents: Vec<(Ident, (Symbol, Region))> = idents_from_patterns(
defs.clone().iter().flat_map(|(_, def)| match def { defs.clone().iter().flat_map(|(_, def)| match def {
Def::AnnotationOnly(_region) => None, Def::Annotation(_, _) => None,
Def::BodyOnly(loc_pattern, _expr) => Some(loc_pattern), Def::Body(loc_pattern, _) => Some(loc_pattern),
Def::AnnotatedBody(_loc_annotation, loc_pattern, _expr) => Some(loc_pattern), Def::TypeAlias(_, _) => None,
Def::CustomType(_, _) => None,
}), }),
&scope, &scope,
); );
@ -1279,12 +1280,33 @@ fn can_defs<'a>(
// Used in constraint generation // Used in constraint generation
let rigid_info = Info::with_capacity(defs.len()); let rigid_info = Info::with_capacity(defs.len());
let mut flex_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 // 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! // block. Order of assignments doesn't matter, thanks to referential transparency!
let (opt_loc_pattern, (loc_can_expr, can_output)) = match def { 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 value = Expr::RuntimeError(NoImplementation);
let loc_expr = Located { let loc_expr = Located {
value, value,
@ -1293,7 +1315,7 @@ fn can_defs<'a>(
(None, (loc_expr, Output::new(True))) (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. // Make types for the pattern and the body expr.
let expr_var = subs.mk_flex_var(); let expr_var = subs.mk_flex_var();
let expr_type = Type::Variable(expr_var); let expr_type = Type::Variable(expr_var);
@ -1345,8 +1367,11 @@ fn can_defs<'a>(
(Some(loc_pattern), (loc_can_expr, output)) (Some(loc_pattern), (loc_can_expr, output))
} }
Def::AnnotatedBody(_loc_annotation, _loc_pattern, _loc_expr) => { Def::CustomType(_, _) => {
panic!("TODO handle annotated def") 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 { for (_, def) in pairs {
let def = match def { let def = match def {
Def::AnnotationOnly(ann) => Def::AnnotationOnly(ann.clone()), Def::Body(pattern, loc_expr) => {
Def::BodyOnly(pattern, loc_expr) => { &*arena.alloc(Def::Body(pattern.clone(), desugar(arena, loc_expr)))
Def::BodyOnly(pattern.clone(), desugar(arena, loc_expr))
} }
Def::AnnotatedBody(annotation, pattern, loc_body) => Def::AnnotatedBody( Def::Annotation(_, _) => def,
annotation.clone(), Def::CustomType(_, _) => def,
pattern.clone(), Def::TypeAlias(_, _) => def,
desugar(arena, loc_body),
),
}; };
desugared_defs.push((Vec::new_in(arena).into_bump_slice(), 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>>), Closure(&'a Vec<'a, Loc<Pattern<'a>>>, &'a Loc<Expr<'a>>),
/// Multiple defs in a row /// Multiple defs in a row
Defs( Defs(
Vec<'a, (&'a [CommentOrNewline<'a>], Def<'a>)>, Vec<'a, (&'a [CommentOrNewline<'a>], &'a Def<'a>)>,
&'a Loc<Expr<'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> { 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); let mut buf = String::new_in(arena);
match def { match def {
Def::AnnotationOnly(_region) => panic!("TODO have format_def support AnnotationOnly"), Def::Annotation(_, _) => panic!("TODO have format_def support Annotation"),
BodyOnly(loc_pattern, loc_expr) => { Def::Body(loc_pattern, loc_expr) => {
buf.push_str(&format_pattern(arena, &loc_pattern.value, indent, true)); buf.push_str(&format_pattern(arena, &loc_pattern.value, indent, true));
buf.push_str(" = "); buf.push_str(" = ");
buf.push_str(&format(arena, &loc_expr.value, indent, false)); buf.push_str(&format(arena, &loc_expr.value, indent, false));
} }
AnnotatedBody(_loc_annotation, _loc_pattern, _loc_expr) => { Def::CustomType(_, _) => panic!("TODO have format_def support CustomType"),
panic!("TODO have format_def support AnnotationOnly") Def::TypeAlias(_, _) => panic!("TODO have format_def support TypeAlias"),
}
} }
buf buf

View file

@ -35,10 +35,10 @@ use parse::blankspace::{
use parse::ident::{ident, Ident, MaybeQualified}; use parse::ident::{ident, Ident, MaybeQualified};
use parse::number_literal::number_literal; use parse::number_literal::number_literal;
use parse::parser::{ use parse::parser::{
and, attempt, between, char, either, loc, map, map_with_arena, not, not_followed_by, one_of16, allocated, and, attempt, between, char, either, loc, map, map_with_arena, not, not_followed_by,
one_of2, one_of5, one_of9, one_or_more, optional, sep_by0, skip_first, skip_second, string, one_of16, one_of2, one_of5, one_of9, one_or_more, optional, sep_by0, skip_first, skip_second,
then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason, ParseResult, Parser, string, then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason, ParseResult,
State, Parser, State,
}; };
use region::Located; use region::Located;
@ -569,7 +569,10 @@ fn parse_def_expr<'a>(
loc(move |arena, state| parse_expr(indented_more, arena, state)), loc(move |arena, state| parse_expr(indented_more, arena, state)),
and( and(
// Optionally parse additional defs. // 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. // Parse the final expression that will be returned.
// It should be indented the same amount as the original. // It should be indented the same amount as the original.
space1_before( space1_before(
@ -585,13 +588,13 @@ fn parse_def_expr<'a>(
} else { } else {
let first_def: Def<'a> = let first_def: Def<'a> =
// TODO if Parser were FnOnce instead of Fn, this might not need .clone()? // 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 // 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 // reorder the first one to the end, because canonicalize will
// re-sort all of these based on dependencies anyway. Only // re-sort all of these based on dependencies anyway. Only
// their regions will ever be visible to the user.) // 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)) 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>> { pub fn type_annotation<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>> {
move |_, _| { 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> pub fn not_followed_by<'a, P, ByParser, By, Val>(parser: P, by: ByParser) -> impl Parser<'a, Val>
where where
ByParser: Parser<'a, By>, ByParser: Parser<'a, By>,

View file

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