Merge branch 'trunk' into list-comment-formatting

This commit is contained in:
Richard Feldman 2020-01-13 23:28:20 -05:00 committed by GitHub
commit 6763f2500f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 139 additions and 32 deletions

View file

@ -486,14 +486,14 @@ pub fn canonicalize_expr(
for (loc_pattern, loc_expr) in branches {
let mut shadowable_idents = scope.idents.clone();
remove_idents(&loc_pattern.value, &mut shadowable_idents);
remove_idents(&loc_pattern.first().unwrap().value, &mut shadowable_idents);
let (can_pattern, loc_can_expr, branch_references) = canonicalize_when_branch(
env,
var_store,
scope,
region,
loc_pattern,
loc_pattern.first().unwrap(),
loc_expr,
&mut output,
);

View file

@ -170,10 +170,10 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
let desugared = desugar_expr(arena, &loc_branch_expr);
desugared_branches.push(&*arena.alloc((
Located {
region: loc_pattern.region,
value: Pattern::Nested(&loc_pattern.value),
},
bumpalo::vec![in arena; Located {
region: loc_pattern.first().unwrap().region,
value: Pattern::Nested(&loc_pattern.first().unwrap().value),
}],
Located {
region: desugared.region,
value: Nested(&desugared.value),
@ -251,10 +251,10 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
let pattern_region = condition.region;
branches.push(&*arena.alloc((
Located {
bumpalo::vec![in arena; Located {
value: Pattern::GlobalTag("False"),
region: pattern_region,
},
}],
Located {
value: Nested(&else_branch.value),
region: else_branch.region,
@ -262,10 +262,10 @@ pub fn desugar_expr<'a>(arena: &'a Bump, loc_expr: &'a Located<Expr<'a>>) -> &'a
)));
branches.push(&*arena.alloc((
Located {
bumpalo::vec![in arena; Located {
value: Pattern::Underscore,
region: pattern_region,
},
}],
Located {
value: Nested(&then_branch.value),
region: then_branch.region,

View file

@ -144,16 +144,29 @@ pub fn fmt_expr<'a>(
buf.push_str(" is\n");
let mut it = branches.iter().peekable();
while let Some((pattern, expr)) = it.next() {
while let Some((patterns, expr)) = it.next() {
add_spaces(buf, indent + INDENT);
let (first, rest) = patterns.split_first().unwrap();
match pattern.value {
match first.value {
Pattern::SpaceBefore(nested, spaces) => {
fmt_comments_only(buf, spaces.iter(), indent + INDENT);
fmt_pattern(buf, nested, indent + INDENT, false);
}
_ => {
fmt_pattern(buf, &pattern.value, indent + INDENT, false);
fmt_pattern(buf, &first.value, indent + INDENT, false);
}
};
for pattern in rest {
buf.push_str(" | ");
match pattern.value {
Pattern::SpaceBefore(nested, spaces) => {
fmt_comments_only(buf, spaces.iter(), indent + INDENT);
fmt_pattern(buf, nested, indent + INDENT, false);
}
_ => {
fmt_pattern(buf, &pattern.value, indent + INDENT, false);
}
}
}

View file

@ -158,7 +158,7 @@ pub enum Expr<'a> {
If(&'a (Loc<Expr<'a>>, Loc<Expr<'a>>, Loc<Expr<'a>>)),
When(
&'a Loc<Expr<'a>>,
Vec<'a, &'a (Loc<Pattern<'a>>, Loc<Expr<'a>>)>,
Vec<'a, &'a (Vec<'a, Loc<Pattern<'a>>>, Loc<Expr<'a>>)>,
),
// Blank Space (e.g. comments, spaces, newlines) before or after an expression.

View file

@ -1,7 +1,6 @@
pub static IF: &str = "if";
pub static THEN: &str = "then";
pub static ELSE: &str = "else";
pub static CASE: &str = "case";
pub static WHEN: &str = "when";
pub static AS: &str = "as";
pub static IS: &str = "is";

View file

@ -687,7 +687,6 @@ fn reserved_keyword<'a>() -> impl Parser<'a, ()> {
string(keyword::IF),
string(keyword::THEN),
string(keyword::ELSE),
string(keyword::CASE),
string(keyword::WHEN),
string(keyword::IS),
string(keyword::AS)
@ -887,27 +886,29 @@ pub fn when_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
pub fn case_branches<'a>(
min_indent: u16,
) -> impl Parser<'a, Vec<'a, &'a (Located<Pattern<'a>>, Located<Expr<'a>>)>> {
) -> impl Parser<'a, Vec<'a, &'a (Vec<'a, Located<Pattern<'a>>>, Located<Expr<'a>>)>> {
move |arena, state| {
let mut branches: Vec<'a, &'a (Located<Pattern<'a>>, Located<Expr<'a>>)> =
let mut branches: Vec<'a, &'a (Vec<'a, Located<Pattern<'a>>>, Located<Expr<'a>>)> =
Vec::with_capacity_in(2, arena);
// 1. Parse the first branch and get its indentation level. (It must be >= min_indent.)
// 2. Parse the other branches. Their indentation levels must be == the first branch's.
let (mut loc_first_pattern, state) =
space1_before(loc_pattern(min_indent), min_indent).parse(arena, state)?;
let (mut loc_first_pattern, state) = sep_by1(
map!(and!(space0(min_indent), char('|')), |_| ()),
space0_before(loc_pattern(min_indent), min_indent),
)
.parse(arena, state)?;
let original_indent = state.indent_col;
let indented_more = original_indent + 1;
let (spaces_before_arrow, state) = space0(min_indent).parse(arena, state)?;
// Record the spaces before the first "->", if any.
if !spaces_before_arrow.is_empty() {
let region = loc_first_pattern.region;
let value =
Pattern::SpaceAfter(arena.alloc(loc_first_pattern.value), spaces_before_arrow);
loc_first_pattern = Located { region, value };
let last = loc_first_pattern.pop().unwrap();
let region = last.region;
let value = Pattern::SpaceAfter(arena.alloc(last.value), spaces_before_arrow);
loc_first_pattern.push(Located { region, value });
};
// Parse the first "->" and the expression after it.
@ -926,7 +927,10 @@ pub fn case_branches<'a>(
let branch_parser = and!(
then(
space1_around(loc_pattern(min_indent), min_indent),
sep_by1(
char('|'),
space0_around(loc_pattern(min_indent), min_indent),
),
move |_arena, state, loc_pattern| {
if state.indent_col == original_indent {
Ok((loc_pattern, state))

View file

@ -1289,6 +1289,50 @@ mod test_format {
));
}
#[test]
fn when_with_alternatives() {
expr_formats_same(indoc!(
r#"
when b is
1 | 2 ->
when c is
6 | 7 ->
8
3 | 4 ->
5
"#
));
expr_formats_same(indoc!(
r#"
when b is
# a comment here
1 | 2 ->
# a comment there
1
"#
));
expr_formats_to(
indoc!(
r#"
when b is
1 | 2 |3
->
1
"#
),
indoc!(
r#"
when b is
1 | 2 | 3
->
1
"#
),
);
}
#[test]
fn when_with_moving_comments() {
expr_formats_to(

View file

@ -1589,14 +1589,14 @@ mod test_parse {
let loc_pattern1 = Located::new(1, 1, 1, 7, pattern1);
let expr1 = Int("1");
let loc_expr1 = Located::new(1, 1, 11, 12, expr1);
let branch1 = &*arena.alloc((loc_pattern1, loc_expr1));
let branch1 = &*arena.alloc((bumpalo::vec![in &arena;loc_pattern1], loc_expr1));
let newlines = bumpalo::vec![in &arena; Newline];
let pattern2 =
Pattern::SpaceBefore(arena.alloc(StrLiteral("mise")), newlines.into_bump_slice());
let loc_pattern2 = Located::new(2, 2, 1, 7, pattern2);
let expr2 = Int("2");
let loc_expr2 = Located::new(2, 2, 11, 12, expr2);
let branch2 = &*arena.alloc((loc_pattern2, loc_expr2));
let branch2 = &*arena.alloc((bumpalo::vec![in &arena;loc_pattern2 ], loc_expr2));
let branches = bumpalo::vec![in &arena; branch1, branch2];
let loc_cond = Located::new(0, 0, 5, 6, Var(&[], "x"));
let expected = Expr::When(arena.alloc(loc_cond), branches);
@ -1623,14 +1623,14 @@ mod test_parse {
let loc_pattern1 = Located::new(1, 1, 1, 2, pattern1);
let expr1 = Int("2");
let loc_expr1 = Located::new(1, 1, 6, 7, expr1);
let branch1 = &*arena.alloc((loc_pattern1, loc_expr1));
let branch1 = &*arena.alloc((bumpalo::vec![in &arena;loc_pattern1], loc_expr1));
let newlines = bumpalo::vec![in &arena; Newline];
let pattern2 =
Pattern::SpaceBefore(arena.alloc(IntLiteral("3")), newlines.into_bump_slice());
let loc_pattern2 = Located::new(2, 2, 1, 2, pattern2);
let expr2 = Int("4");
let loc_expr2 = Located::new(2, 2, 6, 7, expr2);
let branch2 = &*arena.alloc((loc_pattern2, loc_expr2));
let branch2 = &*arena.alloc((bumpalo::vec![in &arena;loc_pattern2], loc_expr2));
let branches = bumpalo::vec![in &arena; branch1, branch2];
let loc_cond = Located::new(0, 0, 5, 6, Var(&[], "x"));
let expected = Expr::When(arena.alloc(loc_cond), branches);
@ -1660,7 +1660,7 @@ mod test_parse {
let loc_pattern1 = Located::new(1, 1, 1, 6, pattern1);
let expr1 = Int("2");
let loc_expr1 = Located::new(1, 1, 10, 11, expr1);
let branch1 = &*arena.alloc((loc_pattern1, loc_expr1));
let branch1 = &*arena.alloc((bumpalo::vec![in &arena;loc_pattern1 ], loc_expr1));
let newlines = bumpalo::vec![in &arena; Newline];
let identifiers2 = bumpalo::vec![in &arena; Located::new(2, 2, 3, 4, Identifier("z")), Located::new(2, 2, 6, 7, Identifier("w")) ];
let pattern2 = Pattern::SpaceBefore(
@ -1670,7 +1670,7 @@ mod test_parse {
let loc_pattern2 = Located::new(2, 2, 1, 9, pattern2);
let expr2 = Int("4");
let loc_expr2 = Located::new(2, 2, 13, 14, expr2);
let branch2 = &*arena.alloc((loc_pattern2, loc_expr2));
let branch2 = &*arena.alloc((bumpalo::vec![in &arena;loc_pattern2 ], loc_expr2));
let branches = bumpalo::vec![in &arena; branch1, branch2];
let loc_cond = Located::new(0, 0, 5, 6, Var(&[], "x"));
let expected = Expr::When(arena.alloc(loc_cond), branches);
@ -1688,6 +1688,53 @@ mod test_parse {
assert_eq!(Ok(expected), actual);
}
#[test]
fn when_with_alternative_patterns() {
let arena = Bump::new();
let newlines = bumpalo::vec![in &arena; Newline];
let pattern1 =
Pattern::SpaceBefore(arena.alloc(StrLiteral("blah")), newlines.into_bump_slice());
let pattern1_alt = StrLiteral("blop");
let loc_pattern1 = Located::new(1, 1, 1, 7, pattern1);
let loc_pattern1_alt = Located::new(1, 1, 10, 16, pattern1_alt);
let expr1 = Int("1");
let loc_expr1 = Located::new(1, 1, 20, 21, expr1);
let branch1 = &*arena.alloc((
bumpalo::vec![in &arena;loc_pattern1, loc_pattern1_alt],
loc_expr1,
));
let newlines = bumpalo::vec![in &arena; Newline];
let pattern2 =
Pattern::SpaceBefore(arena.alloc(StrLiteral("foo")), newlines.into_bump_slice());
let newlines = bumpalo::vec![in &arena; Newline];
let pattern2_alt =
Pattern::SpaceBefore(arena.alloc(StrLiteral("bar")), newlines.into_bump_slice());
let loc_pattern2 = Located::new(2, 2, 1, 6, pattern2);
let loc_pattern2_alt = Located::new(3, 3, 1, 6, pattern2_alt);
let expr2 = Int("2");
let loc_expr2 = Located::new(3, 3, 10, 11, expr2);
let branch2 = &*arena.alloc((
bumpalo::vec![in &arena;loc_pattern2, loc_pattern2_alt],
loc_expr2,
));
let branches = bumpalo::vec![in &arena; branch1, branch2];
let loc_cond = Located::new(0, 0, 5, 6, Var(&[], "x"));
let expected = Expr::When(arena.alloc(loc_cond), branches);
let actual = parse_with(
&arena,
indoc!(
r#"
when x is
"blah" | "blop" -> 1
"foo" |
"bar" -> 2
"#
),
);
assert_eq!(Ok(expected), actual);
}
// MODULE
#[test]