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) {
|
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,
|
indent: u16,
|
||||||
outer_is_multiline: bool,
|
outer_is_multiline: bool,
|
||||||
) {
|
force_newline_at_start: bool,
|
||||||
use self::Pattern::*;
|
) -> bool {
|
||||||
|
|
||||||
let me = pattern_lift_spaces(buf.text.bump(), pat);
|
let me = pattern_lift_spaces(buf.text.bump(), pat);
|
||||||
|
|
||||||
|
let mut was_multiline = me.item.is_multiline();
|
||||||
|
|
||||||
if !me.before.is_empty() {
|
if !me.before.is_empty() {
|
||||||
if !outer_is_multiline {
|
if !outer_is_multiline {
|
||||||
|
was_multiline |= me.before.iter().any(|s| s.is_comment());
|
||||||
fmt_comments_only(buf, me.before.iter(), NewlineAt::Bottom, indent)
|
fmt_comments_only(buf, me.before.iter(), NewlineAt::Bottom, indent)
|
||||||
} else {
|
} else {
|
||||||
|
was_multiline |= true;
|
||||||
fmt_spaces(buf, me.before.iter(), indent);
|
fmt_spaces(buf, me.before.iter(), indent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if force_newline_at_start {
|
||||||
|
buf.ensure_ends_with_newline();
|
||||||
|
}
|
||||||
|
|
||||||
let is_multiline = me.item.is_multiline();
|
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 {
|
match me.item {
|
||||||
Identifier { ident: string } => {
|
Pattern::Identifier { ident: string } => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
snakify_camel_ident(buf, string);
|
snakify_camel_ident(buf, string);
|
||||||
}
|
}
|
||||||
Tag(name) | OpaqueRef(name) => {
|
Pattern::Tag(name) | Pattern::OpaqueRef(name) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str(name);
|
buf.push_str(name);
|
||||||
}
|
}
|
||||||
Apply(loc_pattern, loc_arg_patterns) => {
|
Pattern::Apply(loc_pattern, loc_arg_patterns) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
// Sometimes, an Apply pattern needs parens around it.
|
// Sometimes, an Apply pattern needs parens around it.
|
||||||
// In particular when an Apply's argument is itself an Apply (> 0) arguments
|
// 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 !pat.after.is_empty() {
|
||||||
if !is_multiline {
|
if !is_multiline {
|
||||||
|
@ -165,22 +198,26 @@ fn fmt_pattern_inner(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut add_newlines = false;
|
||||||
|
|
||||||
for loc_arg in loc_arg_patterns.iter() {
|
for loc_arg in loc_arg_patterns.iter() {
|
||||||
buf.spaces(1);
|
buf.spaces(1);
|
||||||
fmt_pattern_inner(
|
let was_multiline = fmt_pattern_inner(
|
||||||
&loc_arg.value,
|
&loc_arg.value,
|
||||||
buf,
|
buf,
|
||||||
Parens::InApply,
|
Parens::InApply,
|
||||||
indent_more,
|
indent_more,
|
||||||
is_multiline,
|
is_multiline,
|
||||||
|
add_newlines,
|
||||||
);
|
);
|
||||||
|
add_newlines |= was_multiline;
|
||||||
}
|
}
|
||||||
|
|
||||||
if parens {
|
if parens {
|
||||||
buf.push(')');
|
buf.push(')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RecordDestructure(loc_patterns) => {
|
Pattern::RecordDestructure(loc_patterns) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str("{");
|
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();
|
let is_multiline = item.item.is_multiline();
|
||||||
|
|
||||||
|
@ -228,7 +272,7 @@ fn fmt_pattern_inner(
|
||||||
buf.push_str("}");
|
buf.push_str("}");
|
||||||
}
|
}
|
||||||
|
|
||||||
RequiredField(name, loc_pattern) => {
|
Pattern::RequiredField(name, loc_pattern) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
snakify_camel_ident(buf, name);
|
snakify_camel_ident(buf, name);
|
||||||
buf.push_str(":");
|
buf.push_str(":");
|
||||||
|
@ -239,10 +283,11 @@ fn fmt_pattern_inner(
|
||||||
Parens::NotNeeded,
|
Parens::NotNeeded,
|
||||||
indent,
|
indent,
|
||||||
is_multiline,
|
is_multiline,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionalField(name, loc_pattern) => {
|
Pattern::OptionalField(name, loc_pattern) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
snakify_camel_ident(buf, name);
|
snakify_camel_ident(buf, name);
|
||||||
buf.push_str(" ?");
|
buf.push_str(" ?");
|
||||||
|
@ -250,11 +295,11 @@ fn fmt_pattern_inner(
|
||||||
loc_pattern.format(buf, indent);
|
loc_pattern.format(buf, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
NumLiteral(string) => {
|
Pattern::NumLiteral(string) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str(string);
|
buf.push_str(string);
|
||||||
}
|
}
|
||||||
NonBase10Literal {
|
Pattern::NonBase10Literal {
|
||||||
base,
|
base,
|
||||||
string,
|
string,
|
||||||
is_negative,
|
is_negative,
|
||||||
|
@ -273,21 +318,21 @@ fn fmt_pattern_inner(
|
||||||
|
|
||||||
buf.push_str(string);
|
buf.push_str(string);
|
||||||
}
|
}
|
||||||
FloatLiteral(string) => {
|
Pattern::FloatLiteral(string) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str(string);
|
buf.push_str(string);
|
||||||
}
|
}
|
||||||
StrLiteral(literal) => fmt_str_literal(buf, literal, indent),
|
Pattern::StrLiteral(literal) => fmt_str_literal(buf, literal, indent),
|
||||||
SingleQuote(string) => {
|
Pattern::SingleQuote(string) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
format_sq_literal(buf, string);
|
format_sq_literal(buf, string);
|
||||||
}
|
}
|
||||||
Underscore(name) => {
|
Pattern::Underscore(name) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push('_');
|
buf.push('_');
|
||||||
buf.push_str(name);
|
buf.push_str(name);
|
||||||
}
|
}
|
||||||
Tuple(loc_patterns) => {
|
Pattern::Tuple(loc_patterns) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str("(");
|
buf.push_str("(");
|
||||||
|
|
||||||
|
@ -299,6 +344,7 @@ fn fmt_pattern_inner(
|
||||||
Parens::NotNeeded,
|
Parens::NotNeeded,
|
||||||
indent,
|
indent,
|
||||||
is_multiline,
|
is_multiline,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
if it.peek().is_some() {
|
if it.peek().is_some() {
|
||||||
|
@ -311,7 +357,7 @@ fn fmt_pattern_inner(
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str(")");
|
buf.push_str(")");
|
||||||
}
|
}
|
||||||
List(loc_patterns) => {
|
Pattern::List(loc_patterns) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str("[");
|
buf.push_str("[");
|
||||||
|
|
||||||
|
@ -323,6 +369,7 @@ fn fmt_pattern_inner(
|
||||||
Parens::NotNeeded,
|
Parens::NotNeeded,
|
||||||
indent,
|
indent,
|
||||||
is_multiline,
|
is_multiline,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
if it.peek().is_some() {
|
if it.peek().is_some() {
|
||||||
|
@ -335,7 +382,7 @@ fn fmt_pattern_inner(
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str("]");
|
buf.push_str("]");
|
||||||
}
|
}
|
||||||
ListRest(opt_pattern_as) => {
|
Pattern::ListRest(opt_pattern_as) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str("..");
|
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;
|
let needs_parens = parens == Parens::InAsPattern;
|
||||||
|
|
||||||
if needs_parens {
|
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
|
||||||
Malformed(string) | MalformedIdent(string, _) => {
|
Pattern::Malformed(string) | Pattern::MalformedIdent(string, _) => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
buf.push_str(string);
|
buf.push_str(string);
|
||||||
}
|
}
|
||||||
QualifiedIdentifier { module_name, ident } => {
|
Pattern::QualifiedIdentifier { module_name, ident } => {
|
||||||
buf.indent(indent);
|
buf.indent(indent);
|
||||||
if !module_name.is_empty() {
|
if !module_name.is_empty() {
|
||||||
buf.push_str(module_name);
|
buf.push_str(module_name);
|
||||||
|
@ -382,18 +431,6 @@ fn fmt_pattern_inner(
|
||||||
snakify_camel_ident(buf, ident);
|
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>>>(
|
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
|
1
|
||||||
"""
|
"""
|
||||||
""" "^" 2 : A
|
"""
|
||||||
|
"^"
|
||||||
|
2 : A
|
||||||
""
|
""
|
|
@ -442,6 +442,7 @@ mod test_snapshots {
|
||||||
pass/list_patterns.expr,
|
pass/list_patterns.expr,
|
||||||
pass/lowest_float.expr,
|
pass/lowest_float.expr,
|
||||||
pass/lowest_int.expr,
|
pass/lowest_int.expr,
|
||||||
|
pass/mega_parens_pat.expr,
|
||||||
pass/min_parens_number.expr,
|
pass/min_parens_number.expr,
|
||||||
pass/minimal_app_header.header,
|
pass/minimal_app_header.header,
|
||||||
pass/minus_minus_block_string.expr,
|
pass/minus_minus_block_string.expr,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue