mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-23 14:35:12 +00:00
PNC for Patterns, stabilize formatting
This commit is contained in:
parent
bac165fd99
commit
3b0db07fa1
78 changed files with 789 additions and 332 deletions
|
@ -190,7 +190,7 @@ pub enum FormatProblem {
|
|||
|
||||
pub fn format_src(arena: &Bump, src: &str, flags: MigrationFlags) -> Result<String, FormatProblem> {
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -78,6 +78,7 @@ Defs {
|
|||
ident: "name",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
value: @125-154 Apply(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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))),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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<Pattern<'a>>, &'a [Loc<Pattern<'a>>]),
|
||||
Apply(
|
||||
&'a Loc<Pattern<'a>>,
|
||||
&'a [Loc<Pattern<'a>>],
|
||||
PatternApplyStyle,
|
||||
),
|
||||
|
||||
/// This is Located<Pattern> rather than Located<str> 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(),
|
||||
|
|
|
@ -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,9 +198,22 @@ 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<Expr<'a>>, EExpr<'a>> {
|
||||
one_of!(
|
||||
loc(specialize_err(
|
||||
EExpr::Closure,
|
||||
closure_help(check_for_arrow)
|
||||
)),
|
||||
loc_term(),
|
||||
)
|
||||
.trace("term_or_underscore")
|
||||
}
|
||||
|
||||
fn loc_term<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||
map_with_arena(
|
||||
and(
|
||||
one_of!(
|
||||
loc_expr_in_parens_etc_help(),
|
||||
loc(specialize_err(EExpr::Str, string_like_literal_help())),
|
||||
|
@ -208,74 +221,57 @@ fn loc_term_or_underscore<'a>(
|
|||
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(),
|
||||
),
|
||||
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_or_underscore")
|
||||
.trace("term")
|
||||
}
|
||||
|
||||
fn loc_term<'a>(check_for_arrow: CheckForArrow) -> impl Parser<'a, Loc<Expr<'a>>, 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 apply_with_pnc<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||
fn pnc_args<'a>() -> impl Parser<'a, Loc<&'a [&'a Loc<Expr<'a>>]>, 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(
|
||||
map_with_arena(
|
||||
specialize_err(
|
||||
EExpr::InParens,
|
||||
collection_trailing_sep_e(
|
||||
loc(collection_trailing_sep_e(
|
||||
byte(b'(', EInParens::Open),
|
||||
specialize_err_ref(EInParens::Expr, loc_expr_block(false, true)),
|
||||
specialize_err_ref(EInParens::Expr, loc_expr_block(true)),
|
||||
byte(b',', EInParens::End),
|
||||
byte(b')', EInParens::End),
|
||||
Expr::SpaceBefore,
|
||||
)),
|
||||
),
|
||||
)
|
||||
.parse(arena, new_state, min_indent)?;
|
||||
|
||||
let arg_slice: &[&Loc<Expr<'a>>] = {
|
||||
|arena, arg_loc| {
|
||||
let mut args_vec = Vec::new_in(arena);
|
||||
for arg in args.items.iter() {
|
||||
for arg in arg_loc.value.items.iter() {
|
||||
let a: &Loc<Expr<'a>> = 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,
|
||||
))
|
||||
Loc {
|
||||
value: args_vec.into_bump_slice(),
|
||||
region: arg_loc.region,
|
||||
}
|
||||
},
|
||||
)
|
||||
.parse(arena, state, min_indent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1743,7 +1739,8 @@ fn parse_negated_term<'a>(
|
|||
initial_state: State<'a>,
|
||||
loc_op: Loc<BinOp>,
|
||||
) -> 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<
|
|||
Expr::Underscore(opt_name) => 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<Pattern<
|
|||
arg_patterns.push(Loc { region, value });
|
||||
}
|
||||
|
||||
let pattern = Pattern::Apply(val_pattern, arg_patterns.into_bump_slice());
|
||||
let pattern = Pattern::Apply(
|
||||
val_pattern,
|
||||
arg_patterns.into_bump_slice(),
|
||||
if matches!(called_via, CalledVia::ParensAndCommas) {
|
||||
PatternApplyStyle::ParensAndCommas
|
||||
} else {
|
||||
PatternApplyStyle::Whitespace
|
||||
},
|
||||
);
|
||||
|
||||
pattern
|
||||
}
|
||||
|
@ -3277,7 +3282,7 @@ fn starts_with_spaces_conservative(value: &Pattern<'_>) -> 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<Expr<'a>>,
|
||||
) -> 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);
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Pattern<'a>>, 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<Pattern<'a>>>, 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<Pattern<'a>>>, 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<Pattern<'a>> = 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<Pattern<'a>> = 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,9 +377,18 @@ 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)?;
|
||||
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<Pattern<'_>>] = { args };
|
||||
|
||||
if loc_args.is_empty() {
|
||||
Ok((MadeProgress, loc_tag, state))
|
||||
|
@ -358,14 +397,10 @@ fn loc_ident_pattern_help<'a>(
|
|||
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());
|
||||
let value = Pattern::Apply(&*arena.alloc(loc_tag), loc_args, style);
|
||||
|
||||
Ok((MadeProgress, Loc { region, value }, state))
|
||||
}
|
||||
} else {
|
||||
Ok((MadeProgress, loc_tag, state))
|
||||
}
|
||||
}
|
||||
Ident::OpaqueRef(name) => {
|
||||
let loc_pat = Loc {
|
||||
|
@ -374,9 +409,14 @@ 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)?;
|
||||
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<Pattern<'_>>] = { args };
|
||||
|
||||
if loc_args.is_empty() {
|
||||
Ok((MadeProgress, loc_pat, state))
|
||||
|
@ -385,14 +425,10 @@ fn loc_ident_pattern_help<'a>(
|
|||
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());
|
||||
let value = Pattern::Apply(&*arena.alloc(loc_pat), loc_args, style);
|
||||
|
||||
Ok((MadeProgress, Loc { region, value }, state))
|
||||
}
|
||||
} else {
|
||||
Ok((MadeProgress, loc_pat, state))
|
||||
}
|
||||
}
|
||||
Ident::Access {
|
||||
module_name, parts, ..
|
||||
|
@ -589,3 +625,90 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, 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<Loc<Pattern<'a>>, 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:#?}"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Loc<Pattern<'a>>, 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<Defs<'a>, SyntaxError<'a>> {
|
||||
let state = State::new(input.as_bytes());
|
||||
|
||||
|
|
|
@ -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::<Vec<String>>();
|
||||
if args.len() < 3 || args.len() > 5 {
|
||||
eprintln!("Usage: {} [--minimize-full-error] [--minimize-initial-parse-error] [expr|full|moduledefs|header] <input>", args[0]);
|
||||
eprintln!("Usage: {} [--minimize-full-error] [--minimize-initial-parse-error] [expr|full|moduledefs|header|pattern] <input>", 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 });
|
||||
}
|
||||
|
|
|
@ -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<Expr<'a>>),
|
||||
|
||||
Full(FullAst<'a>),
|
||||
|
||||
Pattern(Loc<Pattern<'a>>),
|
||||
}
|
||||
|
||||
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());
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"E",
|
||||
),
|
||||
[],
|
||||
Whitespace,
|
||||
),
|
||||
ann_type: @2-3 Apply(
|
||||
"",
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Ok(a)
|
|
@ -0,0 +1,16 @@
|
|||
@0-4 SpaceAfter(
|
||||
Apply(
|
||||
@0-2 Tag(
|
||||
"Ok",
|
||||
),
|
||||
[
|
||||
@3-4 Identifier {
|
||||
ident: "a",
|
||||
},
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
Ok(a)
|
|
@ -0,0 +1 @@
|
|||
Ok a
|
|
@ -0,0 +1,16 @@
|
|||
@0-4 SpaceAfter(
|
||||
Apply(
|
||||
@0-2 Tag(
|
||||
"Ok",
|
||||
),
|
||||
[
|
||||
@3-4 Identifier {
|
||||
ident: "a",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
Ok a
|
|
@ -27,6 +27,7 @@
|
|||
ident: "inner",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
PatternAs {
|
||||
spaces_before: [],
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
},
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
@17-18 SpaceBefore(
|
||||
|
|
|
@ -1 +1 @@
|
|||
\L z -> 42
|
||||
\L(z) -> 42
|
|
@ -20,6 +20,7 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
],
|
||||
@11-13 Num(
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
@8-10 UnaryOp(
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
@10-12 Var {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
1 0 #
|
||||
1(0) #
|
||||
#
|
||||
: gi
|
||||
M
|
|
@ -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",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
1
|
||||
(0 #
|
||||
0)
|
||||
1(
|
||||
0( #
|
||||
0,),)
|
||||
f : f
|
||||
t
|
|
@ -17,7 +17,8 @@
|
|||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Apply(
|
||||
@0-12 Apply(
|
||||
@0-12 Apply(
|
||||
@0-1 NumLiteral(
|
||||
"1",
|
||||
),
|
||||
|
@ -39,15 +40,21 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
[
|
||||
@12-13 Identifier {
|
||||
ident: "f",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@14-15 BoundVariable(
|
||||
"f",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
1
|
||||
(ts 0)
|
||||
1(
|
||||
ts(0),)
|
||||
|
||||
#
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Apply(
|
||||
@0-15 Apply(
|
||||
@0-15 Apply(
|
||||
@0-1 NumLiteral(
|
||||
"1",
|
||||
),
|
||||
|
@ -40,15 +41,21 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
[
|
||||
@15-16 Identifier {
|
||||
ident: "f",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@17-20 BoundVariable(
|
||||
"i7f",
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
ident: "f",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@14-15 BoundVariable(
|
||||
"f",
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
ident: "str",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@12-36 Apply(
|
||||
@12-17 Tag(
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
ident: "e",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@8-14 Apply(
|
||||
@9-10 SpaceAfter(
|
||||
|
@ -52,6 +53,7 @@
|
|||
ident: "p",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
@0-22 SpaceAfter(
|
||||
@0-23 SpaceAfter(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-20,
|
||||
@0-21,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
|
@ -19,23 +19,23 @@
|
|||
header: TypeHeader {
|
||||
name: @0-1 "C",
|
||||
vars: [
|
||||
@2-3 SpaceAfter(
|
||||
NumLiteral(
|
||||
@2-3 NumLiteral(
|
||||
"4",
|
||||
),
|
||||
],
|
||||
},
|
||||
loc_implements: @7-17 SpaceBefore(
|
||||
Implements,
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
},
|
||||
loc_implements: @6-16 Implements,
|
||||
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",
|
||||
),
|
|
@ -0,0 +1,3 @@
|
|||
C 4 #
|
||||
implements e:m
|
||||
C
|
|
@ -1,3 +0,0 @@
|
|||
C(4#
|
||||
)implements e:m
|
||||
C
|
|
@ -33,6 +33,7 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@15-16 BoundVariable(
|
||||
"s",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
1
|
||||
(0 #
|
||||
f)
|
||||
1(
|
||||
0 #
|
||||
f,)
|
||||
(0 #
|
||||
f) : f
|
||||
e
|
|
@ -17,7 +17,8 @@
|
|||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Apply(
|
||||
@0-9 Apply(
|
||||
@0-9 Apply(
|
||||
@0-1 NumLiteral(
|
||||
"1",
|
||||
),
|
||||
|
@ -38,7 +39,12 @@
|
|||
ident: "f",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
[
|
||||
@10-16 Apply(
|
||||
@11-12 SpaceAfter(
|
||||
NumLiteral(
|
||||
|
@ -55,8 +61,10 @@
|
|||
ident: "f",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@18-19 BoundVariable(
|
||||
"f",
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
),
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@12-13 Apply(
|
||||
"",
|
||||
|
|
|
@ -42,12 +42,14 @@
|
|||
),
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
[
|
||||
@12-13 Identifier {
|
||||
ident: "f",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@14-15 Apply(
|
||||
"",
|
||||
|
|
|
@ -33,8 +33,10 @@
|
|||
"0",
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@15-16 BoundVariable(
|
||||
"f",
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"2",
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@12-13 Apply(
|
||||
"",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
-(
|
||||
0
|
||||
(
|
||||
0(
|
||||
1
|
||||
d
|
||||
d,
|
||||
)
|
||||
)
|
|
@ -5,8 +5,7 @@
|
|||
"0",
|
||||
),
|
||||
[
|
||||
@4-7 ParensAround(
|
||||
Defs(
|
||||
@4-7 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
|
@ -40,9 +39,8 @@
|
|||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
ParensAndCommas,
|
||||
),
|
||||
),
|
||||
@0-1 Negate,
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
@14-15 Var {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
ident: "x",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@7-8 BoundVariable(
|
||||
"i",
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
ident: "it",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@12-22 Apply(
|
||||
@12-14 Var {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
ident: "m",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
ident: "a",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
},
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
1
|
||||
(i, p #
|
||||
) : f
|
||||
1(i, p) #
|
||||
: f
|
||||
n
|
|
@ -16,12 +16,10 @@
|
|||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Apply(
|
||||
@0-8 Apply(
|
||||
@0-1 NumLiteral(
|
||||
"1",
|
||||
),
|
||||
[
|
||||
@1-8 Tuple(
|
||||
[
|
||||
@2-3 Identifier {
|
||||
ident: "i",
|
||||
|
@ -37,8 +35,7 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
@9-10 BoundVariable(
|
||||
"f",
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@7-8 BoundVariable(
|
||||
"s",
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
},
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
|
|
|
@ -43,11 +43,13 @@
|
|||
ident: "ry",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@47-48 Underscore(
|
||||
"",
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
),
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
],
|
||||
},
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
ident: "a",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@10-11 BoundVariable(
|
||||
"t",
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
"K",
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
ident: "code",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@30-33 Var {
|
||||
module_name: "",
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
ident: "code",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@29-32 Var {
|
||||
module_name: "",
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
1 (0 0) f : f
|
||||
1(0(0)) f : f
|
||||
i
|
|
@ -17,7 +17,8 @@
|
|||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Apply(
|
||||
@0-10 Apply(
|
||||
@0-10 Apply(
|
||||
@0-1 NumLiteral(
|
||||
"1",
|
||||
),
|
||||
|
@ -36,11 +37,17 @@
|
|||
],
|
||||
),
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
],
|
||||
ParensAndCommas,
|
||||
),
|
||||
[
|
||||
@10-11 Identifier {
|
||||
ident: "f",
|
||||
},
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@12-13 BoundVariable(
|
||||
"f",
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
),
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
@8-15 Apply(
|
||||
@8-9 Var {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
[],
|
||||
),
|
||||
],
|
||||
Whitespace,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
|
|
|
@ -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)"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -767,7 +767,7 @@ impl IterTokens for Loc<Pattern<'_>> {
|
|||
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),
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue