Merge pull request #4414 from roc-lang/i4412

Parse and format list patterns
This commit is contained in:
Richard Feldman 2022-10-26 19:49:12 -07:00 committed by GitHub
commit 67a8bbd6a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 621 additions and 11 deletions

View file

@ -653,6 +653,13 @@ pub enum Pattern<'a> {
Underscore(&'a str),
SingleQuote(&'a str),
/// A list pattern like [_, x, ..]
List(Collection<'a, Loc<Pattern<'a>>>),
/// A list-rest pattern ".."
/// Can only occur inside of a [Pattern::List]
ListRest,
// Space
SpaceBefore(&'a Pattern<'a>, &'a [CommentOrNewline<'a>]),
SpaceAfter(&'a Pattern<'a>, &'a [CommentOrNewline<'a>]),

View file

@ -107,7 +107,8 @@ impl_space_problem! {
EWhen<'a>,
EAbility<'a>,
PInParens<'a>,
PRecord<'a>
PRecord<'a>,
PList<'a>
}
#[derive(Debug, Clone, PartialEq, Eq)]
@ -519,6 +520,7 @@ pub enum EExpect<'a> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EPattern<'a> {
Record(PRecord<'a>, Position),
List(PList<'a>, Position),
Underscore(Position),
Start(Position),
@ -553,6 +555,20 @@ pub enum PRecord<'a> {
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PList<'a> {
End(Position),
Open(Position),
Rest(Position),
Pattern(&'a EPattern<'a>, Position),
Space(BadInputError, Position),
IndentOpen(Position),
IndentEnd(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PInParens<'a> {
End(Position),

View file

@ -3,8 +3,8 @@ use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
use crate::ident::{lowercase_ident, parse_ident, Ident};
use crate::parser::Progress::{self, *};
use crate::parser::{
backtrackable, optional, specialize, specialize_ref, then, word1, EPattern, PInParens, PRecord,
ParseResult, Parser,
backtrackable, optional, specialize, specialize_ref, then, word1, word2, word3, EPattern,
PInParens, PList, PRecord, ParseResult, Parser,
};
use crate::state::State;
use bumpalo::collections::string::String;
@ -59,6 +59,7 @@ pub fn loc_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>
EPattern::Record,
crate::pattern::record_pattern_help(min_indent)
)),
loc!(specialize(EPattern::List, list_pattern_help(min_indent))),
loc!(number_pattern_help()),
loc!(string_pattern_help()),
loc!(single_quote_pattern_help()),
@ -202,6 +203,49 @@ fn single_quote_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>>
)
}
fn list_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Pattern<'a>, PList<'a>> {
move |arena, state| {
let (_, pats, state) = collection_trailing_sep_e!(
word1(b'[', PList::Open),
list_element_pattern(min_indent),
word1(b',', PList::End),
word1(b']', PList::End),
min_indent,
PList::Open,
PList::IndentEnd,
Pattern::SpaceBefore
)
.parse(arena, state)?;
let result = Pattern::List(pats);
Ok((MadeProgress, result, state))
}
}
fn list_element_pattern<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
one_of!(
three_list_rest_pattern_error(),
list_rest_pattern(),
specialize_ref(PList::Pattern, loc_pattern_help(min_indent)),
)
}
fn three_list_rest_pattern_error<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
then(
loc!(word3(b'.', b'.', b'.', PList::Rest)),
|_arena, state, _progress, word| {
Err((MadeProgress, PList::Rest(word.region.start()), state))
},
)
}
fn list_rest_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
map!(loc!(word2(b'.', b'.', PList::Open)), |loc_word: Loc<_>| {
loc_word.map(|_| Pattern::ListRest)
})
}
fn loc_ident_pattern_help<'a>(
min_indent: u32,
can_have_arguments: bool,
@ -354,11 +398,9 @@ fn lowercase_ident_pattern<'a>(
fn record_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
move |arena, state| {
let (_, fields, state) = collection_trailing_sep_e!(
// word1_check_indent!(b'{', PRecord::Open, min_indent, PRecord::IndentOpen),
word1(b'{', PRecord::Open),
record_pattern_field(min_indent),
word1(b',', PRecord::End),
// word1_check_indent!(b'}', PRecord::End, min_indent, PRecord::IndentEnd),
word1(b'}', PRecord::End),
min_indent,
PRecord::Open,

View file

@ -0,0 +1,216 @@
When(
@5-7 List(
[],
),
[
WhenBranch {
patterns: [
@13-15 SpaceBefore(
List(
[],
),
[
Newline,
],
),
],
value: @19-21 Record(
[],
),
guard: None,
},
WhenBranch {
patterns: [
@24-28 SpaceBefore(
List(
[
@25-27 ListRest,
],
),
[
Newline,
],
),
],
value: @32-34 Record(
[],
),
guard: None,
},
WhenBranch {
patterns: [
@37-51 SpaceBefore(
List(
[
@38-39 Underscore(
"",
),
@41-43 ListRest,
@45-46 Underscore(
"",
),
@48-50 ListRest,
],
),
[
Newline,
],
),
],
value: @55-57 Record(
[],
),
guard: None,
},
WhenBranch {
patterns: [
@60-72 SpaceBefore(
List(
[
@61-62 Identifier(
"a",
),
@64-65 Identifier(
"b",
),
@67-68 Identifier(
"c",
),
@70-71 Identifier(
"d",
),
],
),
[
Newline,
],
),
],
value: @76-78 Record(
[],
),
guard: None,
},
WhenBranch {
patterns: [
@81-91 SpaceBefore(
List(
[
@82-83 Identifier(
"a",
),
@85-86 Identifier(
"b",
),
@88-90 ListRest,
],
),
[
Newline,
],
),
],
value: @95-97 Record(
[],
),
guard: None,
},
WhenBranch {
patterns: [
@100-110 SpaceBefore(
List(
[
@101-103 ListRest,
@105-106 Identifier(
"c",
),
@108-109 Identifier(
"d",
),
],
),
[
Newline,
],
),
],
value: @114-116 Record(
[],
),
guard: None,
},
WhenBranch {
patterns: [
@119-135 SpaceBefore(
List(
[
@120-123 List(
[
@121-122 Tag(
"A",
),
],
),
@125-129 List(
[
@126-128 ListRest,
],
),
@131-134 List(
[
@132-133 Identifier(
"a",
),
],
),
],
),
[
Newline,
],
),
],
value: @139-141 Record(
[],
),
guard: None,
},
WhenBranch {
patterns: [
@144-163 SpaceBefore(
List(
[
@145-153 List(
[
@146-148 List(
[],
),
@150-152 List(
[],
),
],
),
@155-162 List(
[
@156-158 List(
[],
),
@160-161 Identifier(
"x",
),
],
),
],
),
[
Newline,
],
),
],
value: @167-169 Record(
[],
),
guard: None,
},
],
)

View file

@ -0,0 +1,9 @@
when [] is
[] -> {}
[..] -> {}
[_, .., _, ..] -> {}
[a, b, c, d] -> {}
[a, b, ..] -> {}
[.., c, d] -> {}
[[A], [..], [a]] -> {}
[[[], []], [[], x]] -> {}

View file

@ -175,6 +175,7 @@ mod test_parse {
pass/list_closing_indent_not_enough.expr,
pass/list_closing_same_indent_no_trailing_comma.expr,
pass/list_closing_same_indent_with_trailing_comma.expr,
pass/list_patterns.expr,
pass/lowest_float.expr,
pass/lowest_int.expr,
pass/malformed_ident_due_to_underscore.expr,