mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 00:01:16 +00:00
Revise Def structure
This commit is contained in:
parent
2d11659b57
commit
f738d9db80
6 changed files with 79 additions and 45 deletions
|
@ -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")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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.)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue