From 3b0db07fa1f06f79120adb88edab9e08d5b97d45 Mon Sep 17 00:00:00 2001 From: Anthony Bullard Date: Tue, 31 Dec 2024 08:25:11 -0600 Subject: [PATCH] PNC for Patterns, stabilize formatting --- crates/cli/src/format.rs | 2 +- crates/compiler/can/src/derive.rs | 7 +- crates/compiler/can/src/desugar.rs | 21 +- crates/compiler/can/src/pattern.rs | 2 +- ...ed_tests__trailing_suffix_inside_when.snap | 1 + crates/compiler/fmt/src/def.rs | 18 +- crates/compiler/fmt/src/expr.rs | 17 +- crates/compiler/fmt/src/pattern.rs | 60 ++++- crates/compiler/parse/src/ast.rs | 18 +- crates/compiler/parse/src/expr.rs | 148 ++++++------ crates/compiler/parse/src/normalize.rs | 5 +- crates/compiler/parse/src/parser.rs | 7 +- crates/compiler/parse/src/pattern.rs | 211 ++++++++++++++---- crates/compiler/parse/src/test_helpers.rs | 13 ++ .../compiler/test_syntax/src/bin/minimize.rs | 14 +- .../compiler/test_syntax/src/test_helpers.rs | 31 ++- ...d_empty_record_destructure.expr.result-ast | 1 + .../annotated_tag_destructure.expr.result-ast | 2 + ...y_tag_single_arg_pnc.pattern.formatted.roc | 1 + ...pply_tag_single_arg_pnc.pattern.result-ast | 16 ++ .../pass/apply_tag_single_arg_pnc.pattern.roc | 1 + ...ingle_arg_whitespace.pattern.formatted.roc | 1 + ...g_single_arg_whitespace.pattern.result-ast | 16 ++ ...pply_tag_single_arg_whitespace.pattern.roc | 1 + .../pass/arg_pattern_as.expr.result-ast | 1 + ...mplex_pattern_indent_issue.expr.result-ast | 1 + ..._parens_double_newlines.expr.formatted.roc | 2 +- ...ure_parens_double_newlines.expr.result-ast | 1 + .../comment_in_closure_pat.expr.result-ast | 1 + ...mment_in_closure_pat_apply.expr.result-ast | 1 + ...omment_indent_in_parens.expr.formatted.roc | 2 +- .../comment_indent_in_parens.expr.result-ast | 3 +- .../crazy_annotation_left.expr.formatted.roc | 6 +- .../crazy_annotation_left.expr.result-ast | 53 +++-- .../crazy_annotation_left2.expr.formatted.roc | 4 +- .../crazy_annotation_left2.expr.result-ast | 59 ++--- .../pass/crazy_pat_ann.expr.result-ast | 1 + ...destructure_tag_assignment.expr.result-ast | 1 + ...e_parens_comment_tuple_pat.expr.result-ast | 2 + ...r_comment_with_newline.expr.formatted.roc} | 0 ...fter_comment_with_newline.expr.result-ast} | 30 +-- ...ements_after_comment_with_newline.expr.roc | 3 + .../implements_after_parens_comment.expr.roc | 3 - ...ments_in_pat_after_comment.expr.result-ast | 1 + .../pass/mega_parens_pat.expr.formatted.roc | 6 +- .../pass/mega_parens_pat.expr.result-ast | 44 ++-- ...ply_equals_multiline_apply.expr.result-ast | 1 + ..._str_after_newlines_in_pat.expr.result-ast | 1 + ...iline_str_and_str_in_alias.expr.result-ast | 2 + ...ne_str_apply_in_parens_pat.expr.result-ast | 2 + .../pass/multiline_str_in_pat.expr.result-ast | 1 + .../pass/neg_nested_parens.expr.formatted.roc | 9 +- .../pass/neg_nested_parens.expr.result-ast | 64 +++--- ...ist_comment_in_closure_arg.expr.result-ast | 1 + .../nested_parens_in_pattern.expr.result-ast | 1 + ...nested_when_comment_in_pat.expr.result-ast | 1 + ...ructure_first_item_in_body.expr.result-ast | 1 + ...nce_pattern_with_arguments.expr.result-ast | 1 + .../parens_in_type_def_apply.expr.result-ast | 1 + .../pattern_comma_newlines.expr.formatted.roc | 5 +- .../pattern_comma_newlines.expr.result-ast | 25 +-- ...ttern_record_apply_comment.expr.result-ast | 1 + .../pattern_with_as_parens.expr.result-ast | 1 + ...ttern_with_space_in_parens.expr.result-ast | 2 + .../quotes_in_parens_in_pat.expr.result-ast | 1 + .../snapshots/pass/repr_7342.expr.result-ast | 1 + .../snapshots/pass/repr_7346.expr.result-ast | 1 + .../pass/tag_destructure_bang.expr.result-ast | 1 + ..._destructure_bang_no_space.expr.result-ast | 1 + .../triple_paren_pat_ann.expr.formatted.roc | 2 +- .../pass/triple_paren_pat_ann.expr.result-ast | 43 ++-- .../triple_quote_craziness.expr.result-ast | 1 + ...core_in_assignment_pattern.expr.result-ast | 6 + .../pass/when_result_list.expr.result-ast | 1 + crates/compiler/test_syntax/tests/test_fmt.rs | 89 ++++++++ .../test_syntax/tests/test_snapshots.rs | 9 +- crates/language_server/src/analysis/tokens.rs | 2 +- crates/reporting/src/error/parse.rs | 4 +- 78 files changed, 789 insertions(+), 332 deletions(-) create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.formatted.roc create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.result-ast create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.roc create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.formatted.roc create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.result-ast create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.roc rename crates/compiler/test_syntax/tests/snapshots/pass/{implements_after_parens_comment.expr.formatted.roc => implements_after_comment_with_newline.expr.formatted.roc} (100%) rename crates/compiler/test_syntax/tests/snapshots/pass/{implements_after_parens_comment.expr.result-ast => implements_after_comment_with_newline.expr.result-ast} (64%) create mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/implements_after_comment_with_newline.expr.roc delete mode 100644 crates/compiler/test_syntax/tests/snapshots/pass/implements_after_parens_comment.expr.roc diff --git a/crates/cli/src/format.rs b/crates/cli/src/format.rs index 96592a3461..3e82628f84 100644 --- a/crates/cli/src/format.rs +++ b/crates/cli/src/format.rs @@ -190,7 +190,7 @@ pub enum FormatProblem { pub fn format_src(arena: &Bump, src: &str, flags: MigrationFlags) -> Result { let ast = arena.alloc(parse_all(arena, src).unwrap_or_else(|e| { - user_error!("Unexpected parse failure when parsing this formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, e) + user_error!("Unexpected parse failure when parsing this formatting:\n\n{src}\n\nParse error was:\n\n{:#?}\n\n", e) })); let mut buf = Buf::new_in(arena, flags); fmt_all(&mut buf, ast); diff --git a/crates/compiler/can/src/derive.rs b/crates/compiler/can/src/derive.rs index 8e45c06146..04fc1e2983 100644 --- a/crates/compiler/can/src/derive.rs +++ b/crates/compiler/can/src/derive.rs @@ -8,7 +8,7 @@ use roc_error_macros::internal_error; use roc_module::{called_via::CalledVia, symbol::Symbol}; -use roc_parse::ast::{self, Collection}; +use roc_parse::ast::{self, Collection, PatternApplyStyle}; use roc_region::all::{Loc, Region}; use crate::{env::Env, pattern::Pattern, scope::Scope}; @@ -27,6 +27,7 @@ fn to_encoder<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { DERIVED_REGION, ast::Pattern::Identifier { ident: payload }, )]), + ast::PatternApplyStyle::Whitespace, ); // Encode.toEncoder payload @@ -132,6 +133,7 @@ fn hash<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { DERIVED_REGION, ast::Pattern::Identifier { ident: payload }, )]), + PatternApplyStyle::Whitespace, ); // Hash.hash hasher payload @@ -178,6 +180,7 @@ fn is_eq<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { DERIVED_REGION, ast::Pattern::Identifier { ident: payload1 }, )]), + PatternApplyStyle::Whitespace, ); // \@Opaq payload2 let opaque2 = ast::Pattern::Apply( @@ -186,6 +189,7 @@ fn is_eq<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { DERIVED_REGION, ast::Pattern::Identifier { ident: payload2 }, )]), + PatternApplyStyle::Whitespace, ); // Bool.isEq payload1 payload2 @@ -232,6 +236,7 @@ fn to_inspector<'a>(env: &mut Env<'a>, at_opaque: &'a str) -> ast::Expr<'a> { DERIVED_REGION, ast::Pattern::Identifier { ident: payload }, )]), + PatternApplyStyle::Whitespace, ); // Inspect.toInspector payload diff --git a/crates/compiler/can/src/desugar.rs b/crates/compiler/can/src/desugar.rs index 5ba9ede2b6..d81630a14c 100644 --- a/crates/compiler/can/src/desugar.rs +++ b/crates/compiler/can/src/desugar.rs @@ -11,8 +11,9 @@ use roc_module::called_via::{BinOp, CalledVia}; use roc_module::ident::ModuleName; use roc_parse::ast::Expr::{self, *}; use roc_parse::ast::{ - is_expr_suffixed, AssignedField, Collection, Defs, ModuleImportParams, Pattern, ResultTryKind, - StrLiteral, StrSegment, TryTarget, TypeAnnotation, ValueDef, WhenBranch, + is_expr_suffixed, AssignedField, Collection, Defs, ModuleImportParams, Pattern, + PatternApplyStyle, ResultTryKind, StrLiteral, StrSegment, TryTarget, TypeAnnotation, ValueDef, + WhenBranch, }; use roc_problem::can::Problem; use roc_region::all::{Loc, Region}; @@ -177,7 +178,11 @@ fn new_op_call_expr<'a>( env.arena.alloc(Loc::at(left.region, Pattern::Tag("Ok"))); branch_1_patts.push(Loc::at( left.region, - Pattern::Apply(branch_1_tag, branch_1_patts_args.into_bump_slice()), + Pattern::Apply( + branch_1_tag, + branch_1_patts_args.into_bump_slice(), + PatternApplyStyle::ParensAndCommas, + ), )); let branch_one: &WhenBranch<'_> = env.arena.alloc(WhenBranch { patterns: branch_1_patts.into_bump_slice(), @@ -198,7 +203,11 @@ fn new_op_call_expr<'a>( env.arena.alloc(Loc::at(left.region, Pattern::Tag("Err"))); branch_2_patts.push(Loc::at( right.region, - Pattern::Apply(branch_2_tag, branch_2_patts_args.into_bump_slice()), + Pattern::Apply( + branch_2_tag, + branch_2_patts_args.into_bump_slice(), + PatternApplyStyle::ParensAndCommas, + ), )); let branch_two: &WhenBranch<'_> = env.arena.alloc(WhenBranch { patterns: branch_2_patts.into_bump_slice(), @@ -1413,7 +1422,7 @@ fn desugar_pattern<'a>(env: &mut Env<'a>, scope: &mut Scope, pattern: Pattern<'a | MalformedIdent(_, _) | QualifiedIdentifier { .. } => pattern, - Apply(tag, arg_patterns) => { + Apply(tag, arg_patterns, style) => { // Skip desugaring the tag, it should either be a Tag or OpaqueRef let mut desugared_arg_patterns = Vec::with_capacity_in(arg_patterns.len(), env.arena); for arg_pattern in arg_patterns.iter() { @@ -1423,7 +1432,7 @@ fn desugar_pattern<'a>(env: &mut Env<'a>, scope: &mut Scope, pattern: Pattern<'a }); } - Apply(tag, desugared_arg_patterns.into_bump_slice()) + Apply(tag, desugared_arg_patterns.into_bump_slice(), style) } RecordDestructure(field_patterns) => { RecordDestructure(desugar_record_destructures(env, scope, field_patterns)) diff --git a/crates/compiler/can/src/pattern.rs b/crates/compiler/can/src/pattern.rs index 70e67df44a..e8976f24b9 100644 --- a/crates/compiler/can/src/pattern.rs +++ b/crates/compiler/can/src/pattern.rs @@ -411,7 +411,7 @@ pub fn canonicalize_pattern<'a>( ))); Pattern::UnsupportedPattern(region) } - Apply(tag, patterns) => { + Apply(tag, patterns, _) => { let mut can_patterns = Vec::with_capacity(patterns.len()); for loc_pattern in *patterns { let can_pattern = canonicalize_pattern( diff --git a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__trailing_suffix_inside_when.snap b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__trailing_suffix_inside_when.snap index b8f0160911..86f970af63 100644 --- a/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__trailing_suffix_inside_when.snap +++ b/crates/compiler/can/tests/snapshots/test_suffixed__suffixed_tests__trailing_suffix_inside_when.snap @@ -78,6 +78,7 @@ Defs { ident: "name", }, ], + Whitespace, ), ], value: @125-154 Apply( diff --git a/crates/compiler/fmt/src/def.rs b/crates/compiler/fmt/src/def.rs index eefab0bc61..5296b468d4 100644 --- a/crates/compiler/fmt/src/def.rs +++ b/crates/compiler/fmt/src/def.rs @@ -13,14 +13,14 @@ use crate::pattern::{pattern_lift_spaces, pattern_lift_spaces_before}; use crate::spaces::{ fmt_comments_only, fmt_default_newline, fmt_default_spaces, fmt_spaces, NewlineAt, INDENT, }; -use crate::Buf; +use crate::{Buf, MigrationFlags}; use bumpalo::Bump; use roc_error_macros::internal_error; use roc_parse::ast::{ AbilityMember, Defs, Expr, ExtractSpaces, ImportAlias, ImportAsKeyword, ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport, - ModuleImportParams, Pattern, Spaceable, Spaces, SpacesAfter, SpacesBefore, StrLiteral, - TypeAnnotation, TypeDef, TypeHeader, ValueDef, + ModuleImportParams, Pattern, PatternApplyStyle, Spaceable, Spaces, SpacesAfter, SpacesBefore, + StrLiteral, TypeAnnotation, TypeDef, TypeHeader, ValueDef, }; use roc_parse::expr::merge_spaces; use roc_parse::header::Keyword; @@ -564,6 +564,11 @@ impl<'a> Formattable for TypeHeader<'a> { _newlines: Newlines, indent: u16, ) { + let old_flags = buf.flags; + buf.flags = MigrationFlags { + parens_and_commas: false, + ..old_flags + }; pattern_fmt_apply( buf, Pattern::Tag(self.name.value), @@ -571,7 +576,9 @@ impl<'a> Formattable for TypeHeader<'a> { Parens::NotNeeded, indent, self.vars.iter().any(|v| v.is_multiline()), + PatternApplyStyle::Whitespace, ); + buf.flags = old_flags; } } @@ -582,6 +589,7 @@ fn type_head_lift_spaces<'a, 'b: 'a>( let pat = Pattern::Apply( arena.alloc(Loc::at(head.name.region, Pattern::Tag(head.name.value))), head.vars, + PatternApplyStyle::Whitespace, ); pattern_lift_spaces(arena, &pat) @@ -903,7 +911,9 @@ impl<'a> Formattable for ValueDef<'a> { fn ann_pattern_needs_parens(value: &Pattern<'_>) -> bool { match value.extract_spaces().item { Pattern::Tag(_) => true, - Pattern::Apply(func, _args) if matches!(func.extract_spaces().item, Pattern::Tag(..)) => { + Pattern::Apply(func, _args, _style) + if matches!(func.extract_spaces().item, Pattern::Tag(..)) => + { true } _ => false, diff --git a/crates/compiler/fmt/src/expr.rs b/crates/compiler/fmt/src/expr.rs index 2d64d5c88a..ee817e8336 100644 --- a/crates/compiler/fmt/src/expr.rs +++ b/crates/compiler/fmt/src/expr.rs @@ -11,7 +11,7 @@ use crate::spaces::{ use crate::Buf; use bumpalo::collections::Vec; use bumpalo::Bump; -use roc_module::called_via::{self, BinOp, UnaryOp}; +use roc_module::called_via::{self, BinOp, CalledVia, UnaryOp}; use roc_parse::ast::{ AssignedField, Base, Collection, CommentOrNewline, Expr, ExtractSpaces, Pattern, Spaceable, Spaces, SpacesAfter, SpacesBefore, TryTarget, WhenBranch, @@ -96,8 +96,9 @@ fn format_expr_only( } Expr::Apply(loc_expr, loc_args, _) => { let apply_needs_parens = parens == Parens::InApply || parens == Parens::InApplyLastArg; - - if apply_needs_parens && !loc_args.is_empty() { + if buf.flags().parens_and_commas { + fmt_apply(loc_expr, loc_args, indent, buf, false); + } else if apply_needs_parens && !loc_args.is_empty() { fmt_parens(item, buf, indent); } else { fmt_apply(loc_expr, loc_args, indent, buf, false); @@ -716,7 +717,9 @@ fn fmt_apply( let is_first_arg = i == 0; let arg = expr_lift_spaces( - if is_last_arg { + if use_commas_and_parens { + Parens::NotNeeded + } else if is_last_arg { Parens::InApplyLastArg } else { Parens::InApply @@ -1038,7 +1041,7 @@ pub fn expr_lift_spaces<'a, 'b: 'a>( ) -> Spaces<'a, Expr<'a>> { match expr { Expr::Apply(func, args, called_via) => { - if args.is_empty() { + if args.is_empty() && !matches!(called_via, CalledVia::ParensAndCommas) { return expr_lift_spaces(Parens::NotNeeded, arena, &func.value); } @@ -1082,7 +1085,9 @@ pub fn expr_lift_spaces<'a, 'b: 'a>( } }; - if parens == Parens::InApply || parens == Parens::InApplyLastArg { + if (parens == Parens::InApply || parens == Parens::InApplyLastArg) + && !matches!(called_via, CalledVia::ParensAndCommas) + { res = Spaces { before: &[], item: Expr::ParensAround(arena.alloc(lower(arena, res))), diff --git a/crates/compiler/fmt/src/pattern.rs b/crates/compiler/fmt/src/pattern.rs index 5dfa321295..b256e47f91 100644 --- a/crates/compiler/fmt/src/pattern.rs +++ b/crates/compiler/fmt/src/pattern.rs @@ -7,7 +7,8 @@ use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt, INDENT}; use crate::Buf; use bumpalo::Bump; use roc_parse::ast::{ - Base, CommentOrNewline, Pattern, PatternAs, Spaceable, Spaces, SpacesAfter, SpacesBefore, + Base, CommentOrNewline, Pattern, PatternApplyStyle, PatternAs, Spaceable, Spaces, SpacesAfter, + SpacesBefore, }; use roc_parse::expr::merge_spaces; use roc_region::all::Loc; @@ -72,7 +73,7 @@ impl<'a> Formattable for Pattern<'a> { } }, Pattern::StrLiteral(literal) => is_str_multiline(literal), - Pattern::Apply(pat, args) => { + Pattern::Apply(pat, args, _) => { pat.is_multiline() || args.iter().any(|a| a.is_multiline()) } @@ -162,7 +163,22 @@ fn fmt_pattern_only( buf.indent(indent); buf.push_str(name); } - Pattern::Apply(loc_pattern, loc_arg_patterns) => { + Pattern::Apply( + loc_pattern, + loc_arg_patterns, + style @ PatternApplyStyle::ParensAndCommas, + ) => { + pattern_fmt_apply( + buf, + loc_pattern.value, + loc_arg_patterns, + Parens::NotNeeded, + indent, + is_multiline, + *style, + ); + } + Pattern::Apply(loc_pattern, loc_arg_patterns, style) => { pattern_fmt_apply( buf, loc_pattern.value, @@ -170,6 +186,7 @@ fn fmt_pattern_only( parens, indent, is_multiline, + *style, ); } Pattern::RecordDestructure(loc_patterns) => { @@ -445,11 +462,14 @@ pub fn pattern_fmt_apply( parens: Parens, indent: u16, is_multiline: bool, + style: PatternApplyStyle, ) { + let use_commas_and_parens = + matches!(style, PatternApplyStyle::ParensAndCommas) || buf.flags().parens_and_commas; buf.indent(indent); // Sometimes, an Apply pattern needs parens around it. // In particular when an Apply's argument is itself an Apply (> 0) arguments - let parens = !args.is_empty() && parens == Parens::InApply; + let parens = !args.is_empty() && parens == Parens::InApply && !use_commas_and_parens; let indent_more = if is_multiline { indent + INDENT @@ -473,14 +493,27 @@ pub fn pattern_fmt_apply( fmt_pattern_only(&func.item, buf, Parens::InApply, indent, is_multiline); + if use_commas_and_parens { + buf.push('('); + } + let mut last_after = func.after; let mut add_newlines = is_multiline; - for loc_arg in args.iter() { - buf.spaces(1); + for (i, loc_arg) in args.iter().enumerate() { + let is_last_arg = i == args.len() - 1; + let is_first_arg = i == 0; - let parens = Parens::InApply; + if !(is_first_arg && use_commas_and_parens) { + buf.spaces(1); + } + + let parens = if use_commas_and_parens { + Parens::NotNeeded + } else { + Parens::InApply + }; let arg = pattern_lift_spaces(buf.text.bump(), &loc_arg.value); let mut was_multiline = arg.item.is_multiline(); @@ -527,6 +560,9 @@ pub fn pattern_fmt_apply( buf.push_str("(implements)"); } else { fmt_pattern_only(&arg.item, buf, parens, indent_more, arg.item.is_multiline()); + if use_commas_and_parens && (!is_last_arg || add_newlines) { + buf.push(','); + } } last_after = arg.after; @@ -542,7 +578,7 @@ pub fn pattern_fmt_apply( } } - if parens { + if parens || use_commas_and_parens { buf.push(')'); } } @@ -597,7 +633,7 @@ fn pattern_prec(pat: Pattern<'_>) -> Prec { | Pattern::Tuple(..) | Pattern::List(..) | Pattern::ListRest(_) => Prec::Term, - Pattern::Apply(_, _) | Pattern::As(_, _) => Prec::Apply, + Pattern::Apply(_, _, _) | Pattern::As(_, _) => Prec::Apply, Pattern::SpaceBefore(inner, _) | Pattern::SpaceAfter(inner, _) => pattern_prec(*inner), Pattern::Malformed(_) | Pattern::MalformedIdent(..) => Prec::Term, } @@ -617,7 +653,7 @@ pub fn pattern_lift_spaces<'a, 'b: 'a>( pat: &Pattern<'b>, ) -> Spaces<'a, Pattern<'a>> { match pat { - Pattern::Apply(func, args) => { + Pattern::Apply(func, args, style) => { let func_lifted = pattern_lift_spaces(arena, &func.value); let args = arena.alloc_slice_copy(args); @@ -652,7 +688,7 @@ pub fn pattern_lift_spaces<'a, 'b: 'a>( }; Spaces { before, - item: Pattern::Apply(arena.alloc(func), args), + item: Pattern::Apply(arena.alloc(func), args, *style), after, } } @@ -712,7 +748,7 @@ fn handle_multiline_str_spaces<'a>(pat: &Pattern<'_>, before: &mut &'a [CommentO fn starts_with_block_str(item: &Pattern<'_>) -> bool { match item { - Pattern::As(inner, _) | Pattern::Apply(inner, _) => starts_with_block_str(&inner.value), + Pattern::As(inner, _) | Pattern::Apply(inner, _, _) => starts_with_block_str(&inner.value), Pattern::SpaceBefore(inner, _) | Pattern::SpaceAfter(inner, _) => { starts_with_block_str(inner) } diff --git a/crates/compiler/parse/src/ast.rs b/crates/compiler/parse/src/ast.rs index d31baaaf35..dfac5b9903 100644 --- a/crates/compiler/parse/src/ast.rs +++ b/crates/compiler/parse/src/ast.rs @@ -1745,6 +1745,12 @@ impl<'a> PatternAs<'a> { } } +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum PatternApplyStyle { + Whitespace, + ParensAndCommas, +} + #[derive(Clone, Copy, Debug, PartialEq)] pub enum Pattern<'a> { // Identifier @@ -1760,7 +1766,11 @@ pub enum Pattern<'a> { OpaqueRef(&'a str), - Apply(&'a Loc>, &'a [Loc>]), + Apply( + &'a Loc>, + &'a [Loc>], + PatternApplyStyle, + ), /// This is Located rather than Located so we can record comments /// around the destructured names, e.g. { x ### x does stuff ###, y } @@ -1841,8 +1851,8 @@ impl<'a> Pattern<'a> { false } } - Apply(constructor_x, args_x) => { - if let Apply(constructor_y, args_y) = other { + Apply(constructor_x, args_x, _) => { + if let Apply(constructor_y, args_y, _) = other { let equivalent_args = args_x .iter() .zip(args_y.iter()) @@ -2670,7 +2680,7 @@ impl<'a> Malformed for Pattern<'a> { Identifier{ .. } | Tag(_) | OpaqueRef(_) => false, - Apply(func, args) => func.is_malformed() || args.iter().any(|arg| arg.is_malformed()), + Apply(func, args, _) => func.is_malformed() || args.iter().any(|arg| arg.is_malformed()), RecordDestructure(items) => items.iter().any(|item| item.is_malformed()), RequiredField(_, pat) => pat.is_malformed(), OptionalField(_, expr) => expr.is_malformed(), diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 51ea06eabe..0b9d674f03 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -2,8 +2,8 @@ use crate::ast::{ is_expr_suffixed, AssignedField, Collection, CommentOrNewline, Defs, Expr, ExtractSpaces, Implements, ImplementsAbilities, ImportAlias, ImportAsKeyword, ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport, - ModuleImportParams, Pattern, Spaceable, Spaced, Spaces, SpacesBefore, TryTarget, - TypeAnnotation, TypeDef, TypeHeader, ValueDef, + ModuleImportParams, Pattern, PatternApplyStyle, Spaceable, Spaced, Spaces, SpacesBefore, + TryTarget, TypeAnnotation, TypeDef, TypeHeader, ValueDef, }; use crate::blankspace::{ loc_space0_e, require_newline_or_eof, space0_after_e, space0_around_ee, space0_before_e, @@ -181,7 +181,7 @@ fn loc_term_or_underscore_or_conditional<'a>( } } - loc_term_or_underscore(check_for_arrow).parse(arena, state, min_indent) + loc_term_or_closure(check_for_arrow).parse(arena, state, min_indent) } } fn loc_conditional<'a>( @@ -198,84 +198,80 @@ fn loc_conditional<'a>( /// In some contexts we want to parse the `_` as an expression, so it can then be turned into a /// pattern later -fn loc_term_or_underscore<'a>( +fn loc_term_or_closure<'a>( check_for_arrow: CheckForArrow, ) -> impl Parser<'a, Loc>, EExpr<'a>> { one_of!( - loc_expr_in_parens_etc_help(), - loc(specialize_err(EExpr::Str, string_like_literal_help())), - loc(specialize_err( - EExpr::Number, - positive_number_literal_help() - )), loc(specialize_err( EExpr::Closure, closure_help(check_for_arrow) )), - loc(crash_kw()), - loc(specialize_err(EExpr::Dbg, dbg_kw())), - loc(try_kw()), - loc(underscore_expression()), - loc(record_literal_help()), - loc(specialize_err(EExpr::List, list_literal_help())), - loc(apply_with_pnc()), - ident_seq(), + loc_term(), ) .trace("term_or_underscore") } -fn loc_term<'a>(check_for_arrow: CheckForArrow) -> impl Parser<'a, Loc>, EExpr<'a>> { - one_of!( - loc_expr_in_parens_etc_help(), - loc(specialize_err(EExpr::Str, string_like_literal_help())), - loc(specialize_err( - EExpr::Number, - positive_number_literal_help() - )), - loc(specialize_err( - EExpr::Closure, - closure_help(check_for_arrow) - )), - loc(crash_kw()), - loc(specialize_err(EExpr::Dbg, dbg_kw())), - loc(try_kw()), - loc(record_literal_help()), - loc(specialize_err(EExpr::List, list_literal_help())), - loc(apply_with_pnc()), - ident_seq(), +fn loc_term<'a>() -> impl Parser<'a, Loc>, EExpr<'a>> { + map_with_arena( + and( + one_of!( + loc_expr_in_parens_etc_help(), + loc(specialize_err(EExpr::Str, string_like_literal_help())), + loc(specialize_err( + EExpr::Number, + positive_number_literal_help() + )), + loc(crash_kw()), + loc(specialize_err(EExpr::Dbg, dbg_kw())), + loc(try_kw()), + loc(underscore_expression()), + loc(record_literal_help()), + loc(specialize_err(EExpr::List, list_literal_help())), + ident_seq(), + ), + optional(pnc_args()), + ), + |arena, (expr, maybe_arg_loc)| { + if let Some(arg_loc) = maybe_arg_loc { + let e = Expr::Apply(arena.alloc(expr), arg_loc.value, CalledVia::ParensAndCommas); + Loc { + value: e, + region: Region::span_across(&expr.region, &arg_loc.region), + } + } else { + expr + } + }, ) + .trace("term") } -fn apply_with_pnc<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> { +fn pnc_args<'a>() -> impl Parser<'a, Loc<&'a [&'a Loc>]>, EExpr<'a>> { |arena: &'a Bump, state: State<'a>, min_indent: u32| { - let (_, ident, new_state) = ident_seq().parse(arena, state, min_indent)?; - - let (_, args, newer_state) = specialize_err( - EExpr::InParens, - collection_trailing_sep_e( - byte(b'(', EInParens::Open), - specialize_err_ref(EInParens::Expr, loc_expr_block(false, true)), - byte(b',', EInParens::End), - byte(b')', EInParens::End), - Expr::SpaceBefore, + map_with_arena( + specialize_err( + EExpr::InParens, + loc(collection_trailing_sep_e( + byte(b'(', EInParens::Open), + specialize_err_ref(EInParens::Expr, loc_expr_block(true)), + byte(b',', EInParens::End), + byte(b')', EInParens::End), + Expr::SpaceBefore, + )), ), + |arena, arg_loc| { + let mut args_vec = Vec::new_in(arena); + for arg in arg_loc.value.items.iter() { + let a: &Loc> = arena.alloc(arg); + args_vec.push(a); + } + Loc { + value: args_vec.into_bump_slice(), + region: arg_loc.region, + } + }, ) - .parse(arena, new_state, min_indent)?; - - let arg_slice: &[&Loc>] = { - let mut args_vec = Vec::new_in(arena); - for arg in args.items.iter() { - let a: &Loc> = arena.alloc(arg); - args_vec.push(a); - } - args_vec.into_bump_slice() - }; - - Ok(( - Progress::MadeProgress, - Expr::Apply(arena.alloc(ident), arg_slice, CalledVia::ParensAndCommas), - newer_state, - )) + .parse(arena, state, min_indent) } } @@ -1743,7 +1739,8 @@ fn parse_negated_term<'a>( initial_state: State<'a>, loc_op: Loc, ) -> ParseResult<'a, Expr<'a>, EExpr<'a>> { - let (_, negated_expr, state) = loc_term(check_for_arrow).parse(arena, state, min_indent)?; + let (_, negated_expr, state) = + loc_term_or_closure(check_for_arrow).parse(arena, state, min_indent)?; let new_end = state.pos(); let arg = numeric_negate_expression( @@ -1793,7 +1790,7 @@ fn parse_expr_end<'a>( ) -> ParseResult<'a, Expr<'a>, EExpr<'a>> { let parser = skip_first( crate::blankspace::check_indent(EExpr::IndentEnd), - loc_term_or_underscore(check_for_arrow), + loc_term_or_closure(check_for_arrow), ); match parser.parse(arena, state.clone(), call_min_indent) { @@ -2089,7 +2086,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result Pattern::Underscore(opt_name), Expr::Tag(value) => Pattern::Tag(value), Expr::OpaqueRef(value) => Pattern::OpaqueRef(value), - Expr::Apply(loc_val, loc_args, _) => { + Expr::Apply(loc_val, loc_args, called_via) => { let region = loc_val.region; let value = expr_to_pattern_help(arena, &loc_val.value)?; let val_pattern = arena.alloc(Loc { region, value }); @@ -2103,7 +2100,15 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result) -> bool { | Pattern::ListRest(_) | Pattern::OpaqueRef(_) => false, Pattern::As(left, _) => starts_with_spaces_conservative(&left.value), - Pattern::Apply(left, _) => starts_with_spaces_conservative(&left.value), + Pattern::Apply(left, _, _) => starts_with_spaces_conservative(&left.value), Pattern::RecordDestructure(_) => false, Pattern::RequiredField(_, _) | Pattern::OptionalField(_, _) => false, Pattern::SpaceBefore(_, _) => true, @@ -3293,6 +3298,7 @@ fn header_to_pat<'a>(arena: &'a Bump, header: TypeHeader<'a>) -> Pattern<'a> { Pattern::Apply( arena.alloc(Loc::at(header.name.region, Pattern::Tag(header.name.value))), header.vars, + PatternApplyStyle::Whitespace, ) } } @@ -3343,7 +3349,7 @@ fn pat_ends_with_spaces_conservative(pat: &Pattern<'_>) -> bool { | Pattern::ListRest(_) | Pattern::As(_, _) | Pattern::OpaqueRef(_) => false, - Pattern::Apply(_, args) => args + Pattern::Apply(_, args, _) => args .last() .map_or(false, |a| pat_ends_with_spaces_conservative(&a.value)), Pattern::RecordDestructure(_) => false, @@ -3365,7 +3371,7 @@ pub fn join_alias_to_body<'a>( body_expr: &'a Loc>, ) -> ValueDef<'a> { let loc_name = arena.alloc(header.name.map(|x| Pattern::Tag(x))); - let ann_pattern = Pattern::Apply(loc_name, header.vars); + let ann_pattern = Pattern::Apply(loc_name, header.vars, PatternApplyStyle::Whitespace); let vars_region = Region::across_all(header.vars.iter().map(|v| &v.region)); let region_ann_pattern = Region::span_across(&loc_name.region, &vars_region); diff --git a/crates/compiler/parse/src/normalize.rs b/crates/compiler/parse/src/normalize.rs index 9fe034ade8..6ab1abad0e 100644 --- a/crates/compiler/parse/src/normalize.rs +++ b/crates/compiler/parse/src/normalize.rs @@ -879,9 +879,10 @@ impl<'a> Normalize<'a> for Pattern<'a> { Pattern::Identifier { ident } => Pattern::Identifier { ident }, Pattern::Tag(a) => Pattern::Tag(a), Pattern::OpaqueRef(a) => Pattern::OpaqueRef(a), - Pattern::Apply(a, b) => Pattern::Apply( + Pattern::Apply(a, b, c) => Pattern::Apply( arena.alloc(a.normalize(arena)), arena.alloc(b.normalize(arena)), + c, ), Pattern::RecordDestructure(a) => Pattern::RecordDestructure(a.normalize(arena)), Pattern::RequiredField(a, b) => { @@ -1257,6 +1258,8 @@ impl<'a> Normalize<'a> for EPattern<'a> { EPattern::AccessorFunction(_) => EPattern::AccessorFunction(Position::zero()), EPattern::RecordUpdaterFunction(_) => EPattern::RecordUpdaterFunction(Position::zero()), EPattern::Str(e, _) => EPattern::Str(e.normalize(arena), Position::zero()), + EPattern::ParenStart(_) => EPattern::ParenStart(Position::zero()), + EPattern::ParenEnd(_) => EPattern::ParenEnd(Position::zero()), } } } diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 4723dfbb26..acc9b53b1a 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1066,6 +1066,9 @@ pub enum EPattern<'a> { AccessorFunction(Position), RecordUpdaterFunction(Position), Str(EString<'a>, Position), + + ParenStart(Position), + ParenEnd(Position), } impl<'a> EPattern<'a> { @@ -1090,7 +1093,9 @@ impl<'a> EPattern<'a> { | EPattern::IndentEnd(position) | EPattern::AsIndentStart(position) | EPattern::AccessorFunction(position) - | EPattern::RecordUpdaterFunction(position) => Region::from_pos(*position), + | EPattern::RecordUpdaterFunction(position) + | EPattern::ParenStart(position) + | EPattern::ParenEnd(position) => Region::from_pos(*position), } } } diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index 65538e8003..d059091619 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -1,11 +1,13 @@ -use crate::ast::{Collection, ExtractSpaces, Implements, Pattern, PatternAs, Spaceable}; -use crate::blankspace::{space0_e, spaces, spaces_before}; +use crate::ast::{ + Collection, ExtractSpaces, Implements, Pattern, PatternApplyStyle, PatternAs, Spaceable, +}; +use crate::blankspace::{space0_before_optional_after, space0_e, spaces, spaces_before}; use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident}; use crate::keyword; use crate::parser::{ - self, backtrackable, byte, collection_trailing_sep_e, fail_when, loc, map, optional, - skip_first, specialize_err, specialize_err_ref, then, three_bytes, two_bytes, zero_or_more, - EPattern, PInParens, PList, PRecord, Parser, + self, backtrackable, byte, collection_trailing_sep_e, fail_when, loc, map, map_with_arena, + optional, skip_first, skip_second, specialize_err, specialize_err_ref, then, three_bytes, + two_bytes, zero_or_more, EPattern, PInParens, PList, PRecord, Parser, }; use crate::parser::{either, Progress::*}; use crate::state::State; @@ -85,15 +87,16 @@ fn loc_pattern_help_help<'a>( ) -> impl Parser<'a, Loc>, EPattern<'a>> { one_of!( specialize_err(EPattern::PInParens, loc_pattern_in_parens_help()), + loc(string_like_pattern_help()), + loc(number_pattern_help()), loc(underscore_pattern_help()), - loc_ident_pattern_help(can_have_arguments), loc(specialize_err( EPattern::Record, crate::pattern::record_pattern_help() )), loc(specialize_err(EPattern::List, list_pattern_help())), - loc(number_pattern_help()), - loc(string_like_pattern_help()), + // Move my pnc tag apply parser here + loc_ident_pattern_help(can_have_arguments), ) } @@ -121,10 +124,6 @@ fn pattern_as<'a>() -> impl Parser<'a, PatternAs<'a>, EPattern<'a>> { } } -fn loc_tag_pattern_args_help<'a>() -> impl Parser<'a, Vec<'a, Loc>>, EPattern<'a>> { - zero_or_more(loc_tag_pattern_arg(false)) -} - /// Like `loc_tag_pattern_args_help`, but stops if a "implements" keyword is seen (indicating an ability). fn loc_type_def_tag_pattern_args_help<'a>( ) -> impl Parser<'a, Vec<'a, Loc>>, EPattern<'a>> { @@ -339,6 +338,37 @@ fn loc_ident_pattern_help<'a>( let (_, loc_ident, state) = specialize_err(|_, pos| EPattern::Start(pos), loc(parse_ident)) .parse(arena, state, min_indent)?; + let commas_and_paren_args_help = map_with_arena( + collection_trailing_sep_e( + byte(b'(', EPattern::ParenStart), + loc_tag_pattern_arg(false), + byte(b',', EPattern::NotAPattern), + byte(b')', EPattern::ParenEnd), + Pattern::SpaceBefore, + ), + |arena, args| { + let mut args_vec = Vec::new_in(arena); + for arg in args.iter() { + let a: &Loc> = arena.alloc(arg); + args_vec.push(*a); + } + ( + args_vec.into_bump_slice(), + PatternApplyStyle::ParensAndCommas, + ) + }, + ); + + let whitespace_args = + map_with_arena(loc_type_def_tag_pattern_args_help(), |arena, args| { + let mut args_vec = Vec::new_in(arena); + for arg in args.iter() { + let a: &Loc> = arena.alloc(arg); + args_vec.push(*a); + } + (args_vec.into_bump_slice(), PatternApplyStyle::Whitespace) + }); + match loc_ident.value { Ident::Tag(tag) => { let loc_tag = Loc { @@ -347,24 +377,29 @@ fn loc_ident_pattern_help<'a>( }; // Make sure `Foo Bar 1` is parsed as `Foo (Bar) 1`, and not `Foo (Bar 1)` - if can_have_arguments { - let (_, loc_args, state) = - loc_type_def_tag_pattern_args_help().parse(arena, state, min_indent)?; - - if loc_args.is_empty() { - Ok((MadeProgress, loc_tag, state)) - } else { - let region = Region::across_all( - std::iter::once(&loc_ident.region) - .chain(loc_args.iter().map(|loc_arg| &loc_arg.region)), - ); - let value = - Pattern::Apply(&*arena.alloc(loc_tag), loc_args.into_bump_slice()); - - Ok((MadeProgress, Loc { region, value }, state)) - } + let (_, (args, style), state) = if can_have_arguments { + one_of!(commas_and_paren_args_help, whitespace_args) + .parse(arena, state, min_indent)? } else { + match commas_and_paren_args_help.parse(arena, state.clone(), min_indent) { + Ok((_, res, new_state)) => (MadeProgress, res, new_state), + Err((NoProgress, _)) => return Ok((MadeProgress, loc_tag, state)), + Err((MadeProgress, e)) => return Err((MadeProgress, e)), + } + }; + + let loc_args: &[Loc>] = { args }; + + if loc_args.is_empty() { Ok((MadeProgress, loc_tag, state)) + } else { + let region = Region::across_all( + std::iter::once(&loc_ident.region) + .chain(loc_args.iter().map(|loc_arg| &loc_arg.region)), + ); + let value = Pattern::Apply(&*arena.alloc(loc_tag), loc_args, style); + + Ok((MadeProgress, Loc { region, value }, state)) } } Ident::OpaqueRef(name) => { @@ -374,24 +409,25 @@ fn loc_ident_pattern_help<'a>( }; // Make sure `@Foo Bar 1` is parsed as `@Foo (Bar) 1`, and not `@Foo (Bar 1)` - if can_have_arguments { - let (_, loc_args, state) = - loc_tag_pattern_args_help().parse(arena, state, min_indent)?; - - if loc_args.is_empty() { - Ok((MadeProgress, loc_pat, state)) - } else { - let region = Region::across_all( - std::iter::once(&loc_ident.region) - .chain(loc_args.iter().map(|loc_arg| &loc_arg.region)), - ); - let value = - Pattern::Apply(&*arena.alloc(loc_pat), loc_args.into_bump_slice()); - - Ok((MadeProgress, Loc { region, value }, state)) - } + let (_, (args, style), state) = if can_have_arguments { + one_of!(commas_and_paren_args_help, whitespace_args) + .parse(arena, state, min_indent)? } else { + commas_and_paren_args_help.parse(arena, state, min_indent)? + }; + + let loc_args: &[Loc>] = { args }; + + if loc_args.is_empty() { Ok((MadeProgress, loc_pat, state)) + } else { + let region = Region::across_all( + std::iter::once(&loc_ident.region) + .chain(loc_args.iter().map(|loc_arg| &loc_arg.region)), + ); + let value = Pattern::Apply(&*arena.alloc(loc_pat), loc_args, style); + + Ok((MadeProgress, Loc { region, value }, state)) } } Ident::Access { @@ -589,3 +625,90 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc>, PRecord<'a>> } } } + +pub fn pattern_end<'a>() -> impl Parser<'a, (), EPattern<'a>> { + |_arena, state: State<'a>, _min_indent: u32| { + if state.has_reached_end() { + Ok((NoProgress, (), state)) + } else { + Err((NoProgress, EPattern::End(state.pos()))) + } + } +} + +pub fn test_parse_pattern<'a>( + min_indent: u32, + arena: &'a bumpalo::Bump, + state: State<'a>, +) -> Result>, EPattern<'a>> { + let parser = skip_second( + space0_before_optional_after( + loc_pattern_help(), + EPattern::IndentStart, + EPattern::IndentEnd, + ), + pattern_end(), + ); + + match parser.parse(arena, state, min_indent) { + Ok((_, expression, _)) => Ok(expression), + Err((_, fail)) => Err(fail), + } +} + +#[cfg(test)] +mod test_parse_pattern { + use super::*; + use pretty_assertions::assert_eq; + use roc_region::all::Position; + + fn new_region(start: u32, end: u32) -> Region { + Region::new(Position::new(start), Position::new(end)) + } + + #[test] + fn test_parse_ident_tag() { + let arena = Bump::new(); + let state = State::new("Ok a".as_ref()); + let min_indent = 0; + let (_, res, _) = loc_pattern_help().parse(&arena, state, min_indent).unwrap(); + let expected_tag = Loc { + value: Pattern::Tag("Ok"), + region: new_region(0, 2), + }; + let expected_args = [Loc { + value: Pattern::Identifier { ident: "a" }, + region: new_region(3, 4), + }]; + let expected = Loc { + value: Pattern::Apply(&expected_tag, &expected_args, PatternApplyStyle::Whitespace), + region: new_region(0, 4), + }; + assert_eq!(format!("{res:#?}"), format!("{expected:#?}")); + } + + #[test] + fn test_parse_ident_tag_pnc() { + let arena = Bump::new(); + let state = State::new("Ok(a)".as_ref()); + let min_indent = 0; + let (_, res, _) = loc_pattern_help().parse(&arena, state, min_indent).unwrap(); + let expected_tag = Loc { + value: Pattern::Tag("Ok"), + region: new_region(0, 2), + }; + let expected_args = [Loc { + value: Pattern::Identifier { ident: "a" }, + region: new_region(3, 4), + }]; + let expected = Loc { + value: Pattern::Apply( + &expected_tag, + &expected_args, + PatternApplyStyle::ParensAndCommas, + ), + region: new_region(0, 4), + }; + assert_eq!(format!("{res:#?}"), format!("{expected:#?}")); + } +} diff --git a/crates/compiler/parse/src/test_helpers.rs b/crates/compiler/parse/src/test_helpers.rs index 194bab9c59..3e49ac2b69 100644 --- a/crates/compiler/parse/src/test_helpers.rs +++ b/crates/compiler/parse/src/test_helpers.rs @@ -1,6 +1,7 @@ use crate::ast; use crate::ast::Defs; use crate::ast::Header; +use crate::ast::Pattern; use crate::ast::SpacesBefore; use crate::header::parse_module_defs; use crate::parser::SourceError; @@ -32,6 +33,18 @@ pub fn parse_loc_with<'a>( } } +pub fn parse_pattern_with<'a>( + arena: &'a Bump, + input: &'a str, +) -> Result>, SourceError<'a, SyntaxError<'a>>> { + let state = State::new(input.as_bytes()); + + match crate::pattern::test_parse_pattern(0, arena, state.clone()) { + Ok(loc_patt) => Ok(loc_patt), + Err(fail) => Err(SyntaxError::Pattern(fail).into_source_error(&state)), + } +} + pub fn parse_defs_with<'a>(arena: &'a Bump, input: &'a str) -> Result, SyntaxError<'a>> { let state = State::new(input.as_bytes()); diff --git a/crates/compiler/test_syntax/src/bin/minimize.rs b/crates/compiler/test_syntax/src/bin/minimize.rs index de1cc72fda..bd5a763c13 100644 --- a/crates/compiler/test_syntax/src/bin/minimize.rs +++ b/crates/compiler/test_syntax/src/bin/minimize.rs @@ -10,6 +10,8 @@ //! //! Note that `--release` is important, as this tool is very slow in debug mode. +use std::io::Read; + use test_syntax::{ minimize::{print_minimizations, Options}, test_helpers::InputKind, @@ -18,7 +20,7 @@ use test_syntax::{ fn main() { let args = std::env::args().collect::>(); if args.len() < 3 || args.len() > 5 { - eprintln!("Usage: {} [--minimize-full-error] [--minimize-initial-parse-error] [expr|full|moduledefs|header] ", args[0]); + eprintln!("Usage: {} [--minimize-full-error] [--minimize-initial-parse-error] [expr|full|moduledefs|header|pattern] ", args[0]); std::process::exit(1); } @@ -46,13 +48,21 @@ fn main() { "full" => InputKind::Full, "moduledefs" => InputKind::ModuleDefs, "header" => InputKind::Header, + "pattern" => InputKind::Pattern, _ => { eprintln!("Invalid input kind: {}", args[index]); std::process::exit(1); } }; + let input = &args[index + 1]; + let mut buf = String::new(); + let text = if input == "-" { + std::io::stdin().read_to_string(&mut buf).unwrap(); + buf.to_string() + } else { + std::fs::read_to_string(input).unwrap() + }; - let text = std::fs::read_to_string(&args[index + 1]).unwrap(); let found_error = print_minimizations(&text, options); std::process::exit(if found_error { 0 } else { 1 }); } diff --git a/crates/compiler/test_syntax/src/test_helpers.rs b/crates/compiler/test_syntax/src/test_helpers.rs index 87bd70f3e3..7076e1401a 100644 --- a/crates/compiler/test_syntax/src/test_helpers.rs +++ b/crates/compiler/test_syntax/src/test_helpers.rs @@ -9,13 +9,13 @@ use roc_error_macros::set_panic_not_exit; use roc_fmt::{annotation::Formattable, header::fmt_header, MigrationFlags}; use roc_module::ident::QualifiedModuleName; use roc_module::symbol::{IdentIds, Interns, ModuleIds, PackageModuleIds, Symbol}; -use roc_parse::ast::RecursiveValueDefIter; use roc_parse::ast::ValueDef; +use roc_parse::ast::{Pattern, RecursiveValueDefIter}; use roc_parse::header::parse_module_defs; use roc_parse::parser::Parser; use roc_parse::parser::SyntaxError; use roc_parse::state::State; -use roc_parse::test_helpers::parse_loc_with; +use roc_parse::test_helpers::{parse_loc_with, parse_pattern_with}; use roc_parse::{ast::Malformed, normalize::Normalize}; use roc_parse::{ ast::{Defs, Expr, FullAst, Header, SpacesBefore}, @@ -45,6 +45,9 @@ pub enum Input<'a> { /// Both the header and the module defs Full(&'a str), + + /// A single pattern + Pattern(&'a str), } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -53,6 +56,7 @@ pub enum InputKind { ModuleDefs, Expr, Full, + Pattern, } impl InputKind { @@ -62,6 +66,7 @@ impl InputKind { InputKind::ModuleDefs => Input::ModuleDefs(text), InputKind::Expr => Input::Expr(text), InputKind::Full => Input::Full(text), + InputKind::Pattern => Input::Pattern(text), } } } @@ -73,6 +78,7 @@ pub enum InputOwned { ModuleDefs(String), Expr(String), Full(String), + Pattern(String), } impl InputOwned { @@ -82,6 +88,7 @@ impl InputOwned { InputOwned::ModuleDefs(s) => Input::ModuleDefs(s), InputOwned::Expr(s) => Input::Expr(s), InputOwned::Full(s) => Input::Full(s), + InputOwned::Pattern(s) => Input::Pattern(s), } } } @@ -96,6 +103,8 @@ pub enum Output<'a> { Expr(Loc>), Full(FullAst<'a>), + + Pattern(Loc>), } impl<'a> Output<'a> { @@ -127,6 +136,10 @@ impl<'a> Output<'a> { buf.fmt_end_of_file(); InputOwned::Full(buf.as_str().to_string()) } + Output::Pattern(patt) => { + patt.format(&mut buf, 0); + InputOwned::Pattern(buf.as_str().to_string()) + } } } @@ -136,6 +149,7 @@ impl<'a> Output<'a> { Output::ModuleDefs(defs) => format!("{defs:#?}\n"), Output::Expr(expr) => format!("{expr:#?}\n"), Output::Full { .. } => format!("{self:#?}\n"), + Output::Pattern(patt) => format!("{patt:#?}\n"), } } @@ -150,6 +164,7 @@ impl<'a> Output<'a> { Output::Full(_) => { // TODO: canonicalize full ast } + Output::Pattern(_) => {} Output::Expr(loc_expr) => { let mut var_store = VarStore::default(); let mut imported: Vec<(QualifiedModuleName, Region)> = vec![]; @@ -248,6 +263,7 @@ impl<'a> Malformed for Output<'a> { Output::ModuleDefs(defs) => defs.is_malformed(), Output::Expr(expr) => expr.is_malformed(), Output::Full(full) => full.is_malformed(), + Output::Pattern(patt) => patt.is_malformed(), } } } @@ -259,6 +275,7 @@ impl<'a> Normalize<'a> for Output<'a> { Output::ModuleDefs(defs) => Output::ModuleDefs(defs.normalize(arena)), Output::Expr(expr) => Output::Expr(expr.normalize(arena)), Output::Full(full) => Output::Full(full.normalize(arena)), + Output::Pattern(patt) => Output::Pattern(patt.normalize(arena)), } } } @@ -270,6 +287,7 @@ impl<'a> Input<'a> { Input::ModuleDefs(s) => s, Input::Expr(s) => s, Input::Full(s) => s, + Input::Pattern(s) => s, } } @@ -308,6 +326,11 @@ impl<'a> Input<'a> { Ok(Output::Full(FullAst { header, defs })) } + + Input::Pattern(input) => { + let patt = parse_pattern_with(arena, input).map_err(|e| e.problem)?; + Ok(Output::Pattern(patt)) + } } } @@ -325,9 +348,11 @@ impl<'a> Input<'a> { let arena = Bump::new(); let actual = self.parse_in(&arena).unwrap_or_else(|err| { - panic!("Unexpected parse failure when parsing this for formatting:\n\n{}\n\nParse error was:\n\n{:?}\n\n", self.as_str(), err); + panic!("Unexpected parse failure when parsing this for formatting:\n\n{}\n\nParse error was:\n\n{:#?}\n\n", self.as_str(), err); }); + println!("Actual {actual:#?}"); + let output = actual.format(); handle_formatted_output(output.as_ref()); diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.result-ast index 81a8cc4659..5485392182 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.result-ast @@ -21,6 +21,7 @@ "E", ), [], + Whitespace, ), ann_type: @2-3 Apply( "", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotated_tag_destructure.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_tag_destructure.expr.result-ast index 7f09e80c22..0b6c28bcd4 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/annotated_tag_destructure.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_tag_destructure.expr.result-ast @@ -26,6 +26,7 @@ ident: "x", }, ], + Whitespace, ), ann_type: @11-25 TagUnion { ext: None, @@ -54,6 +55,7 @@ ident: "x", }, ], + Whitespace, ), body_expr: @37-46 Apply( @37-43 Tag( diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.formatted.roc new file mode 100644 index 0000000000..784e318f43 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.formatted.roc @@ -0,0 +1 @@ +Ok(a) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.result-ast new file mode 100644 index 0000000000..c283ee9fa0 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.result-ast @@ -0,0 +1,16 @@ +@0-4 SpaceAfter( + Apply( + @0-2 Tag( + "Ok", + ), + [ + @3-4 Identifier { + ident: "a", + }, + ], + ParensAndCommas, + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.roc new file mode 100644 index 0000000000..84443618cb --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_pnc.pattern.roc @@ -0,0 +1 @@ +Ok(a) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.formatted.roc new file mode 100644 index 0000000000..d7c96636cd --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.formatted.roc @@ -0,0 +1 @@ +Ok a \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.result-ast new file mode 100644 index 0000000000..51b5c8a36d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.result-ast @@ -0,0 +1,16 @@ +@0-4 SpaceAfter( + Apply( + @0-2 Tag( + "Ok", + ), + [ + @3-4 Identifier { + ident: "a", + }, + ], + Whitespace, + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.roc new file mode 100644 index 0000000000..cd74add159 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_tag_single_arg_whitespace.pattern.roc @@ -0,0 +1 @@ +Ok a diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.result-ast index 5a6f04c7ce..bc14aab1da 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/arg_pattern_as.expr.result-ast @@ -27,6 +27,7 @@ ident: "inner", }, ], + Whitespace, ), PatternAs { spaces_before: [], diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/closure_complex_pattern_indent_issue.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/closure_complex_pattern_indent_issue.expr.result-ast index 4139b12367..361e19f8d5 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/closure_complex_pattern_indent_issue.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/closure_complex_pattern_indent_issue.expr.result-ast @@ -38,6 +38,7 @@ }, ), ], + Whitespace, ), ], @17-18 SpaceBefore( diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/closure_parens_double_newlines.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/closure_parens_double_newlines.expr.formatted.roc index 009b538ae0..f48df276f3 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/closure_parens_double_newlines.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/closure_parens_double_newlines.expr.formatted.roc @@ -1 +1 @@ -\L z -> 42 \ No newline at end of file +\L(z) -> 42 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/closure_parens_double_newlines.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/closure_parens_double_newlines.expr.result-ast index 9f417ee9fc..416d91ac16 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/closure_parens_double_newlines.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/closure_parens_double_newlines.expr.result-ast @@ -20,6 +20,7 @@ ], ), ], + ParensAndCommas, ), ], @11-13 Num( diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.result-ast index cd803b0ba8..394892fd02 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.result-ast @@ -16,6 +16,7 @@ ], ), ], + Whitespace, ), ], @8-10 UnaryOp( diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.result-ast index c30d7db340..b1d566abd4 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.result-ast @@ -19,6 +19,7 @@ ], ), ], + Whitespace, ), ], @10-12 Var { diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.formatted.roc index 51e264b710..7270273d14 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.formatted.roc @@ -1,4 +1,4 @@ -1 0 # +1(0) # # : gi M \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.result-ast index b34d093b10..1fccdafe1b 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.result-ast @@ -16,7 +16,7 @@ type_defs: [], value_defs: [ Annotation( - @0-1 Apply( + @0-10 Apply( @0-1 NumLiteral( "1", ), @@ -35,6 +35,7 @@ ], ), ], + ParensAndCommas, ), @11-13 BoundVariable( "gi", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.formatted.roc index ab25264ec0..5e1f8df384 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.formatted.roc @@ -1,5 +1,5 @@ -1 - (0 # - 0) +1( + 0( # + 0,),) f : f t \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.result-ast index 13c1389302..80789ca81e 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.result-ast @@ -17,37 +17,44 @@ type_defs: [], value_defs: [ Annotation( - @0-1 Apply( - @0-1 NumLiteral( - "1", - ), - [ - @2-11 SpaceAfter( - Apply( - @3-4 NumLiteral( - "0", + @0-12 Apply( + @0-12 Apply( + @0-1 NumLiteral( + "1", + ), + [ + @2-11 SpaceAfter( + Apply( + @3-4 NumLiteral( + "0", + ), + [ + @7-8 SpaceBefore( + NumLiteral( + "0", + ), + [ + LineComment( + "", + ), + ], + ), + ], + ParensAndCommas, ), [ - @7-8 SpaceBefore( - NumLiteral( - "0", - ), - [ - LineComment( - "", - ), - ], - ), + Newline, ], ), - [ - Newline, - ], - ), + ], + ParensAndCommas, + ), + [ @12-13 Identifier { ident: "f", }, ], + Whitespace, ), @14-15 BoundVariable( "f", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.formatted.roc index 9713d5305b..46bc54855f 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.formatted.roc @@ -1,5 +1,5 @@ -1 - (ts 0) +1( + ts(0),) # diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.result-ast index 3cc6ededed..a61c45e7c4 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.result-ast @@ -16,39 +16,46 @@ type_defs: [], value_defs: [ Annotation( - @0-1 Apply( - @0-1 NumLiteral( - "1", - ), - [ - @2-13 SpaceAfter( - Apply( - @2-4 Identifier { - ident: "ts", - }, - [ - @5-9 SpaceAfter( - NumLiteral( - "0", - ), - [ - Newline, - Newline, - LineComment( - "", + @0-15 Apply( + @0-15 Apply( + @0-1 NumLiteral( + "1", + ), + [ + @2-13 SpaceAfter( + Apply( + @2-4 Identifier { + ident: "ts", + }, + [ + @5-9 SpaceAfter( + NumLiteral( + "0", ), - ], - ), + [ + Newline, + Newline, + LineComment( + "", + ), + ], + ), + ], + ParensAndCommas, + ), + [ + Newline, ], ), - [ - Newline, - ], - ), + ], + ParensAndCommas, + ), + [ @15-16 Identifier { ident: "f", }, ], + Whitespace, ), @17-20 BoundVariable( "i7f", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.result-ast index de778e5534..3c551afe5b 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.result-ast @@ -34,6 +34,7 @@ ident: "f", }, ], + Whitespace, ), @14-15 BoundVariable( "f", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/destructure_tag_assignment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/destructure_tag_assignment.expr.result-ast index 6b3363e2d9..e598dc9541 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/destructure_tag_assignment.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/destructure_tag_assignment.expr.result-ast @@ -26,6 +26,7 @@ ident: "str", }, ], + Whitespace, ), @12-36 Apply( @12-17 Tag( diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/double_parens_comment_tuple_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/double_parens_comment_tuple_pat.expr.result-ast index 4601075a32..478e25e8e0 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/double_parens_comment_tuple_pat.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/double_parens_comment_tuple_pat.expr.result-ast @@ -35,6 +35,7 @@ ident: "e", }, ], + Whitespace, ), @8-14 Apply( @9-10 SpaceAfter( @@ -52,6 +53,7 @@ ident: "p", }, ], + Whitespace, ), ], ), diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_parens_comment.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_comment_with_newline.expr.formatted.roc similarity index 100% rename from crates/compiler/test_syntax/tests/snapshots/pass/implements_after_parens_comment.expr.formatted.roc rename to crates/compiler/test_syntax/tests/snapshots/pass/implements_after_comment_with_newline.expr.formatted.roc diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_parens_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_comment_with_newline.expr.result-ast similarity index 64% rename from crates/compiler/test_syntax/tests/snapshots/pass/implements_after_parens_comment.expr.result-ast rename to crates/compiler/test_syntax/tests/snapshots/pass/implements_after_comment_with_newline.expr.result-ast index 897574c761..d625b977e6 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_parens_comment.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_comment_with_newline.expr.result-ast @@ -1,11 +1,11 @@ -@0-22 SpaceAfter( +@0-23 SpaceAfter( Defs( Defs { tags: [ EitherIndex(0), ], regions: [ - @0-20, + @0-21, ], space_before: [ Slice { start: 0, length: 0 }, @@ -19,23 +19,23 @@ header: TypeHeader { name: @0-1 "C", vars: [ - @2-3 SpaceAfter( - NumLiteral( - "4", - ), - [ - LineComment( - "", - ), - ], + @2-3 NumLiteral( + "4", ), ], }, - loc_implements: @6-16 Implements, + loc_implements: @7-17 SpaceBefore( + Implements, + [ + LineComment( + "", + ), + ], + ), members: [ AbilityMember { - name: @17-18 "e", - typ: @19-20 BoundVariable( + name: @18-19 "e", + typ: @20-21 BoundVariable( "m", ), }, @@ -44,7 +44,7 @@ ], value_defs: [], }, - @21-22 SpaceBefore( + @22-23 SpaceBefore( Tag( "C", ), diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_comment_with_newline.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_comment_with_newline.expr.roc new file mode 100644 index 0000000000..2aeced370a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_comment_with_newline.expr.roc @@ -0,0 +1,3 @@ +C 4 # + implements e:m +C diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_parens_comment.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_parens_comment.expr.roc deleted file mode 100644 index 5e25dc2684..0000000000 --- a/crates/compiler/test_syntax/tests/snapshots/pass/implements_after_parens_comment.expr.roc +++ /dev/null @@ -1,3 +0,0 @@ -C(4# -)implements e:m -C diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/implements_in_pat_after_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/implements_in_pat_after_comment.expr.result-ast index 68a0ed5cc6..57eb03f9bd 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/implements_in_pat_after_comment.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/implements_in_pat_after_comment.expr.result-ast @@ -33,6 +33,7 @@ ], ), ], + Whitespace, ), @15-16 BoundVariable( "s", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/mega_parens_pat.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/mega_parens_pat.expr.formatted.roc index 6afb9689c7..a8be8c3bad 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/mega_parens_pat.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/mega_parens_pat.expr.formatted.roc @@ -1,6 +1,6 @@ -1 - (0 # - f) +1( + 0 # + f,) (0 # f) : f e \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/mega_parens_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/mega_parens_pat.expr.result-ast index 72721638b7..15bb415a7f 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/mega_parens_pat.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/mega_parens_pat.expr.result-ast @@ -17,28 +17,34 @@ type_defs: [], value_defs: [ Annotation( - @0-1 Apply( - @0-1 NumLiteral( - "1", - ), - [ - @2-8 Apply( - @3-4 SpaceAfter( - NumLiteral( - "0", + @0-9 Apply( + @0-9 Apply( + @0-1 NumLiteral( + "1", + ), + [ + @2-8 Apply( + @3-4 SpaceAfter( + NumLiteral( + "0", + ), + [ + LineComment( + "", + ), + ], ), [ - LineComment( - "", - ), + @7-8 Identifier { + ident: "f", + }, ], + Whitespace, ), - [ - @7-8 Identifier { - ident: "f", - }, - ], - ), + ], + ParensAndCommas, + ), + [ @10-16 Apply( @11-12 SpaceAfter( NumLiteral( @@ -55,8 +61,10 @@ ident: "f", }, ], + Whitespace, ), ], + Whitespace, ), @18-19 BoundVariable( "f", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.result-ast index 822c6854b6..3a78180692 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.result-ast @@ -32,6 +32,7 @@ ], ), ], + Whitespace, ), [ Newline, diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_after_newlines_in_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_after_newlines_in_pat.expr.result-ast index c6bd478e64..d6eaefefb8 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_after_newlines_in_pat.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_after_newlines_in_pat.expr.result-ast @@ -34,6 +34,7 @@ ), ), ], + Whitespace, ), @12-13 Apply( "", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_and_str_in_alias.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_and_str_in_alias.expr.result-ast index b5d5d3fc03..7d1b87ac4a 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_and_str_in_alias.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_and_str_in_alias.expr.result-ast @@ -42,12 +42,14 @@ ), ), ], + Whitespace, ), [ @12-13 Identifier { ident: "f", }, ], + Whitespace, ), @14-15 Apply( "", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_apply_in_parens_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_apply_in_parens_pat.expr.result-ast index 6f4f0ffc52..954d962cf9 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_apply_in_parens_pat.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_apply_in_parens_pat.expr.result-ast @@ -33,8 +33,10 @@ "0", ), ], + Whitespace, ), ], + Whitespace, ), @15-16 BoundVariable( "f", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_in_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_in_pat.expr.result-ast index e54e729336..a6b75c6b96 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_in_pat.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_str_in_pat.expr.result-ast @@ -36,6 +36,7 @@ "2", ), ], + Whitespace, ), @12-13 Apply( "", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.formatted.roc index 408d473392..c237748fb7 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.formatted.roc @@ -1,7 +1,6 @@ -( - 0 - ( - 1 - d - ) + 0( + 1 + d, + ) ) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.result-ast index 80653fe465..2df2cd752b 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.result-ast @@ -5,44 +5,42 @@ "0", ), [ - @4-7 ParensAround( - Defs( - Defs { - tags: [ - EitherIndex(2147483648), - ], - regions: [ - @4-5, - ], - space_before: [ - Slice { start: 0, length: 0 }, - ], - space_after: [ - Slice { start: 0, length: 0 }, - ], - spaces: [], - type_defs: [], - value_defs: [ - Stmt( - @4-5 Num( - "1", - ), + @4-7 Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @4-5, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @4-5 Num( + "1", ), - ], + ), + ], + }, + @6-7 SpaceBefore( + Var { + module_name: "", + ident: "d", }, - @6-7 SpaceBefore( - Var { - module_name: "", - ident: "d", - }, - [ - Newline, - ], - ), + [ + Newline, + ], ), ), ], - Space, + ParensAndCommas, ), ), @0-1 Negate, diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.result-ast index 77141fe1a8..ef38608602 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.result-ast @@ -32,6 +32,7 @@ ], ), ], + Whitespace, ), ], @14-15 Var { diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nested_parens_in_pattern.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/nested_parens_in_pattern.expr.result-ast index 486101626f..2911fd032d 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/nested_parens_in_pattern.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nested_parens_in_pattern.expr.result-ast @@ -25,6 +25,7 @@ ident: "x", }, ], + Whitespace, ), @7-8 BoundVariable( "i", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nested_when_comment_in_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/nested_when_comment_in_pat.expr.result-ast index c0f317fa44..ebad424e27 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/nested_when_comment_in_pat.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nested_when_comment_in_pat.expr.result-ast @@ -23,6 +23,7 @@ ], ), ], + Whitespace, ), [ Newline, diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opaque_destructure_first_item_in_body.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_destructure_first_item_in_body.expr.result-ast index 1049a5d6ea..1a8dc9412c 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/opaque_destructure_first_item_in_body.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_destructure_first_item_in_body.expr.result-ast @@ -26,6 +26,7 @@ ident: "it", }, ], + Whitespace, ), @12-22 Apply( @12-14 Var { diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opaque_reference_pattern_with_arguments.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_reference_pattern_with_arguments.expr.result-ast index 08211e8d8b..43f3a909f7 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/opaque_reference_pattern_with_arguments.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_reference_pattern_with_arguments.expr.result-ast @@ -20,6 +20,7 @@ ident: "m", }, ], + Whitespace, ), [ Newline, diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_in_type_def_apply.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/parens_in_type_def_apply.expr.result-ast index 46c53e30c9..3b40e80c58 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/parens_in_type_def_apply.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_in_type_def_apply.expr.result-ast @@ -28,6 +28,7 @@ ident: "a", }, ], + Whitespace, ), ], }, diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.formatted.roc index db431fc0a7..86865d4222 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.formatted.roc @@ -1,4 +1,3 @@ -1 - (i, p # - ) : f +1(i, p) # + : f n \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.result-ast index ff787c46cf..8fc0699436 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.result-ast @@ -16,29 +16,26 @@ type_defs: [], value_defs: [ Annotation( - @0-1 Apply( + @0-8 Apply( @0-1 NumLiteral( "1", ), [ - @1-8 Tuple( + @2-3 Identifier { + ident: "i", + }, + @4-5 SpaceAfter( + Identifier { + ident: "p", + }, [ - @2-3 Identifier { - ident: "i", - }, - @4-5 SpaceAfter( - Identifier { - ident: "p", - }, - [ - LineComment( - "", - ), - ], + LineComment( + "", ), ], ), ], + ParensAndCommas, ), @9-10 BoundVariable( "f", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.result-ast index e3859ae77e..a9ffb62aed 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.result-ast @@ -37,6 +37,7 @@ ], ), ], + Whitespace, ), @7-8 BoundVariable( "s", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_with_as_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_with_as_parens.expr.result-ast index 618e7996ef..5cfade595e 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_with_as_parens.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_with_as_parens.expr.result-ast @@ -23,6 +23,7 @@ }, ), ], + Whitespace, ), [ Newline, diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast index 35b3fce174..a756669583 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_with_space_in_parens.expr.result-ast @@ -43,11 +43,13 @@ ident: "ry", }, ], + Whitespace, ), @47-48 Underscore( "", ), ], + Whitespace, ), [ Newline, diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/quotes_in_parens_in_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/quotes_in_parens_in_pat.expr.result-ast index 2ea6d2191c..a928416a6a 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/quotes_in_parens_in_pat.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/quotes_in_parens_in_pat.expr.result-ast @@ -32,6 +32,7 @@ ), ), ], + Whitespace, ), ], }, diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/repr_7342.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/repr_7342.expr.result-ast index a838faad68..64ef72d318 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/repr_7342.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/repr_7342.expr.result-ast @@ -37,6 +37,7 @@ ident: "a", }, ], + Whitespace, ), @10-11 BoundVariable( "t", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/repr_7346.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/repr_7346.expr.result-ast index 6ebfbb59dc..415780d440 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/repr_7346.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/repr_7346.expr.result-ast @@ -45,6 +45,7 @@ "K", ), ], + Whitespace, ), [ LineComment( diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tag_destructure_bang.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/tag_destructure_bang.expr.result-ast index 39fb47dfb2..359d61921c 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/tag_destructure_bang.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tag_destructure_bang.expr.result-ast @@ -29,6 +29,7 @@ ident: "code", }, ], + Whitespace, ), @30-33 Var { module_name: "", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tag_destructure_bang_no_space.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/tag_destructure_bang_no_space.expr.result-ast index 6398fbd487..815ab4b93f 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/tag_destructure_bang_no_space.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tag_destructure_bang_no_space.expr.result-ast @@ -29,6 +29,7 @@ ident: "code", }, ], + Whitespace, ), @29-32 Var { module_name: "", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.formatted.roc index edc201ec4f..9e03396f1d 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.formatted.roc @@ -1,2 +1,2 @@ -1 (0 0) f : f +1(0(0)) f : f i \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.result-ast index 8a5dfca170..79e230df8a 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.result-ast @@ -17,30 +17,37 @@ type_defs: [], value_defs: [ Annotation( - @0-1 Apply( - @0-1 NumLiteral( - "1", + @0-10 Apply( + @0-10 Apply( + @0-1 NumLiteral( + "1", + ), + [ + @2-9 Apply( + @3-4 NumLiteral( + "0", + ), + [ + @5-6 SpaceAfter( + NumLiteral( + "0", + ), + [ + Newline, + ], + ), + ], + ParensAndCommas, + ), + ], + ParensAndCommas, ), [ - @2-9 Apply( - @3-4 NumLiteral( - "0", - ), - [ - @5-6 SpaceAfter( - NumLiteral( - "0", - ), - [ - Newline, - ], - ), - ], - ), @10-11 Identifier { ident: "f", }, ], + Whitespace, ), @12-13 BoundVariable( "f", diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/triple_quote_craziness.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/triple_quote_craziness.expr.result-ast index 62e4310d60..eb4505fae0 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/triple_quote_craziness.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/triple_quote_craziness.expr.result-ast @@ -28,6 +28,7 @@ ), ), ], + Whitespace, ), @8-15 Apply( @8-9 Var { diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/underscore_in_assignment_pattern.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/underscore_in_assignment_pattern.expr.result-ast index db9854c250..fbece1e6fb 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/underscore_in_assignment_pattern.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/underscore_in_assignment_pattern.expr.result-ast @@ -50,6 +50,7 @@ "", ), ], + Whitespace, ), @11-19 Apply( @11-15 Tag( @@ -79,6 +80,7 @@ ident: "y", }, ], + Whitespace, ), @31-39 Apply( @31-35 Tag( @@ -108,6 +110,7 @@ "", ), ], + Whitespace, ), @51-59 Apply( @51-55 Tag( @@ -161,6 +164,7 @@ "", ), ], + Whitespace, ), @90-98 Apply( @90-94 Tag( @@ -174,8 +178,10 @@ ident: "y", }, ], + Whitespace, ), ], + Whitespace, ), @102-128 Apply( @102-106 Tag( diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/when_result_list.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/when_result_list.expr.result-ast index 0e78d039ba..0a946329da 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/when_result_list.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/when_result_list.expr.result-ast @@ -23,6 +23,7 @@ [], ), ], + Whitespace, ), [ Newline, diff --git a/crates/compiler/test_syntax/tests/test_fmt.rs b/crates/compiler/test_syntax/tests/test_fmt.rs index 275fa4a1ea..d2e2d67202 100644 --- a/crates/compiler/test_syntax/tests/test_fmt.rs +++ b/crates/compiler/test_syntax/tests/test_fmt.rs @@ -37,6 +37,14 @@ mod test_fmt { ) } + fn pattern_formats_same(input: &str) { + Input::Pattern(input.trim()).check_invariants( + check_formatting(input.trim()), + true, + Some(false), + ); + } + fn fmt_module_and_defs<'a>( arena: &Bump, src: &str, @@ -3497,6 +3505,33 @@ mod test_fmt { )); } + #[test] + fn zero_arg_application_with_parens() { + expr_formats_same(indoc!( + r" + a() + " + )); + } + + #[test] + fn try_then_application_with_parens() { + expr_formats_same(indoc!( + r" + try something!(arg) + " + )); + } + + #[test] + fn dbg_then_application_with_parens() { + expr_formats_same(indoc!( + r" + dbg something!(arg) + " + )); + } + #[test] fn single_line_application_with_parens() { expr_formats_same(indoc!( @@ -3885,6 +3920,40 @@ mod test_fmt { )); } + #[test] + fn multi_line_when_condition_2_pnc() { + expr_formats_same(indoc!( + r" + when + # this is quite complicated + complexFunction(a, b, c) + # Watch out + is + Complex(x, y) -> + simplify(x, y) + + Simple(z) -> + z + " + )); + } + + #[test] + fn anthony_testing() { + expr_formats_same(indoc!( + r" + when alter (Ok value) is + Ok newValue -> + bucket = listGetUnsafe buckets bucketIndex + newData = List.set data (Num.toU64 bucket.dataIndex) (key, newValue) + @Dict { buckets, data: newData, maxBucketCapacity, maxLoadFactor, shifts } + + Err Missing -> + removeBucket (@Dict { buckets, data, maxBucketCapacity, maxLoadFactor, shifts }) bucketIndex + " + )); + } + #[test] fn multi_line_when_condition_3() { expr_formats_to( @@ -6238,4 +6307,24 @@ mod test_fmt { // " // )); // } + + #[test] + fn pattern_tag_apply_with_whitespace_single_arg() { + pattern_formats_same(indoc!("Ok a")); + } + + #[test] + fn pattern_tag_apply_with_pnc_single_arg() { + pattern_formats_same(indoc!("Ok(a)")); + } + + #[test] + fn pattern_tag_apply_with_whitespace_multi_arg() { + pattern_formats_same(indoc!("Ok a b")); + } + + #[test] + fn pattern_tag_apply_with_pnc_multi_arg() { + pattern_formats_same(indoc!("Ok(a, b)")); + } } diff --git a/crates/compiler/test_syntax/tests/test_snapshots.rs b/crates/compiler/test_syntax/tests/test_snapshots.rs index 76d6745271..4aacb5d402 100644 --- a/crates/compiler/test_syntax/tests/test_snapshots.rs +++ b/crates/compiler/test_syntax/tests/test_snapshots.rs @@ -33,6 +33,9 @@ mod test_snapshots { (full => $input:expr) => { Input::Full($input) }; + (pattern => $input:expr) => { + Input::Pattern($input) + }; } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -324,6 +327,8 @@ mod test_snapshots { pass/apply_record_parens_newline_field.expr, pass/apply_tag.expr, pass/apply_tag_pnc.expr, + pass/apply_tag_single_arg_pnc.pattern, + pass/apply_tag_single_arg_whitespace.pattern, pass/apply_three_args.expr, pass/apply_tuple_ext_parens_ty.expr, pass/apply_two_args.expr, @@ -450,7 +455,7 @@ mod test_snapshots { pass/if_in_record_field_opt_pat.expr, pass/if_newline_then_negate_else_recordupdater.expr, pass/if_then_weird_indent.expr, - pass/implements_after_parens_comment.expr, + pass/implements_after_comment_with_newline.expr, pass/implements_annotation_comment.expr, pass/implements_in_pat_after_comment.expr, pass/implements_newline_in_fn_ty.expr, @@ -859,8 +864,6 @@ mod test_snapshots { Err(err) => Err(format!("{err:?}")), }; - println!("{:?}", result); - if expect == TestExpectation::Pass { let tokens = roc_parse::highlight::highlight(&source); for token in tokens { diff --git a/crates/language_server/src/analysis/tokens.rs b/crates/language_server/src/analysis/tokens.rs index 9e1ef85b2f..f62163cc6c 100644 --- a/crates/language_server/src/analysis/tokens.rs +++ b/crates/language_server/src/analysis/tokens.rs @@ -767,7 +767,7 @@ impl IterTokens for Loc> { Pattern::Identifier { .. } => onetoken(Token::Variable, region, arena), Pattern::Tag(_) => onetoken(Token::Tag, region, arena), Pattern::OpaqueRef(_) => onetoken(Token::Type, region, arena), - Pattern::Apply(p1, p2) => (p1.iter_tokens(arena).into_iter()) + Pattern::Apply(p1, p2, _) => (p1.iter_tokens(arena).into_iter()) .chain(p2.iter_tokens(arena)) .collect_in(arena), Pattern::RecordDestructure(ps) => ps.iter_tokens(arena), diff --git a/crates/reporting/src/error/parse.rs b/crates/reporting/src/error/parse.rs index 7098bca212..638656eb73 100644 --- a/crates/reporting/src/error/parse.rs +++ b/crates/reporting/src/error/parse.rs @@ -2281,7 +2281,9 @@ fn to_pattern_report<'a>( | EPattern::IndentEnd(pos) | EPattern::AsIndentStart(pos) | EPattern::AccessorFunction(pos) - | EPattern::RecordUpdaterFunction(pos) => to_unhandled_parse_error_report( + | EPattern::RecordUpdaterFunction(pos) + | EPattern::ParenStart(pos) + | EPattern::ParenEnd(pos) => to_unhandled_parse_error_report( alloc, lines, filename,