mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-10 10:02:38 +03:00
parse and format pattern as
This commit is contained in:
parent
ea53a50447
commit
e9196f3c0b
@ -450,6 +450,7 @@ pub fn to_pattern2<'a>(
|
||||
Tuple(..) => todo!(),
|
||||
List(..) => todo!(),
|
||||
ListRest => todo!(),
|
||||
As(_, _, _) => todo!(),
|
||||
|
||||
Malformed(_str) => {
|
||||
let problem = MalformedPatternProblem::Unknown;
|
||||
|
@ -738,6 +738,10 @@ pub fn canonicalize_pattern<'a>(
|
||||
malformed_pattern(env, problem, region)
|
||||
}
|
||||
|
||||
As(_pattern, _spaces, _identifier) => {
|
||||
todo!();
|
||||
}
|
||||
|
||||
Malformed(_str) => {
|
||||
let problem = MalformedPatternProblem::Unknown;
|
||||
malformed_pattern(env, problem, region)
|
||||
|
@ -69,7 +69,11 @@ impl<'a> Buf<'a> {
|
||||
}
|
||||
|
||||
pub fn push_str_allow_spaces(&mut self, s: &str) {
|
||||
debug_assert!(!self.beginning_of_line);
|
||||
debug_assert!(
|
||||
!self.beginning_of_line,
|
||||
"push_str: `{s}` with text:\n{}",
|
||||
self.text
|
||||
);
|
||||
|
||||
self.flush_spaces();
|
||||
|
||||
@ -77,8 +81,13 @@ impl<'a> Buf<'a> {
|
||||
}
|
||||
|
||||
pub fn push_str(&mut self, s: &str) {
|
||||
debug_assert!(!self.beginning_of_line);
|
||||
debug_assert!(!s.contains('\n') && !s.ends_with(' '));
|
||||
debug_assert!(
|
||||
!self.beginning_of_line,
|
||||
"push_str: `{s}` with text:\n{}",
|
||||
self.text
|
||||
);
|
||||
debug_assert!(!s.contains('\n'));
|
||||
debug_assert!(!s.ends_with(' '));
|
||||
|
||||
if !s.is_empty() {
|
||||
self.flush_spaces();
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::annotation::{Formattable, Newlines, Parens};
|
||||
use crate::expr::{fmt_str_literal, format_sq_literal};
|
||||
use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt};
|
||||
use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt, INDENT};
|
||||
use crate::Buf;
|
||||
use roc_parse::ast::{Base, CommentOrNewline, Pattern};
|
||||
|
||||
@ -28,6 +28,10 @@ impl<'a> Formattable for Pattern<'a> {
|
||||
|
||||
Pattern::OptionalField(_, expr) => expr.is_multiline(),
|
||||
|
||||
Pattern::As(pattern, spaces, _identifier) => {
|
||||
pattern.is_multiline() || spaces.iter().any(|s| s.is_comment())
|
||||
}
|
||||
|
||||
Pattern::Identifier(_)
|
||||
| Pattern::Tag(_)
|
||||
| Pattern::OpaqueRef(_)
|
||||
@ -199,6 +203,27 @@ impl<'a> Formattable for Pattern<'a> {
|
||||
buf.push_str("..");
|
||||
}
|
||||
|
||||
As(pattern, spaces, identifier) => {
|
||||
fmt_pattern(buf, &pattern.value, indent, parens);
|
||||
|
||||
let as_indent = indent + INDENT;
|
||||
|
||||
buf.indent(as_indent);
|
||||
|
||||
if !buf.ends_with_space() {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
buf.push_str("as");
|
||||
buf.spaces(1);
|
||||
|
||||
// these spaces "belong" to the identifier, which can never be multiline
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
|
||||
buf.indent(as_indent);
|
||||
buf.push_str(identifier.value);
|
||||
}
|
||||
|
||||
// Space
|
||||
SpaceBefore(sub_pattern, spaces) => {
|
||||
if !sub_pattern.is_multiline() {
|
||||
|
@ -766,6 +766,11 @@ impl<'a> RemoveSpaces<'a> for Pattern<'a> {
|
||||
Pattern::OptionalField(a, b) => {
|
||||
Pattern::OptionalField(a, arena.alloc(b.remove_spaces(arena)))
|
||||
}
|
||||
Pattern::As(pattern, spaces, identifier) => Pattern::As(
|
||||
arena.alloc(pattern.remove_spaces(arena)),
|
||||
spaces,
|
||||
identifier,
|
||||
),
|
||||
Pattern::NumLiteral(a) => Pattern::NumLiteral(a),
|
||||
Pattern::NonBase10Literal {
|
||||
string,
|
||||
|
@ -702,6 +702,12 @@ pub enum Pattern<'a> {
|
||||
/// Can only occur inside of a [Pattern::List]
|
||||
ListRest,
|
||||
|
||||
As(
|
||||
&'a Loc<Pattern<'a>>,
|
||||
&'a [CommentOrNewline<'a>],
|
||||
Loc<&'a str>,
|
||||
),
|
||||
|
||||
// Space
|
||||
SpaceBefore(&'a Pattern<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a Pattern<'a>, &'a [CommentOrNewline<'a>]),
|
||||
@ -934,6 +940,12 @@ impl<'a> Pattern<'a> {
|
||||
}
|
||||
}
|
||||
ListRest => matches!(other, ListRest),
|
||||
As(pattern, _, identifier) => match other {
|
||||
As(other_pattern, _, other_identifier) => {
|
||||
identifier == other_identifier && pattern.value.equivalent(&other_pattern.value)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
MalformedIdent(str_x, _) => {
|
||||
if let MalformedIdent(str_y, _) = other {
|
||||
str_x == str_y
|
||||
|
@ -556,6 +556,8 @@ pub enum EPattern<'a> {
|
||||
Record(PRecord<'a>, Position),
|
||||
List(PList<'a>, Position),
|
||||
Underscore(Position),
|
||||
As(Position),
|
||||
AsIdentifier(Position),
|
||||
NotAPattern(Position),
|
||||
|
||||
Start(Position),
|
||||
|
@ -1,10 +1,11 @@
|
||||
use crate::ast::{Has, Pattern};
|
||||
use crate::ast::{CommentOrNewline, Has, Pattern, Spaceable};
|
||||
use crate::blankspace::{space0_before_e, space0_e};
|
||||
use crate::ident::{lowercase_ident, parse_ident, Ident};
|
||||
use crate::keyword;
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
backtrackable, fail_when, optional, specialize, specialize_ref, then, word1, word2, word3,
|
||||
EPattern, PInParens, PList, PRecord, Parser,
|
||||
self, backtrackable, fail_when, optional, specialize, specialize_ref, then, word1, word2,
|
||||
word3, EPattern, PInParens, PList, PRecord, Parser,
|
||||
};
|
||||
use crate::state::State;
|
||||
use bumpalo::collections::string::String;
|
||||
@ -42,6 +43,35 @@ pub fn closure_param<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
}
|
||||
|
||||
pub fn loc_pattern_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
move |arena, state: State<'a>, min_indent| {
|
||||
let (_, pattern, state) = loc_pattern_help_help().parse(arena, state, min_indent)?;
|
||||
|
||||
let pattern_state = state.clone();
|
||||
|
||||
let (pattern_spaces, state) = match space0_e(EPattern::As).parse(arena, state, min_indent) {
|
||||
Err(_) => return Ok((MadeProgress, pattern, pattern_state)),
|
||||
Ok((_, pattern_spaces, state)) => (pattern_spaces, state),
|
||||
};
|
||||
|
||||
match pattern_as().parse(arena, state, min_indent) {
|
||||
Err((progress, e)) => match progress {
|
||||
MadeProgress => Err((MadeProgress, e)),
|
||||
NoProgress => Ok((MadeProgress, pattern, pattern_state)),
|
||||
},
|
||||
Ok((_, (spaces, identifier), state)) => {
|
||||
let region = Region::span_across(&pattern.region, &identifier.region);
|
||||
let pattern = arena
|
||||
.alloc(pattern.value)
|
||||
.with_spaces_after(pattern_spaces, pattern.region);
|
||||
let as_pattern = Pattern::As(arena.alloc(pattern), spaces, identifier);
|
||||
|
||||
Ok((MadeProgress, Loc::at(region, as_pattern), state))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn loc_pattern_help_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
one_of!(
|
||||
specialize(EPattern::PInParens, loc_pattern_in_parens_help()),
|
||||
loc!(underscore_pattern_help()),
|
||||
@ -57,6 +87,23 @@ pub fn loc_pattern_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>>
|
||||
)
|
||||
}
|
||||
|
||||
fn pattern_as<'a>() -> impl Parser<'a, (&'a [CommentOrNewline<'a>], Loc<&'a str>), EPattern<'a>> {
|
||||
move |arena, state: State<'a>, min_indent| {
|
||||
let (_, _, state) =
|
||||
parser::keyword_e(keyword::AS, EPattern::As).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, spaces, state) =
|
||||
space0_e(EPattern::AsIdentifier).parse(arena, state, min_indent)?;
|
||||
|
||||
let position = state.pos();
|
||||
|
||||
match loc!(lowercase_ident()).parse(arena, state, min_indent) {
|
||||
Ok((_, identifier, state)) => Ok((MadeProgress, (spaces, identifier), state)),
|
||||
Err((_, ())) => Err((MadeProgress, EPattern::AsIdentifier(position))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn loc_tag_pattern_args_help<'a>() -> impl Parser<'a, Vec<'a, Loc<Pattern<'a>>>, EPattern<'a>> {
|
||||
zero_or_more!(loc_tag_pattern_arg(false))
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
When(
|
||||
@5-6 Num(
|
||||
"0",
|
||||
),
|
||||
[
|
||||
WhenBranch {
|
||||
patterns: [
|
||||
@14-20 SpaceBefore(
|
||||
As(
|
||||
@14-15 SpaceAfter(
|
||||
Underscore(
|
||||
"",
|
||||
),
|
||||
[],
|
||||
),
|
||||
[],
|
||||
@19-20 "n",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
],
|
||||
value: @24-25 Var {
|
||||
module_name: "",
|
||||
ident: "n",
|
||||
},
|
||||
guard: None,
|
||||
},
|
||||
],
|
||||
)
|
@ -0,0 +1,2 @@
|
||||
when 0 is
|
||||
_ as n -> n
|
@ -0,0 +1,38 @@
|
||||
When(
|
||||
@5-6 Num(
|
||||
"0",
|
||||
),
|
||||
[
|
||||
WhenBranch {
|
||||
patterns: [
|
||||
@14-54 SpaceBefore(
|
||||
As(
|
||||
@14-15 SpaceAfter(
|
||||
NumLiteral(
|
||||
"0",
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
" foobar",
|
||||
),
|
||||
],
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
" barfoo",
|
||||
),
|
||||
],
|
||||
@53-54 "n",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
],
|
||||
value: @58-60 Record(
|
||||
[],
|
||||
),
|
||||
guard: None,
|
||||
},
|
||||
],
|
||||
)
|
@ -0,0 +1,4 @@
|
||||
when 0 is
|
||||
0 # foobar
|
||||
as # barfoo
|
||||
n -> {}
|
@ -354,6 +354,8 @@ mod test_snapshots {
|
||||
pass/parenthetical_var.expr,
|
||||
pass/parse_alias.expr,
|
||||
pass/parse_as_ann.expr,
|
||||
pass/pattern_as.expr,
|
||||
pass/pattern_as_spaces.expr,
|
||||
pass/pattern_with_space_in_parens.expr, // https://github.com/roc-lang/roc/issues/929
|
||||
pass/plus_if.expr,
|
||||
pass/plus_when.expr,
|
||||
|
Loading…
Reference in New Issue
Block a user