mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Ensure formatted multiline patterns can be parsed
This commit is contained in:
parent
78cda703d9
commit
dfcb7a0c3b
6 changed files with 168 additions and 39 deletions
|
@ -94,7 +94,7 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, _newlines: Newlines, indent: u16) {
|
||||
fmt_pattern_inner(self, buf, parens, indent, self.is_multiline());
|
||||
fmt_pattern_inner(self, buf, parens, indent, self.is_multiline(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,31 +105,64 @@ fn fmt_pattern_inner(
|
|||
|
||||
indent: u16,
|
||||
outer_is_multiline: bool,
|
||||
) {
|
||||
use self::Pattern::*;
|
||||
|
||||
force_newline_at_start: bool,
|
||||
) -> bool {
|
||||
let me = pattern_lift_spaces(buf.text.bump(), pat);
|
||||
|
||||
let mut was_multiline = me.item.is_multiline();
|
||||
|
||||
if !me.before.is_empty() {
|
||||
if !outer_is_multiline {
|
||||
was_multiline |= me.before.iter().any(|s| s.is_comment());
|
||||
fmt_comments_only(buf, me.before.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
was_multiline |= true;
|
||||
fmt_spaces(buf, me.before.iter(), indent);
|
||||
}
|
||||
}
|
||||
|
||||
if force_newline_at_start {
|
||||
buf.ensure_ends_with_newline();
|
||||
}
|
||||
|
||||
let is_multiline = me.item.is_multiline();
|
||||
|
||||
fmt_pattern_only(me, buf, indent, parens, is_multiline);
|
||||
|
||||
if !me.after.is_empty() {
|
||||
if starts_with_inline_comment(me.after.iter()) {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
if !outer_is_multiline {
|
||||
was_multiline |= me.before.iter().any(|s| s.is_comment());
|
||||
fmt_comments_only(buf, me.after.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
was_multiline |= true;
|
||||
fmt_spaces(buf, me.after.iter(), indent);
|
||||
}
|
||||
}
|
||||
|
||||
was_multiline
|
||||
}
|
||||
|
||||
fn fmt_pattern_only(
|
||||
me: Spaces<'_, Pattern<'_>>,
|
||||
buf: &mut Buf<'_>,
|
||||
indent: u16,
|
||||
parens: Parens,
|
||||
is_multiline: bool,
|
||||
) {
|
||||
match me.item {
|
||||
Identifier { ident: string } => {
|
||||
Pattern::Identifier { ident: string } => {
|
||||
buf.indent(indent);
|
||||
snakify_camel_ident(buf, string);
|
||||
}
|
||||
Tag(name) | OpaqueRef(name) => {
|
||||
Pattern::Tag(name) | Pattern::OpaqueRef(name) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name);
|
||||
}
|
||||
Apply(loc_pattern, loc_arg_patterns) => {
|
||||
Pattern::Apply(loc_pattern, loc_arg_patterns) => {
|
||||
buf.indent(indent);
|
||||
// Sometimes, an Apply pattern needs parens around it.
|
||||
// In particular when an Apply's argument is itself an Apply (> 0) arguments
|
||||
|
@ -155,7 +188,7 @@ fn fmt_pattern_inner(
|
|||
}
|
||||
}
|
||||
|
||||
fmt_pattern_inner(&pat.item, buf, Parens::InApply, indent, is_multiline);
|
||||
fmt_pattern_inner(&pat.item, buf, Parens::InApply, indent, is_multiline, false);
|
||||
|
||||
if !pat.after.is_empty() {
|
||||
if !is_multiline {
|
||||
|
@ -165,22 +198,26 @@ fn fmt_pattern_inner(
|
|||
}
|
||||
}
|
||||
|
||||
let mut add_newlines = false;
|
||||
|
||||
for loc_arg in loc_arg_patterns.iter() {
|
||||
buf.spaces(1);
|
||||
fmt_pattern_inner(
|
||||
let was_multiline = fmt_pattern_inner(
|
||||
&loc_arg.value,
|
||||
buf,
|
||||
Parens::InApply,
|
||||
indent_more,
|
||||
is_multiline,
|
||||
add_newlines,
|
||||
);
|
||||
add_newlines |= was_multiline;
|
||||
}
|
||||
|
||||
if parens {
|
||||
buf.push(')');
|
||||
}
|
||||
}
|
||||
RecordDestructure(loc_patterns) => {
|
||||
Pattern::RecordDestructure(loc_patterns) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("{");
|
||||
|
||||
|
@ -198,7 +235,14 @@ fn fmt_pattern_inner(
|
|||
}
|
||||
}
|
||||
|
||||
fmt_pattern_inner(&item.item, buf, Parens::NotNeeded, indent, is_multiline);
|
||||
fmt_pattern_inner(
|
||||
&item.item,
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
indent,
|
||||
is_multiline,
|
||||
false,
|
||||
);
|
||||
|
||||
let is_multiline = item.item.is_multiline();
|
||||
|
||||
|
@ -228,7 +272,7 @@ fn fmt_pattern_inner(
|
|||
buf.push_str("}");
|
||||
}
|
||||
|
||||
RequiredField(name, loc_pattern) => {
|
||||
Pattern::RequiredField(name, loc_pattern) => {
|
||||
buf.indent(indent);
|
||||
snakify_camel_ident(buf, name);
|
||||
buf.push_str(":");
|
||||
|
@ -239,10 +283,11 @@ fn fmt_pattern_inner(
|
|||
Parens::NotNeeded,
|
||||
indent,
|
||||
is_multiline,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
OptionalField(name, loc_pattern) => {
|
||||
Pattern::OptionalField(name, loc_pattern) => {
|
||||
buf.indent(indent);
|
||||
snakify_camel_ident(buf, name);
|
||||
buf.push_str(" ?");
|
||||
|
@ -250,11 +295,11 @@ fn fmt_pattern_inner(
|
|||
loc_pattern.format(buf, indent);
|
||||
}
|
||||
|
||||
NumLiteral(string) => {
|
||||
Pattern::NumLiteral(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
NonBase10Literal {
|
||||
Pattern::NonBase10Literal {
|
||||
base,
|
||||
string,
|
||||
is_negative,
|
||||
|
@ -273,21 +318,21 @@ fn fmt_pattern_inner(
|
|||
|
||||
buf.push_str(string);
|
||||
}
|
||||
FloatLiteral(string) => {
|
||||
Pattern::FloatLiteral(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
StrLiteral(literal) => fmt_str_literal(buf, literal, indent),
|
||||
SingleQuote(string) => {
|
||||
Pattern::StrLiteral(literal) => fmt_str_literal(buf, literal, indent),
|
||||
Pattern::SingleQuote(string) => {
|
||||
buf.indent(indent);
|
||||
format_sq_literal(buf, string);
|
||||
}
|
||||
Underscore(name) => {
|
||||
Pattern::Underscore(name) => {
|
||||
buf.indent(indent);
|
||||
buf.push('_');
|
||||
buf.push_str(name);
|
||||
}
|
||||
Tuple(loc_patterns) => {
|
||||
Pattern::Tuple(loc_patterns) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("(");
|
||||
|
||||
|
@ -299,6 +344,7 @@ fn fmt_pattern_inner(
|
|||
Parens::NotNeeded,
|
||||
indent,
|
||||
is_multiline,
|
||||
false,
|
||||
);
|
||||
|
||||
if it.peek().is_some() {
|
||||
|
@ -311,7 +357,7 @@ fn fmt_pattern_inner(
|
|||
buf.indent(indent);
|
||||
buf.push_str(")");
|
||||
}
|
||||
List(loc_patterns) => {
|
||||
Pattern::List(loc_patterns) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("[");
|
||||
|
||||
|
@ -323,6 +369,7 @@ fn fmt_pattern_inner(
|
|||
Parens::NotNeeded,
|
||||
indent,
|
||||
is_multiline,
|
||||
false,
|
||||
);
|
||||
|
||||
if it.peek().is_some() {
|
||||
|
@ -335,7 +382,7 @@ fn fmt_pattern_inner(
|
|||
buf.indent(indent);
|
||||
buf.push_str("]");
|
||||
}
|
||||
ListRest(opt_pattern_as) => {
|
||||
Pattern::ListRest(opt_pattern_as) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("..");
|
||||
|
||||
|
@ -347,7 +394,7 @@ fn fmt_pattern_inner(
|
|||
}
|
||||
}
|
||||
|
||||
As(pattern, pattern_as) => {
|
||||
Pattern::As(pattern, pattern_as) => {
|
||||
let needs_parens = parens == Parens::InAsPattern;
|
||||
|
||||
if needs_parens {
|
||||
|
@ -365,14 +412,16 @@ fn fmt_pattern_inner(
|
|||
}
|
||||
}
|
||||
|
||||
SpaceBefore(..) | SpaceAfter(..) => unreachable!("handled by lift_spaces"),
|
||||
Pattern::SpaceBefore(..) | Pattern::SpaceAfter(..) => {
|
||||
unreachable!("handled by lift_spaces")
|
||||
}
|
||||
|
||||
// Malformed
|
||||
Malformed(string) | MalformedIdent(string, _) => {
|
||||
Pattern::Malformed(string) | Pattern::MalformedIdent(string, _) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
QualifiedIdentifier { module_name, ident } => {
|
||||
Pattern::QualifiedIdentifier { module_name, ident } => {
|
||||
buf.indent(indent);
|
||||
if !module_name.is_empty() {
|
||||
buf.push_str(module_name);
|
||||
|
@ -382,18 +431,6 @@ fn fmt_pattern_inner(
|
|||
snakify_camel_ident(buf, ident);
|
||||
}
|
||||
}
|
||||
|
||||
if !me.after.is_empty() {
|
||||
if starts_with_inline_comment(me.after.iter()) {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
if !outer_is_multiline {
|
||||
fmt_comments_only(buf, me.after.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
fmt_spaces(buf, me.after.iter(), indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn starts_with_inline_comment<'a, I: IntoIterator<Item = &'a CommentOrNewline<'a>>>(
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
1 (0 #
|
||||
f)
|
||||
(0 #
|
||||
f) : f
|
||||
e
|
|
@ -0,0 +1,80 @@
|
|||
SpaceAfter(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-19,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Apply(
|
||||
@0-1 NumLiteral(
|
||||
"1",
|
||||
),
|
||||
[
|
||||
@2-8 Apply(
|
||||
@3-4 SpaceAfter(
|
||||
NumLiteral(
|
||||
"0",
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
[
|
||||
@7-8 Identifier {
|
||||
ident: "f",
|
||||
},
|
||||
],
|
||||
),
|
||||
@10-16 Apply(
|
||||
@11-12 SpaceAfter(
|
||||
NumLiteral(
|
||||
"0",
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
[
|
||||
@15-16 Identifier {
|
||||
ident: "f",
|
||||
},
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
@18-19 BoundVariable(
|
||||
"f",
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@20-21 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "e",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -0,0 +1,4 @@
|
|||
1((0#
|
||||
)f)((0#
|
||||
)f):f
|
||||
e
|
|
@ -1,4 +1,6 @@
|
|||
1
|
||||
"""
|
||||
""" "^" 2 : A
|
||||
"""
|
||||
"^"
|
||||
2 : A
|
||||
""
|
|
@ -442,6 +442,7 @@ mod test_snapshots {
|
|||
pass/list_patterns.expr,
|
||||
pass/lowest_float.expr,
|
||||
pass/lowest_int.expr,
|
||||
pass/mega_parens_pat.expr,
|
||||
pass/min_parens_number.expr,
|
||||
pass/minimal_app_header.header,
|
||||
pass/minus_minus_block_string.expr,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue