mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
Revert "Merge pull request #7267 from joshuawarner32/fuzzing-bugs-2"
This reverts commit364249a29d
, reversing changes made to0e550a7f68
.
This commit is contained in:
parent
a92cf2fdf9
commit
74d137cad4
347 changed files with 1157 additions and 8214 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2559,7 +2559,6 @@ dependencies = [
|
|||
"roc_module",
|
||||
"roc_parse",
|
||||
"roc_region",
|
||||
"soa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -1104,21 +1104,10 @@ pub fn desugar_expr<'a>(
|
|||
// Allow naked dbg, necessary for piping values into dbg with the `Pizza` binop
|
||||
loc_expr
|
||||
}
|
||||
DbgStmt {
|
||||
first: condition,
|
||||
extra_args,
|
||||
continuation,
|
||||
} => {
|
||||
DbgStmt(condition, continuation) => {
|
||||
let desugared_condition = &*env.arena.alloc(desugar_expr(env, scope, condition));
|
||||
let desugared_continuation = &*env.arena.alloc(desugar_expr(env, scope, continuation));
|
||||
|
||||
if let Some(last) = extra_args.last() {
|
||||
let args_region = Region::span_across(&condition.region, &last.region);
|
||||
env.problem(Problem::OverAppliedDbg {
|
||||
region: args_region,
|
||||
});
|
||||
}
|
||||
|
||||
env.arena.alloc(Loc {
|
||||
value: *desugar_dbg_stmt(env, desugared_condition, desugared_continuation),
|
||||
region: loc_expr.region,
|
||||
|
|
|
@ -1245,7 +1245,7 @@ pub fn canonicalize_expr<'a>(
|
|||
|
||||
(loc_expr.value, output)
|
||||
}
|
||||
ast::Expr::DbgStmt { .. } => {
|
||||
ast::Expr::DbgStmt(_, _) => {
|
||||
internal_error!("DbgStmt should have been desugared by now")
|
||||
}
|
||||
ast::Expr::LowLevelDbg((source_location, source), message, continuation) => {
|
||||
|
@ -2546,7 +2546,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
| ast::Expr::Tag(_)
|
||||
| ast::Expr::OpaqueRef(_) => true,
|
||||
// Newlines are disallowed inside interpolation, and these all require newlines
|
||||
ast::Expr::DbgStmt { .. }
|
||||
ast::Expr::DbgStmt(_, _)
|
||||
| ast::Expr::LowLevelDbg(_, _, _)
|
||||
| ast::Expr::Return(_, _)
|
||||
| ast::Expr::When(_, _)
|
||||
|
|
|
@ -15,4 +15,3 @@ roc_region.workspace = true
|
|||
roc_error_macros.workspace = true
|
||||
|
||||
bumpalo.workspace = true
|
||||
soa.workspace = true
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
use crate::{
|
||||
collection::{fmt_collection, Braces},
|
||||
expr::merge_spaces_conservative,
|
||||
spaces::{fmt_comments_only, fmt_spaces, NewlineAt, INDENT},
|
||||
Buf,
|
||||
};
|
||||
use bumpalo::{collections::Vec, Bump};
|
||||
use roc_parse::ast::{
|
||||
AbilityImpls, AssignedField, Collection, CommentOrNewline, Expr, ExtractSpaces, FunctionArrow,
|
||||
ImplementsAbilities, ImplementsAbility, ImplementsClause, Spaceable, Spaces, SpacesAfter,
|
||||
SpacesBefore, Tag, TypeAnnotation, TypeHeader,
|
||||
AbilityImpls, AssignedField, Collection, Expr, ExtractSpaces, FunctionArrow,
|
||||
ImplementsAbilities, ImplementsAbility, ImplementsClause, Tag, TypeAnnotation, TypeHeader,
|
||||
};
|
||||
use roc_parse::ident::UppercaseIdent;
|
||||
use roc_region::all::Loc;
|
||||
|
@ -38,7 +35,6 @@ use roc_region::all::Loc;
|
|||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum Parens {
|
||||
NotNeeded,
|
||||
InCollection,
|
||||
InFunctionType,
|
||||
InApply,
|
||||
InOperator,
|
||||
|
@ -152,10 +148,7 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
true
|
||||
}
|
||||
|
||||
TypeAnnotation::Wildcard
|
||||
| TypeAnnotation::Inferred
|
||||
| BoundVariable(_)
|
||||
| Malformed(_) => false,
|
||||
Wildcard | Inferred | BoundVariable(_) | Malformed(_) => false,
|
||||
Function(args, _arrow, result) => {
|
||||
result.value.is_multiline()
|
||||
|| args.iter().any(|loc_arg| loc_arg.value.is_multiline())
|
||||
|
@ -172,7 +165,8 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
Some(ann) if ann.value.is_multiline() => return true,
|
||||
_ => {}
|
||||
}
|
||||
is_collection_multiline(fields)
|
||||
|
||||
fields.items.iter().any(|field| field.value.is_multiline())
|
||||
}
|
||||
|
||||
Record { fields, ext } => {
|
||||
|
@ -181,7 +175,7 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
is_collection_multiline(fields)
|
||||
fields.items.iter().any(|field| field.value.is_multiline())
|
||||
}
|
||||
|
||||
TagUnion { tags, ext } => {
|
||||
|
@ -190,335 +184,223 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
!tags.final_comments().is_empty() || tags.iter().any(|tag| tag.value.is_multiline())
|
||||
tags.iter().any(|tag| tag.value.is_multiline())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
fmt_ty_ann(self, buf, indent, parens, newlines, false);
|
||||
}
|
||||
}
|
||||
use roc_parse::ast::TypeAnnotation::*;
|
||||
|
||||
fn fmt_ty_ann(
|
||||
me: &TypeAnnotation<'_>,
|
||||
buf: &mut Buf<'_>,
|
||||
indent: u16,
|
||||
parens: Parens,
|
||||
newlines: Newlines,
|
||||
newline_at_top: bool,
|
||||
) {
|
||||
let me = ann_lift_spaces(buf.text.bump(), me);
|
||||
let self_is_multiline = self.is_multiline();
|
||||
|
||||
let self_is_multiline = me.item.is_multiline();
|
||||
match self {
|
||||
Function(args, arrow, ret) => {
|
||||
let needs_parens = parens != Parens::NotNeeded;
|
||||
|
||||
if !me.before.is_empty() {
|
||||
buf.ensure_ends_with_newline();
|
||||
fmt_comments_only(buf, me.before.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
if newline_at_top {
|
||||
buf.ensure_ends_with_newline();
|
||||
}
|
||||
buf.indent(indent);
|
||||
|
||||
match &me.item {
|
||||
TypeAnnotation::SpaceBefore(_ann, _spaces) | TypeAnnotation::SpaceAfter(_ann, _spaces) => {
|
||||
unreachable!()
|
||||
}
|
||||
TypeAnnotation::Function(args, arrow, ret) => {
|
||||
let needs_parens = parens != Parens::NotNeeded;
|
||||
if needs_parens {
|
||||
buf.push('(')
|
||||
}
|
||||
|
||||
buf.indent(indent);
|
||||
let mut it = args.iter().enumerate().peekable();
|
||||
|
||||
if needs_parens {
|
||||
buf.push('(')
|
||||
}
|
||||
while let Some((index, argument)) = it.next() {
|
||||
let is_first = index == 0;
|
||||
let is_multiline = &argument.value.is_multiline();
|
||||
|
||||
for (index, argument) in args.iter().enumerate() {
|
||||
let is_first = index == 0;
|
||||
if !is_first && !is_multiline && self_is_multiline {
|
||||
buf.newline();
|
||||
}
|
||||
|
||||
if !is_first {
|
||||
buf.push_str(",");
|
||||
if !self_is_multiline {
|
||||
buf.spaces(1);
|
||||
argument.value.format_with_options(
|
||||
buf,
|
||||
Parens::InFunctionType,
|
||||
Newlines::Yes,
|
||||
indent,
|
||||
);
|
||||
|
||||
if it.peek().is_some() {
|
||||
buf.push_str(",");
|
||||
if !self_is_multiline {
|
||||
buf.spaces(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let newline_at_top = !is_first && self_is_multiline;
|
||||
|
||||
fmt_ty_ann(
|
||||
&argument.value,
|
||||
buf,
|
||||
indent,
|
||||
Parens::InFunctionType,
|
||||
Newlines::Yes,
|
||||
newline_at_top,
|
||||
);
|
||||
}
|
||||
|
||||
if self_is_multiline {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
match arrow {
|
||||
FunctionArrow::Pure => buf.push_str("->"),
|
||||
FunctionArrow::Effectful => buf.push_str("=>"),
|
||||
}
|
||||
|
||||
buf.spaces(1);
|
||||
|
||||
ret.value
|
||||
.format_with_options(buf, Parens::InFunctionType, Newlines::No, indent);
|
||||
|
||||
if needs_parens {
|
||||
buf.push(')')
|
||||
}
|
||||
}
|
||||
TypeAnnotation::Apply(pkg, name, arguments) => {
|
||||
buf.indent(indent);
|
||||
let write_parens = parens == Parens::InApply && !arguments.is_empty();
|
||||
|
||||
if write_parens {
|
||||
buf.push('(')
|
||||
}
|
||||
|
||||
if !pkg.is_empty() {
|
||||
buf.push_str(pkg);
|
||||
buf.push('.');
|
||||
}
|
||||
|
||||
buf.push_str(name);
|
||||
|
||||
let needs_indent = except_last(arguments).any(|a| a.is_multiline())
|
||||
|| arguments
|
||||
.last()
|
||||
.map(|a| {
|
||||
a.is_multiline()
|
||||
&& (!a.extract_spaces().before.is_empty()
|
||||
|| !ty_is_outdentable(&a.value))
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let arg_indent = if needs_indent {
|
||||
indent + INDENT
|
||||
} else {
|
||||
indent
|
||||
};
|
||||
|
||||
for arg in arguments.iter() {
|
||||
if needs_indent {
|
||||
let arg = arg.extract_spaces();
|
||||
fmt_spaces(buf, arg.before.iter(), arg_indent);
|
||||
buf.ensure_ends_with_newline();
|
||||
arg.item
|
||||
.format_with_options(buf, Parens::InApply, Newlines::Yes, arg_indent);
|
||||
fmt_spaces(buf, arg.after.iter(), arg_indent);
|
||||
if self_is_multiline {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
arg.format_with_options(buf, Parens::InApply, Newlines::No, arg_indent);
|
||||
}
|
||||
|
||||
match arrow {
|
||||
FunctionArrow::Pure => buf.push_str("->"),
|
||||
FunctionArrow::Effectful => buf.push_str("=>"),
|
||||
}
|
||||
|
||||
buf.spaces(1);
|
||||
|
||||
ret.value
|
||||
.format_with_options(buf, Parens::InFunctionType, Newlines::No, indent);
|
||||
|
||||
if needs_parens {
|
||||
buf.push(')')
|
||||
}
|
||||
}
|
||||
|
||||
if write_parens {
|
||||
buf.push(')')
|
||||
}
|
||||
}
|
||||
TypeAnnotation::BoundVariable(v) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(v)
|
||||
}
|
||||
TypeAnnotation::Wildcard => {
|
||||
buf.indent(indent);
|
||||
buf.push('*')
|
||||
}
|
||||
TypeAnnotation::Inferred => {
|
||||
buf.indent(indent);
|
||||
buf.push('_')
|
||||
}
|
||||
|
||||
TypeAnnotation::TagUnion { tags, ext } => {
|
||||
fmt_collection(buf, indent, Braces::Square, *tags, newlines);
|
||||
fmt_ext(ext, buf, indent);
|
||||
}
|
||||
|
||||
TypeAnnotation::Tuple { elems: fields, ext } => {
|
||||
fmt_ty_collection(buf, indent, Braces::Round, *fields, newlines);
|
||||
fmt_ext(ext, buf, indent);
|
||||
}
|
||||
|
||||
TypeAnnotation::Record { fields, ext } => {
|
||||
fmt_collection(buf, indent, Braces::Curly, *fields, newlines);
|
||||
fmt_ext(ext, buf, indent);
|
||||
}
|
||||
|
||||
TypeAnnotation::As(lhs, _spaces, TypeHeader { name, vars }) => {
|
||||
// TODO use _spaces?
|
||||
lhs.value
|
||||
.format_with_options(buf, Parens::InFunctionType, Newlines::No, indent);
|
||||
buf.spaces(1);
|
||||
buf.push_str("as");
|
||||
buf.spaces(1);
|
||||
buf.push_str(name.value);
|
||||
for var in *vars {
|
||||
buf.spaces(1);
|
||||
var.value
|
||||
.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
}
|
||||
}
|
||||
|
||||
TypeAnnotation::Where(annot, implements_clauses) => {
|
||||
annot.format_with_options(buf, parens, newlines, indent);
|
||||
if implements_clauses
|
||||
.iter()
|
||||
.any(|implements| implements.is_multiline())
|
||||
{
|
||||
buf.newline();
|
||||
Apply(pkg, name, arguments) => {
|
||||
buf.indent(indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
for (i, has) in implements_clauses.iter().enumerate() {
|
||||
buf.push_str(if i == 0 {
|
||||
roc_parse::keyword::WHERE
|
||||
let write_parens = parens == Parens::InApply && !arguments.is_empty();
|
||||
|
||||
if write_parens {
|
||||
buf.push('(')
|
||||
}
|
||||
|
||||
if !pkg.is_empty() {
|
||||
buf.push_str(pkg);
|
||||
buf.push('.');
|
||||
}
|
||||
|
||||
buf.push_str(name);
|
||||
|
||||
let needs_indent = except_last(arguments).any(|a| a.is_multiline())
|
||||
|| arguments
|
||||
.last()
|
||||
.map(|a| {
|
||||
a.is_multiline()
|
||||
&& (!a.extract_spaces().before.is_empty()
|
||||
|| !is_outdentable(&a.value))
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let arg_indent = if needs_indent {
|
||||
indent + INDENT
|
||||
} else {
|
||||
","
|
||||
});
|
||||
indent
|
||||
};
|
||||
|
||||
for arg in arguments.iter() {
|
||||
if needs_indent {
|
||||
let arg = arg.extract_spaces();
|
||||
fmt_spaces(buf, arg.before.iter(), arg_indent);
|
||||
buf.ensure_ends_with_newline();
|
||||
arg.item.format_with_options(
|
||||
buf,
|
||||
Parens::InApply,
|
||||
Newlines::Yes,
|
||||
arg_indent,
|
||||
);
|
||||
fmt_spaces(buf, arg.after.iter(), arg_indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
arg.format_with_options(buf, Parens::InApply, Newlines::No, arg_indent);
|
||||
}
|
||||
}
|
||||
|
||||
if write_parens {
|
||||
buf.push(')')
|
||||
}
|
||||
}
|
||||
BoundVariable(v) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(v)
|
||||
}
|
||||
Wildcard => {
|
||||
buf.indent(indent);
|
||||
buf.push('*')
|
||||
}
|
||||
Inferred => {
|
||||
buf.indent(indent);
|
||||
buf.push('_')
|
||||
}
|
||||
|
||||
TagUnion { tags, ext } => {
|
||||
fmt_collection(buf, indent, Braces::Square, *tags, newlines);
|
||||
|
||||
if let Some(loc_ext_ann) = *ext {
|
||||
loc_ext_ann.value.format(buf, indent);
|
||||
}
|
||||
}
|
||||
|
||||
Tuple { elems: fields, ext } => {
|
||||
fmt_collection(buf, indent, Braces::Round, *fields, newlines);
|
||||
|
||||
if let Some(loc_ext_ann) = *ext {
|
||||
loc_ext_ann.value.format(buf, indent);
|
||||
}
|
||||
}
|
||||
|
||||
Record { fields, ext } => {
|
||||
fmt_collection(buf, indent, Braces::Curly, *fields, newlines);
|
||||
|
||||
if let Some(loc_ext_ann) = *ext {
|
||||
loc_ext_ann.value.format(buf, indent);
|
||||
}
|
||||
}
|
||||
|
||||
As(lhs, _spaces, TypeHeader { name, vars }) => {
|
||||
// TODO use _spaces?
|
||||
lhs.value
|
||||
.format_with_options(buf, Parens::InFunctionType, Newlines::No, indent);
|
||||
buf.spaces(1);
|
||||
has.format_with_options(buf, parens, newlines, indent);
|
||||
buf.push_str("as");
|
||||
buf.spaces(1);
|
||||
buf.push_str(name.value);
|
||||
for var in *vars {
|
||||
buf.spaces(1);
|
||||
var.value
|
||||
.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
}
|
||||
}
|
||||
|
||||
Where(annot, implements_clauses) => {
|
||||
annot.format_with_options(buf, parens, newlines, indent);
|
||||
if implements_clauses
|
||||
.iter()
|
||||
.any(|implements| implements.is_multiline())
|
||||
{
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
for (i, has) in implements_clauses.iter().enumerate() {
|
||||
buf.push_str(if i == 0 {
|
||||
roc_parse::keyword::WHERE
|
||||
} else {
|
||||
","
|
||||
});
|
||||
buf.spaces(1);
|
||||
has.format_with_options(buf, parens, newlines, indent);
|
||||
}
|
||||
}
|
||||
|
||||
SpaceBefore(ann, spaces) => {
|
||||
buf.ensure_ends_with_newline();
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
ann.format_with_options(buf, parens, newlines, indent)
|
||||
}
|
||||
SpaceAfter(ann, spaces) => {
|
||||
ann.format_with_options(buf, parens, newlines, indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
Malformed(raw) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(raw)
|
||||
}
|
||||
}
|
||||
TypeAnnotation::Malformed(raw) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(raw)
|
||||
}
|
||||
}
|
||||
if !me.after.is_empty() {
|
||||
fmt_comments_only(buf, me.after.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
}
|
||||
|
||||
fn lower<'a, 'b: 'a>(
|
||||
arena: &'b Bump,
|
||||
lifted: Spaces<'b, TypeAnnotation<'b>>,
|
||||
) -> TypeAnnotation<'b> {
|
||||
if lifted.before.is_empty() && lifted.after.is_empty() {
|
||||
return lifted.item;
|
||||
}
|
||||
if lifted.before.is_empty() {
|
||||
return TypeAnnotation::SpaceAfter(arena.alloc(lifted.item), lifted.after);
|
||||
}
|
||||
if lifted.after.is_empty() {
|
||||
return TypeAnnotation::SpaceBefore(arena.alloc(lifted.item), lifted.before);
|
||||
}
|
||||
TypeAnnotation::SpaceBefore(
|
||||
arena.alloc(TypeAnnotation::SpaceAfter(
|
||||
arena.alloc(lifted.item),
|
||||
lifted.after,
|
||||
)),
|
||||
lifted.before,
|
||||
fn is_outdentable(ann: &TypeAnnotation) -> bool {
|
||||
matches!(
|
||||
ann.extract_spaces().item,
|
||||
TypeAnnotation::Tuple { .. } | TypeAnnotation::Record { .. }
|
||||
)
|
||||
}
|
||||
|
||||
fn fmt_ty_collection(
|
||||
buf: &mut Buf<'_>,
|
||||
indent: u16,
|
||||
braces: Braces,
|
||||
items: Collection<'_, Loc<TypeAnnotation<'_>>>,
|
||||
newlines: Newlines,
|
||||
) {
|
||||
let arena = buf.text.bump();
|
||||
let mut new_items: Vec<'_, NodeSpaces<'_, Node<'_>>> =
|
||||
Vec::with_capacity_in(items.len(), arena);
|
||||
|
||||
let mut last_after: &[CommentOrNewline<'_>] = &[];
|
||||
|
||||
for (i, item) in items.items.iter().enumerate() {
|
||||
let func_ty_risky = i > 0;
|
||||
let lifted = ann_lift_to_node(
|
||||
if func_ty_risky {
|
||||
Parens::InCollection
|
||||
} else {
|
||||
Parens::NotNeeded
|
||||
},
|
||||
arena,
|
||||
&item.value,
|
||||
);
|
||||
let before = merge_spaces_conservative(arena, last_after, lifted.before);
|
||||
last_after = lifted.after;
|
||||
new_items.push(NodeSpaces {
|
||||
before,
|
||||
item: lifted.item,
|
||||
after: &[],
|
||||
});
|
||||
}
|
||||
|
||||
let final_comments = merge_spaces_conservative(arena, last_after, items.final_comments());
|
||||
|
||||
let new_items =
|
||||
Collection::with_items_and_comments(arena, new_items.into_bump_slice(), final_comments);
|
||||
|
||||
fmt_collection(buf, indent, braces, new_items, newlines)
|
||||
}
|
||||
|
||||
fn fmt_ext(ext: &Option<&Loc<TypeAnnotation<'_>>>, buf: &mut Buf<'_>, indent: u16) {
|
||||
if let Some(loc_ext_ann) = *ext {
|
||||
let me = ann_lift_spaces(buf.text.bump(), &loc_ext_ann.value);
|
||||
let parens_needed = !me.before.is_empty() || ext_needs_parens(me.item);
|
||||
if parens_needed {
|
||||
// We need to make sure to not have whitespace before the ext of a type,
|
||||
// since that would make it parse as something else.
|
||||
buf.push('(');
|
||||
loc_ext_ann.value.format(buf, indent + INDENT);
|
||||
buf.indent(indent);
|
||||
buf.push(')');
|
||||
} else {
|
||||
loc_ext_ann.value.format(buf, indent + INDENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ext_needs_parens(item: TypeAnnotation<'_>) -> bool {
|
||||
match item {
|
||||
TypeAnnotation::Record { .. }
|
||||
| TypeAnnotation::TagUnion { .. }
|
||||
| TypeAnnotation::Tuple { .. }
|
||||
| TypeAnnotation::BoundVariable(..)
|
||||
| TypeAnnotation::Wildcard
|
||||
| TypeAnnotation::Inferred => false,
|
||||
TypeAnnotation::Apply(_module, _func, args) => !args.is_empty(),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ty_is_outdentable(mut rhs: &TypeAnnotation) -> bool {
|
||||
loop {
|
||||
match rhs {
|
||||
TypeAnnotation::SpaceBefore(sub_def, spaces) => {
|
||||
let is_only_newlines = spaces.iter().all(|s| s.is_newline());
|
||||
if !is_only_newlines || !sub_def.is_multiline() {
|
||||
return false;
|
||||
}
|
||||
rhs = sub_def;
|
||||
}
|
||||
TypeAnnotation::SpaceAfter(sub_def, _) => {
|
||||
rhs = sub_def;
|
||||
}
|
||||
TypeAnnotation::Where(ann, _clauses) => {
|
||||
if !ann.is_multiline() {
|
||||
return false;
|
||||
}
|
||||
rhs = &ann.value;
|
||||
}
|
||||
TypeAnnotation::Record { .. }
|
||||
| TypeAnnotation::TagUnion { .. }
|
||||
| TypeAnnotation::Tuple { .. } => return rhs.is_multiline(),
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fields are subtly different on the type and term level:
|
||||
///
|
||||
/// > type: { x : Int, y : Bool }
|
||||
|
@ -584,7 +466,6 @@ fn format_assigned_field_help<T>(
|
|||
}
|
||||
|
||||
buf.spaces(separator_spaces);
|
||||
buf.indent(indent);
|
||||
buf.push(':');
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
|
@ -602,7 +483,6 @@ fn format_assigned_field_help<T>(
|
|||
}
|
||||
|
||||
buf.spaces(separator_spaces);
|
||||
buf.indent(indent);
|
||||
buf.push('?');
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
|
@ -824,279 +704,3 @@ pub fn except_last<T>(items: &[T]) -> impl Iterator<Item = &T> {
|
|||
items[..items.len() - 1].iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ann_lift_spaces<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
ann: &TypeAnnotation<'b>,
|
||||
) -> Spaces<'a, TypeAnnotation<'a>> {
|
||||
match ann {
|
||||
TypeAnnotation::Apply(module, func, args) => {
|
||||
if args.is_empty() {
|
||||
return Spaces {
|
||||
item: *ann,
|
||||
before: &[],
|
||||
after: &[],
|
||||
};
|
||||
}
|
||||
let mut new_args = Vec::with_capacity_in(args.len(), arena);
|
||||
|
||||
if !args.is_empty() {
|
||||
for arg in args.iter().take(args.len() - 1) {
|
||||
let lifted = ann_lift_spaces(arena, &arg.value);
|
||||
new_args.push(Loc::at(arg.region, lower(arena, lifted)));
|
||||
}
|
||||
}
|
||||
|
||||
let after = if let Some(last) = args.last() {
|
||||
let lifted = ann_lift_spaces(arena, &last.value);
|
||||
if lifted.before.is_empty() {
|
||||
new_args.push(Loc::at(last.region, lifted.item));
|
||||
} else {
|
||||
new_args.push(Loc::at(
|
||||
last.region,
|
||||
TypeAnnotation::SpaceBefore(arena.alloc(lifted.item), lifted.before),
|
||||
));
|
||||
}
|
||||
lifted.after
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: TypeAnnotation::Apply(module, func, new_args.into_bump_slice()),
|
||||
after,
|
||||
}
|
||||
}
|
||||
TypeAnnotation::SpaceBefore(expr, spaces) => {
|
||||
let mut inner = ann_lift_spaces(arena, expr);
|
||||
inner.before = merge_spaces_conservative(arena, spaces, inner.before);
|
||||
inner
|
||||
}
|
||||
TypeAnnotation::SpaceAfter(expr, spaces) => {
|
||||
let mut inner = ann_lift_spaces(arena, expr);
|
||||
inner.after = merge_spaces_conservative(arena, inner.after, spaces);
|
||||
inner
|
||||
}
|
||||
_ => Spaces {
|
||||
before: &[],
|
||||
item: *ann,
|
||||
after: &[],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ann_lift_spaces_before<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
ann: &TypeAnnotation<'b>,
|
||||
) -> SpacesBefore<'a, TypeAnnotation<'a>> {
|
||||
let lifted = ann_lift_spaces(arena, ann);
|
||||
SpacesBefore {
|
||||
before: lifted.before,
|
||||
item: lifted.item.maybe_after(arena, lifted.after),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ann_lift_spaces_after<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
ann: &TypeAnnotation<'b>,
|
||||
) -> SpacesAfter<'a, TypeAnnotation<'a>> {
|
||||
let lifted = ann_lift_spaces(arena, ann);
|
||||
SpacesAfter {
|
||||
item: lifted.item.maybe_before(arena, lifted.before),
|
||||
after: lifted.after,
|
||||
}
|
||||
}
|
||||
|
||||
type Sp<'a> = &'a [CommentOrNewline<'a>];
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum Node<'a> {
|
||||
DelimitedSequence(Braces, &'a [(Sp<'a>, Node<'a>)], Sp<'a>),
|
||||
TypeAnnotation(TypeAnnotation<'a>),
|
||||
}
|
||||
|
||||
impl<'a> Formattable for Node<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
match self {
|
||||
Node::DelimitedSequence(_braces, lefts, right) => {
|
||||
if !right.is_empty() {
|
||||
return true;
|
||||
}
|
||||
for (sp, l) in *lefts {
|
||||
if l.is_multiline() || !sp.is_empty() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
Node::TypeAnnotation(type_annotation) => type_annotation.is_multiline(),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
match self {
|
||||
Node::DelimitedSequence(braces, lefts, right) => {
|
||||
buf.indent(indent);
|
||||
buf.push(braces.start());
|
||||
|
||||
for (sp, l) in *lefts {
|
||||
if !sp.is_empty() {
|
||||
fmt_spaces(buf, sp.iter(), indent);
|
||||
}
|
||||
|
||||
l.format_with_options(buf, parens, newlines, indent);
|
||||
}
|
||||
|
||||
if !right.is_empty() {
|
||||
fmt_spaces(buf, right.iter(), indent);
|
||||
}
|
||||
|
||||
buf.indent(indent);
|
||||
buf.push(braces.end());
|
||||
}
|
||||
Node::TypeAnnotation(type_annotation) => {
|
||||
type_annotation.format_with_options(buf, parens, newlines, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ann_lift_to_node<'a, 'b: 'a>(
|
||||
parens: Parens,
|
||||
arena: &'a Bump,
|
||||
ann: &TypeAnnotation<'b>,
|
||||
) -> Spaces<'a, Node<'a>> {
|
||||
match ann {
|
||||
TypeAnnotation::Apply(module, func, args) => {
|
||||
if args.is_empty() {
|
||||
return Spaces {
|
||||
item: Node::TypeAnnotation(*ann),
|
||||
before: &[],
|
||||
after: &[],
|
||||
};
|
||||
}
|
||||
let mut new_args = Vec::with_capacity_in(args.len(), arena);
|
||||
|
||||
if !args.is_empty() {
|
||||
for arg in args.iter().take(args.len() - 1) {
|
||||
let lifted = ann_lift_spaces(arena, &arg.value);
|
||||
new_args.push(Loc::at(arg.region, lower(arena, lifted)));
|
||||
}
|
||||
}
|
||||
|
||||
let after = if let Some(last) = args.last() {
|
||||
let lifted = ann_lift_spaces(arena, &last.value);
|
||||
if lifted.before.is_empty() {
|
||||
new_args.push(Loc::at(last.region, lifted.item));
|
||||
} else {
|
||||
new_args.push(Loc::at(
|
||||
last.region,
|
||||
TypeAnnotation::SpaceBefore(arena.alloc(lifted.item), lifted.before),
|
||||
));
|
||||
}
|
||||
lifted.after
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: Node::TypeAnnotation(TypeAnnotation::Apply(
|
||||
module,
|
||||
func,
|
||||
new_args.into_bump_slice(),
|
||||
)),
|
||||
after,
|
||||
}
|
||||
}
|
||||
TypeAnnotation::SpaceBefore(expr, spaces) => {
|
||||
let mut inner = ann_lift_to_node(parens, arena, expr);
|
||||
inner.before = merge_spaces_conservative(arena, spaces, inner.before);
|
||||
inner
|
||||
}
|
||||
TypeAnnotation::SpaceAfter(expr, spaces) => {
|
||||
let mut inner = ann_lift_to_node(parens, arena, expr);
|
||||
inner.after = merge_spaces_conservative(arena, inner.after, spaces);
|
||||
inner
|
||||
}
|
||||
TypeAnnotation::Function(args, _purity, res) => {
|
||||
let new_args = arena.alloc_slice_copy(args);
|
||||
let before = if let Some(first) = new_args.first_mut() {
|
||||
let lifted = ann_lift_spaces_before(arena, &first.value);
|
||||
first.value = lifted.item;
|
||||
lifted.before
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
let new_res = ann_lift_spaces_after(arena, &res.value);
|
||||
let new_ann = TypeAnnotation::Function(
|
||||
new_args,
|
||||
FunctionArrow::Pure,
|
||||
arena.alloc(Loc::at_zero(new_res.item)),
|
||||
);
|
||||
let inner = Spaces {
|
||||
before,
|
||||
item: Node::TypeAnnotation(new_ann),
|
||||
after: new_res.after,
|
||||
};
|
||||
if parens == Parens::InCollection {
|
||||
let node = Node::DelimitedSequence(
|
||||
Braces::Round,
|
||||
arena.alloc_slice_copy(&[(inner.before, inner.item)]),
|
||||
inner.after,
|
||||
);
|
||||
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: node,
|
||||
after: &[],
|
||||
}
|
||||
} else {
|
||||
inner
|
||||
}
|
||||
}
|
||||
_ => Spaces {
|
||||
before: &[],
|
||||
item: Node::TypeAnnotation(*ann),
|
||||
after: &[],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct NodeSpaces<'a, T> {
|
||||
pub before: &'a [CommentOrNewline<'a>],
|
||||
pub item: T,
|
||||
pub after: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
impl<'a, T: Copy> ExtractSpaces<'a> for NodeSpaces<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn extract_spaces(&self) -> Spaces<'a, T> {
|
||||
Spaces {
|
||||
before: self.before,
|
||||
item: self.item,
|
||||
after: self.after,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: Formattable> Formattable for NodeSpaces<'a, V> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
!self.before.is_empty() || !self.after.is_empty() || self.item.is_multiline()
|
||||
}
|
||||
|
||||
fn format_with_options(
|
||||
&self,
|
||||
buf: &mut Buf,
|
||||
parens: crate::annotation::Parens,
|
||||
newlines: Newlines,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_spaces(buf, self.before.iter(), indent);
|
||||
self.item.format_with_options(buf, parens, newlines, indent);
|
||||
fmt_spaces(buf, self.after.iter(), indent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
use roc_parse::{
|
||||
ast::{Collection, CommentOrNewline, ExtractSpaces},
|
||||
expr::merge_spaces,
|
||||
};
|
||||
use roc_parse::ast::{Collection, CommentOrNewline, ExtractSpaces};
|
||||
|
||||
use crate::{
|
||||
annotation::{is_collection_multiline, Formattable, Newlines},
|
||||
spaces::{fmt_comments_only, NewlineAt, INDENT},
|
||||
Buf,
|
||||
};
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum Braces {
|
||||
Round,
|
||||
|
@ -15,35 +13,26 @@ pub enum Braces {
|
|||
Curly,
|
||||
}
|
||||
|
||||
impl Braces {
|
||||
pub fn start(self) -> char {
|
||||
match self {
|
||||
Braces::Round => '(',
|
||||
Braces::Curly => '{',
|
||||
Braces::Square => '[',
|
||||
}
|
||||
}
|
||||
|
||||
pub fn end(self) -> char {
|
||||
match self {
|
||||
Braces::Round => ')',
|
||||
Braces::Curly => '}',
|
||||
Braces::Square => ']',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable + std::fmt::Debug>(
|
||||
pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>(
|
||||
buf: &mut Buf<'buf>,
|
||||
indent: u16,
|
||||
braces: Braces,
|
||||
items: Collection<'a, T>,
|
||||
newline: Newlines,
|
||||
) where
|
||||
<T as ExtractSpaces<'a>>::Item: Formattable + std::fmt::Debug,
|
||||
<T as ExtractSpaces<'a>>::Item: Formattable,
|
||||
{
|
||||
let start = braces.start();
|
||||
let end = braces.end();
|
||||
let start = match braces {
|
||||
Braces::Round => '(',
|
||||
Braces::Curly => '{',
|
||||
Braces::Square => '[',
|
||||
};
|
||||
|
||||
let end = match braces {
|
||||
Braces::Round => ')',
|
||||
Braces::Curly => '}',
|
||||
Braces::Square => ']',
|
||||
};
|
||||
|
||||
if is_collection_multiline(&items) {
|
||||
let braces_indent = indent;
|
||||
|
@ -54,21 +43,10 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable + std::fmt::D
|
|||
buf.indent(braces_indent);
|
||||
buf.push(start);
|
||||
|
||||
let mut last_after: &[CommentOrNewline<'_>] = &[];
|
||||
|
||||
for (index, item) in items.iter().enumerate() {
|
||||
let is_first_item = index == 0;
|
||||
let item = item.extract_spaces();
|
||||
let is_only_newlines = item.before.iter().all(|s| s.is_newline());
|
||||
let last_after_was_only_newlines = last_after.iter().all(|s| s.is_newline());
|
||||
|
||||
if !last_after.is_empty() {
|
||||
if last_after.iter().any(|s| s.is_newline()) {
|
||||
buf.newline();
|
||||
}
|
||||
|
||||
fmt_comments_only(buf, last_after.iter(), NewlineAt::None, item_indent);
|
||||
}
|
||||
|
||||
if item.before.is_empty() || is_only_newlines {
|
||||
buf.ensure_ends_with_newline();
|
||||
|
@ -86,14 +64,13 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable + std::fmt::D
|
|||
if item
|
||||
.before
|
||||
.starts_with(&[CommentOrNewline::Newline, CommentOrNewline::Newline])
|
||||
&& last_after_was_only_newlines
|
||||
{
|
||||
// If there's a comment, and it's not on the first item,
|
||||
// and it's preceded by at least one blank line, maintain 1 blank line.
|
||||
// (We already ensured that it ends in a newline, so this will turn that
|
||||
// into a blank line.)
|
||||
|
||||
buf.ensure_ends_with_blank_line();
|
||||
buf.newline();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,30 +91,32 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable + std::fmt::D
|
|||
buf.indent(item_indent);
|
||||
buf.push(',');
|
||||
|
||||
last_after = item.after;
|
||||
if !item.after.is_empty() {
|
||||
if item.after.iter().any(|s| s.is_newline()) {
|
||||
buf.newline();
|
||||
}
|
||||
|
||||
fmt_comments_only(buf, item.after.iter(), NewlineAt::None, item_indent);
|
||||
}
|
||||
}
|
||||
|
||||
let final_comments = if !last_after.is_empty() {
|
||||
if last_after.iter().any(|s| s.is_newline()) {
|
||||
buf.newline();
|
||||
}
|
||||
if items.final_comments().iter().any(|s| s.is_newline()) {
|
||||
buf.newline();
|
||||
}
|
||||
|
||||
merge_spaces(buf.text.bump(), last_after, items.final_comments())
|
||||
} else {
|
||||
if items.final_comments().iter().any(|s| s.is_newline()) {
|
||||
buf.newline();
|
||||
}
|
||||
|
||||
items.final_comments()
|
||||
};
|
||||
|
||||
if has_comments(final_comments)
|
||||
&& final_comments.starts_with(&[CommentOrNewline::Newline, CommentOrNewline::Newline])
|
||||
if items
|
||||
.final_comments()
|
||||
.starts_with(&[CommentOrNewline::Newline, CommentOrNewline::Newline])
|
||||
{
|
||||
buf.ensure_ends_with_blank_line();
|
||||
buf.newline();
|
||||
}
|
||||
|
||||
fmt_comments_only(buf, final_comments.iter(), NewlineAt::None, item_indent);
|
||||
fmt_comments_only(
|
||||
buf,
|
||||
items.final_comments().iter(),
|
||||
NewlineAt::None,
|
||||
item_indent,
|
||||
);
|
||||
|
||||
buf.ensure_ends_with_newline();
|
||||
buf.indent(braces_indent);
|
||||
|
@ -165,13 +144,3 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable + std::fmt::D
|
|||
|
||||
buf.push(end);
|
||||
}
|
||||
|
||||
fn has_comments(spaces: &[CommentOrNewline<'_>]) -> bool {
|
||||
for space in spaces {
|
||||
match space {
|
||||
CommentOrNewline::Newline => {}
|
||||
CommentOrNewline::LineComment(_) | CommentOrNewline::DocComment(_) => return true,
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
@ -1,27 +1,15 @@
|
|||
use crate::annotation::{
|
||||
ann_lift_spaces, ann_lift_spaces_after, is_collection_multiline, ty_is_outdentable,
|
||||
Formattable, Newlines, Parens,
|
||||
};
|
||||
use crate::annotation::{is_collection_multiline, Formattable, Newlines, Parens};
|
||||
use crate::collection::{fmt_collection, Braces};
|
||||
use crate::expr::{
|
||||
expr_lift_and_lower, expr_lift_spaces, expr_lift_spaces_after, expr_lift_spaces_before,
|
||||
fmt_str_literal, is_str_multiline, sub_expr_requests_parens,
|
||||
};
|
||||
use crate::pattern::{fmt_pattern, pattern_lift_spaces};
|
||||
use crate::pattern::{pattern_lift_spaces_before, starts_with_inline_comment};
|
||||
use crate::spaces::{
|
||||
fmt_comments_only, fmt_default_newline, fmt_default_spaces, fmt_spaces, NewlineAt, INDENT,
|
||||
};
|
||||
use crate::expr::fmt_str_literal;
|
||||
use crate::pattern::fmt_pattern;
|
||||
use crate::spaces::{fmt_default_newline, fmt_default_spaces, fmt_spaces, INDENT};
|
||||
use crate::Buf;
|
||||
use bumpalo::Bump;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_parse::ast::{
|
||||
AbilityMember, CommentOrNewline, Defs, Expr, ExtractSpaces, ImportAlias, ImportAsKeyword,
|
||||
ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation, IngestedFileImport,
|
||||
ModuleImport, ModuleImportParams, Pattern, Spaceable, Spaces, SpacesAfter, SpacesBefore,
|
||||
StrLiteral, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||
AbilityMember, Defs, Expr, ExtractSpaces, ImportAlias, ImportAsKeyword, ImportExposingKeyword,
|
||||
ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport,
|
||||
ModuleImportParams, Pattern, Spaces, StrLiteral, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
|
||||
};
|
||||
use roc_parse::expr::merge_spaces;
|
||||
use roc_parse::header::Keyword;
|
||||
use roc_region::all::Loc;
|
||||
|
||||
|
@ -40,24 +28,18 @@ impl<'a> Formattable for Defs<'a> {
|
|||
indent: u16,
|
||||
) {
|
||||
let mut prev_spaces = true;
|
||||
let arena = buf.text.bump();
|
||||
|
||||
for (index, def) in self.defs().enumerate() {
|
||||
let spaces_before = &self.spaces[self.space_before[index].indices()];
|
||||
let spaces_after = &self.spaces[self.space_after[index].indices()];
|
||||
|
||||
let def = def_lift_spaces(buf.text.bump(), def);
|
||||
|
||||
let spaces_before = merge_spaces(arena, spaces_before, def.before);
|
||||
let spaces_after = merge_spaces(arena, def.after, spaces_after);
|
||||
|
||||
if prev_spaces {
|
||||
fmt_spaces(buf, spaces_before.iter(), indent);
|
||||
} else {
|
||||
fmt_default_newline(buf, spaces_before, indent);
|
||||
}
|
||||
|
||||
match def.item {
|
||||
match def {
|
||||
Ok(type_def) => type_def.format(buf, indent),
|
||||
Err(value_def) => value_def.format(buf, indent),
|
||||
}
|
||||
|
@ -69,339 +51,6 @@ impl<'a> Formattable for Defs<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn def_lift_spaces<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
def: Result<&'a TypeDef<'b>, &'a ValueDef<'b>>,
|
||||
) -> Spaces<'a, Result<TypeDef<'a>, ValueDef<'a>>> {
|
||||
match def {
|
||||
Ok(td) => {
|
||||
let td = tydef_lift_spaces(arena, *td);
|
||||
Spaces {
|
||||
before: td.before,
|
||||
item: Ok(td.item),
|
||||
after: td.after,
|
||||
}
|
||||
}
|
||||
Err(vd) => {
|
||||
let vd = valdef_lift_spaces(arena, *vd);
|
||||
Spaces {
|
||||
before: vd.before,
|
||||
item: Err(vd.item),
|
||||
after: vd.after,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lift_spaces_after<'a, 'b: 'a, T: 'b + ExtractSpaces<'a> + Spaceable<'a>>(
|
||||
arena: &'a Bump,
|
||||
item: T,
|
||||
) -> SpacesAfter<'a, <T as ExtractSpaces<'a>>::Item>
|
||||
where
|
||||
<T as ExtractSpaces<'a>>::Item: Spaceable<'a>,
|
||||
{
|
||||
let spaces = item.extract_spaces();
|
||||
|
||||
SpacesAfter {
|
||||
item: spaces.item.maybe_before(arena, spaces.before),
|
||||
after: spaces.after,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tydef_lift_spaces<'a, 'b: 'a>(arena: &'a Bump, def: TypeDef<'b>) -> Spaces<'a, TypeDef<'a>> {
|
||||
match def {
|
||||
TypeDef::Alias { header, ann } => {
|
||||
let ann_lifted = ann_lift_spaces_after(arena, &ann.value);
|
||||
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: TypeDef::Alias {
|
||||
header,
|
||||
ann: Loc::at(ann.region, ann_lifted.item),
|
||||
},
|
||||
after: ann_lifted.after,
|
||||
}
|
||||
}
|
||||
TypeDef::Opaque {
|
||||
header,
|
||||
typ,
|
||||
derived,
|
||||
} => {
|
||||
if let Some(derived) = derived {
|
||||
let derived_lifted = lift_spaces_after(arena, derived.value);
|
||||
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: TypeDef::Opaque {
|
||||
header,
|
||||
typ,
|
||||
derived: Some(Loc::at(derived.region, derived_lifted.item)),
|
||||
},
|
||||
after: derived_lifted.after,
|
||||
}
|
||||
} else {
|
||||
let typ_lifted = ann_lift_spaces_after(arena, &typ.value);
|
||||
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: TypeDef::Opaque {
|
||||
header,
|
||||
typ: Loc::at(typ.region, typ_lifted.item),
|
||||
derived,
|
||||
},
|
||||
after: typ_lifted.after,
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeDef::Ability {
|
||||
header: _,
|
||||
loc_implements: _,
|
||||
members: _,
|
||||
} => {
|
||||
// TODO: if the fuzzer ever generates examples where it's important to lift spaces from the members,
|
||||
// we'll need to implement this. I'm not sure that's possible, though.
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: def,
|
||||
after: &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn valdef_lift_spaces<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
def: ValueDef<'b>,
|
||||
) -> Spaces<'a, ValueDef<'a>> {
|
||||
match def {
|
||||
ValueDef::Annotation(pat, ann) => {
|
||||
let pat_lifted = pattern_lift_spaces_before(arena, &pat.value);
|
||||
let ann_lifted = ann_lift_spaces_after(arena, &ann.value);
|
||||
|
||||
Spaces {
|
||||
before: pat_lifted.before,
|
||||
item: ValueDef::Annotation(
|
||||
Loc::at(pat.region, pat_lifted.item),
|
||||
Loc::at(ann.region, ann_lifted.item),
|
||||
),
|
||||
after: ann_lifted.after,
|
||||
}
|
||||
}
|
||||
ValueDef::Body(pat, expr) => {
|
||||
let pat_lifted = pattern_lift_spaces_before(arena, &pat.value);
|
||||
let expr_lifted = expr_lift_spaces_after(Parens::NotNeeded, arena, &expr.value);
|
||||
|
||||
Spaces {
|
||||
before: pat_lifted.before,
|
||||
item: ValueDef::Body(
|
||||
arena.alloc(Loc::at(pat.region, pat_lifted.item)),
|
||||
arena.alloc(Loc::at(expr.region, expr_lifted.item)),
|
||||
),
|
||||
after: expr_lifted.after,
|
||||
}
|
||||
}
|
||||
ValueDef::AnnotatedBody {
|
||||
ann_pattern,
|
||||
ann_type,
|
||||
lines_between,
|
||||
body_pattern,
|
||||
body_expr,
|
||||
} => {
|
||||
let ann_pattern_lifted = pattern_lift_spaces_before(arena, &ann_pattern.value);
|
||||
let ann_type_lifted = ann_lift_spaces_after(arena, &ann_type.value);
|
||||
let body_pattern_lifted = pattern_lift_spaces_before(arena, &body_pattern.value);
|
||||
let body_expr_lifted =
|
||||
expr_lift_spaces_after(Parens::NotNeeded, arena, &body_expr.value);
|
||||
|
||||
let lines_between = merge_spaces(
|
||||
arena,
|
||||
ann_type_lifted.after,
|
||||
merge_spaces(arena, lines_between, body_pattern_lifted.before),
|
||||
);
|
||||
|
||||
Spaces {
|
||||
before: ann_pattern_lifted.before,
|
||||
item: ValueDef::AnnotatedBody {
|
||||
ann_pattern: arena.alloc(Loc::at(ann_pattern.region, ann_pattern_lifted.item)),
|
||||
ann_type: arena.alloc(Loc::at(ann_type.region, ann_type_lifted.item)),
|
||||
lines_between,
|
||||
body_pattern: arena
|
||||
.alloc(Loc::at(body_pattern.region, body_pattern_lifted.item)),
|
||||
body_expr: arena.alloc(Loc::at(body_expr.region, body_expr_lifted.item)),
|
||||
},
|
||||
after: body_expr_lifted.after,
|
||||
}
|
||||
}
|
||||
ValueDef::Dbg {
|
||||
condition,
|
||||
preceding_comment,
|
||||
} => {
|
||||
let condition_lifted =
|
||||
expr_lift_spaces_after(Parens::NotNeeded, arena, &condition.value);
|
||||
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: ValueDef::Dbg {
|
||||
condition: arena.alloc(Loc::at(condition.region, condition_lifted.item)),
|
||||
preceding_comment,
|
||||
},
|
||||
after: condition_lifted.after,
|
||||
}
|
||||
}
|
||||
ValueDef::Expect {
|
||||
condition,
|
||||
preceding_comment,
|
||||
} => {
|
||||
let condition_lifted =
|
||||
expr_lift_spaces_after(Parens::NotNeeded, arena, &condition.value);
|
||||
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: ValueDef::Expect {
|
||||
condition: arena.alloc(Loc::at(condition.region, condition_lifted.item)),
|
||||
preceding_comment,
|
||||
},
|
||||
after: condition_lifted.after,
|
||||
}
|
||||
}
|
||||
ValueDef::ModuleImport(module_import) => {
|
||||
// Module imports begin with 'import', and end with either a ImportAlias or Collection
|
||||
// No spaces in sight!
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: ValueDef::ModuleImport(module_import),
|
||||
after: &[],
|
||||
}
|
||||
}
|
||||
ValueDef::IngestedFileImport(mut ingested_file_import) => {
|
||||
// Ingested file imports begin with 'import', but can end with a TypeAnnotation, which can have spaces
|
||||
let after = if let Some(ann) = &mut ingested_file_import.annotation {
|
||||
let lifted = ann_lift_spaces_after(arena, &ann.annotation.value);
|
||||
ann.annotation.value = lifted.item;
|
||||
lifted.after
|
||||
} else {
|
||||
&[]
|
||||
};
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: ValueDef::IngestedFileImport(ingested_file_import),
|
||||
after,
|
||||
}
|
||||
}
|
||||
ValueDef::Stmt(expr) => {
|
||||
let expr_lifted = expr_lift_spaces(Parens::NotNeeded, arena, &expr.value);
|
||||
Spaces {
|
||||
before: expr_lifted.before,
|
||||
item: ValueDef::Stmt(arena.alloc(Loc::at(expr.region, expr_lifted.item))),
|
||||
after: expr_lifted.after,
|
||||
}
|
||||
}
|
||||
ValueDef::StmtAfterExpr => Spaces {
|
||||
before: &[],
|
||||
item: ValueDef::StmtAfterExpr,
|
||||
after: &[],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn valdef_lift_spaces_before<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
def: ValueDef<'b>,
|
||||
) -> SpacesBefore<'a, ValueDef<'a>> {
|
||||
match def {
|
||||
ValueDef::Annotation(pat, ann) => {
|
||||
let pat_lifted = pattern_lift_spaces_before(arena, &pat.value);
|
||||
|
||||
SpacesBefore {
|
||||
before: pat_lifted.before,
|
||||
item: ValueDef::Annotation(Loc::at(pat.region, pat_lifted.item), ann),
|
||||
}
|
||||
}
|
||||
ValueDef::Body(pat, expr) => {
|
||||
let pat_lifted = pattern_lift_spaces_before(arena, &pat.value);
|
||||
|
||||
SpacesBefore {
|
||||
before: pat_lifted.before,
|
||||
item: ValueDef::Body(arena.alloc(Loc::at(pat.region, pat_lifted.item)), expr),
|
||||
}
|
||||
}
|
||||
ValueDef::AnnotatedBody {
|
||||
ann_pattern,
|
||||
ann_type,
|
||||
lines_between,
|
||||
body_pattern,
|
||||
body_expr,
|
||||
} => {
|
||||
let ann_pattern_lifted = pattern_lift_spaces_before(arena, &ann_pattern.value);
|
||||
let ann_type_lifted = ann_lift_spaces_after(arena, &ann_type.value);
|
||||
let body_pattern_lifted = pattern_lift_spaces_before(arena, &body_pattern.value);
|
||||
|
||||
let lines_between = merge_spaces(
|
||||
arena,
|
||||
ann_type_lifted.after,
|
||||
merge_spaces(arena, lines_between, body_pattern_lifted.before),
|
||||
);
|
||||
|
||||
SpacesBefore {
|
||||
before: ann_pattern_lifted.before,
|
||||
item: ValueDef::AnnotatedBody {
|
||||
ann_pattern: arena.alloc(Loc::at(ann_pattern.region, ann_pattern_lifted.item)),
|
||||
ann_type: arena.alloc(Loc::at(ann_type.region, ann_type_lifted.item)),
|
||||
lines_between,
|
||||
body_pattern: arena
|
||||
.alloc(Loc::at(body_pattern.region, body_pattern_lifted.item)),
|
||||
body_expr,
|
||||
},
|
||||
}
|
||||
}
|
||||
ValueDef::Dbg {
|
||||
condition,
|
||||
preceding_comment,
|
||||
} => SpacesBefore {
|
||||
before: &[],
|
||||
item: ValueDef::Dbg {
|
||||
condition,
|
||||
preceding_comment,
|
||||
},
|
||||
},
|
||||
ValueDef::Expect {
|
||||
condition,
|
||||
preceding_comment,
|
||||
} => SpacesBefore {
|
||||
before: &[],
|
||||
item: ValueDef::Expect {
|
||||
condition,
|
||||
preceding_comment,
|
||||
},
|
||||
},
|
||||
ValueDef::ModuleImport(module_import) => {
|
||||
// Module imports always start with 'import', no spaces
|
||||
SpacesBefore {
|
||||
before: &[],
|
||||
item: ValueDef::ModuleImport(module_import),
|
||||
}
|
||||
}
|
||||
ValueDef::IngestedFileImport(ingested_file_import) => {
|
||||
// Similarly, ingested file imports always start with 'import', no spaces
|
||||
SpacesBefore {
|
||||
before: &[],
|
||||
item: ValueDef::IngestedFileImport(ingested_file_import),
|
||||
}
|
||||
}
|
||||
ValueDef::Stmt(expr) => {
|
||||
let expr_lifted = expr_lift_spaces_before(Parens::NotNeeded, arena, &expr.value);
|
||||
SpacesBefore {
|
||||
before: expr_lifted.before,
|
||||
item: ValueDef::Stmt(arena.alloc(Loc::at(expr.region, expr_lifted.item))),
|
||||
}
|
||||
}
|
||||
ValueDef::StmtAfterExpr => SpacesBefore {
|
||||
before: &[],
|
||||
item: ValueDef::StmtAfterExpr,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for TypeDef<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
use roc_parse::ast::TypeDef::*;
|
||||
|
@ -417,23 +66,34 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
use roc_parse::ast::TypeDef::*;
|
||||
|
||||
match self {
|
||||
Alias { header, ann } => {
|
||||
header.format(buf, indent);
|
||||
|
||||
Alias {
|
||||
header: TypeHeader { name, vars },
|
||||
ann,
|
||||
} => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name.value);
|
||||
|
||||
for var in *vars {
|
||||
buf.spaces(1);
|
||||
|
||||
let need_parens = matches!(var.value, Pattern::Apply(..));
|
||||
|
||||
if need_parens {
|
||||
buf.push_str("(");
|
||||
}
|
||||
|
||||
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
||||
buf.indent(indent);
|
||||
|
||||
if need_parens {
|
||||
buf.push_str(")");
|
||||
}
|
||||
}
|
||||
|
||||
buf.push_str(" :");
|
||||
buf.spaces(1);
|
||||
|
||||
let ann = ann_lift_spaces(buf.text.bump(), &ann.value);
|
||||
|
||||
let inner_indent = if ty_is_outdentable(&ann.item) {
|
||||
indent
|
||||
} else {
|
||||
indent + INDENT
|
||||
};
|
||||
fmt_comments_only(buf, ann.before.iter(), NewlineAt::Bottom, inner_indent);
|
||||
ann.item.format(buf, inner_indent);
|
||||
fmt_spaces(buf, ann.after.iter(), indent);
|
||||
ann.format(buf, indent)
|
||||
}
|
||||
Opaque {
|
||||
header,
|
||||
|
@ -467,11 +127,17 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
}
|
||||
}
|
||||
Ability {
|
||||
header,
|
||||
header: TypeHeader { name, vars },
|
||||
loc_implements: _,
|
||||
members,
|
||||
} => {
|
||||
header.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
buf.indent(indent);
|
||||
buf.push_str(name.value);
|
||||
for var in *vars {
|
||||
buf.spaces(1);
|
||||
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
||||
buf.indent(indent);
|
||||
}
|
||||
buf.spaces(1);
|
||||
buf.push_str(roc_parse::keyword::IMPLEMENTS);
|
||||
|
||||
|
@ -514,62 +180,10 @@ impl<'a> Formattable for TypeHeader<'a> {
|
|||
buf.indent(indent);
|
||||
buf.push_str(self.name.value);
|
||||
|
||||
let vars_indent = if self.vars.iter().any(|v| v.is_multiline()) {
|
||||
indent + INDENT
|
||||
} else {
|
||||
indent
|
||||
};
|
||||
|
||||
let mut last_after: &[CommentOrNewline<'_>] = &[];
|
||||
let mut last_multiline = false;
|
||||
|
||||
for var in self.vars.iter() {
|
||||
let var = pattern_lift_spaces(buf.text.bump(), &var.value);
|
||||
|
||||
let before = if !last_after.is_empty() {
|
||||
merge_spaces(buf.text.bump(), last_after, var.before)
|
||||
} else {
|
||||
var.before
|
||||
};
|
||||
|
||||
if !before.is_empty() {
|
||||
if !var.item.is_multiline() {
|
||||
fmt_comments_only(buf, before.iter(), NewlineAt::Bottom, vars_indent)
|
||||
} else {
|
||||
fmt_spaces(buf, before.iter(), vars_indent);
|
||||
}
|
||||
}
|
||||
|
||||
buf.ensure_ends_with_whitespace();
|
||||
|
||||
last_after = var.after;
|
||||
last_multiline = var.item.is_multiline();
|
||||
|
||||
let need_parens = matches!(var.item, Pattern::Apply(..));
|
||||
|
||||
if need_parens {
|
||||
buf.push_str("(");
|
||||
}
|
||||
|
||||
fmt_pattern(buf, &var.item, vars_indent, Parens::NotNeeded);
|
||||
|
||||
buf.indent(vars_indent);
|
||||
|
||||
if need_parens {
|
||||
buf.push_str(")");
|
||||
}
|
||||
}
|
||||
|
||||
if !last_after.is_empty() {
|
||||
if starts_with_inline_comment(last_after.iter()) {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
if !last_multiline {
|
||||
fmt_comments_only(buf, last_after.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
fmt_spaces(buf, last_after.iter(), indent);
|
||||
}
|
||||
buf.spaces(1);
|
||||
fmt_pattern(buf, &var.value, indent, Parens::NotNeeded);
|
||||
buf.indent(indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -827,7 +441,7 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
);
|
||||
}
|
||||
Body(loc_pattern, loc_expr) => {
|
||||
fmt_body(buf, true, &loc_pattern.value, &loc_expr.value, indent);
|
||||
fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent);
|
||||
}
|
||||
Dbg { condition, .. } => fmt_dbg_in_def(buf, condition, self.is_multiline(), indent),
|
||||
Expect { condition, .. } => fmt_expect(buf, condition, self.is_multiline(), indent),
|
||||
|
@ -843,7 +457,7 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
fmt_annotated_body_comment(buf, indent, lines_between);
|
||||
|
||||
buf.newline();
|
||||
fmt_body(buf, false, &body_pattern.value, &body_expr.value, indent);
|
||||
fmt_body(buf, &body_pattern.value, &body_expr.value, indent);
|
||||
}
|
||||
ModuleImport(module_import) => module_import.format(buf, indent),
|
||||
IngestedFileImport(ingested_file_import) => ingested_file_import.format(buf, indent),
|
||||
|
@ -869,25 +483,20 @@ fn fmt_general_def<L: Formattable>(
|
|||
buf.push_str(sep);
|
||||
buf.spaces(1);
|
||||
|
||||
let rhs_lifted = ann_lift_spaces(buf.text.bump(), rhs);
|
||||
let should_outdent = should_outdent(rhs);
|
||||
|
||||
if ty_is_outdentable(&rhs_lifted.item) && rhs_lifted.before.iter().all(|s| s.is_newline()) {
|
||||
rhs_lifted
|
||||
.item
|
||||
.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
if should_outdent {
|
||||
match rhs {
|
||||
TypeAnnotation::SpaceBefore(sub_def, _) => {
|
||||
sub_def.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
}
|
||||
_ => {
|
||||
rhs.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buf.ensure_ends_with_newline();
|
||||
fmt_comments_only(
|
||||
buf,
|
||||
rhs_lifted.before.iter(),
|
||||
NewlineAt::Bottom,
|
||||
indent + INDENT,
|
||||
);
|
||||
rhs_lifted
|
||||
.item
|
||||
.format_with_options(buf, Parens::NotNeeded, newlines, indent + INDENT);
|
||||
rhs.format_with_options(buf, Parens::NotNeeded, newlines, indent + INDENT);
|
||||
}
|
||||
fmt_comments_only(buf, rhs_lifted.after.iter(), NewlineAt::Bottom, indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
buf.push_str(sep);
|
||||
|
@ -896,6 +505,28 @@ fn fmt_general_def<L: Formattable>(
|
|||
}
|
||||
}
|
||||
|
||||
fn should_outdent(mut rhs: &TypeAnnotation) -> bool {
|
||||
loop {
|
||||
match rhs {
|
||||
TypeAnnotation::SpaceBefore(sub_def, spaces) => {
|
||||
let is_only_newlines = spaces.iter().all(|s| s.is_newline());
|
||||
if !is_only_newlines || !sub_def.is_multiline() {
|
||||
return false;
|
||||
}
|
||||
rhs = sub_def;
|
||||
}
|
||||
TypeAnnotation::Where(ann, _clauses) => {
|
||||
if !ann.is_multiline() {
|
||||
return false;
|
||||
}
|
||||
rhs = &ann.value;
|
||||
}
|
||||
TypeAnnotation::Record { .. } | TypeAnnotation::TagUnion { .. } => return true,
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_dbg_in_def<'a>(buf: &mut Buf, condition: &'a Loc<Expr<'a>>, _: bool, indent: u16) {
|
||||
buf.ensure_ends_with_newline();
|
||||
buf.indent(indent);
|
||||
|
@ -977,36 +608,21 @@ pub fn fmt_annotated_body_comment<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fmt_body<'a>(
|
||||
buf: &mut Buf,
|
||||
allow_simplify_empty_record_destructure: bool,
|
||||
pattern: &'a Pattern<'a>,
|
||||
body: &'a Expr<'a>,
|
||||
indent: u16,
|
||||
) {
|
||||
let pattern_extracted = pattern.extract_spaces();
|
||||
pub fn fmt_body<'a>(buf: &mut Buf, pattern: &'a Pattern<'a>, body: &'a Expr<'a>, indent: u16) {
|
||||
// Check if this is an assignment into the unit value
|
||||
let is_unit_assignment = if let Pattern::RecordDestructure(collection) = pattern_extracted.item
|
||||
{
|
||||
allow_simplify_empty_record_destructure
|
||||
&& collection.is_empty()
|
||||
&& pattern_extracted.before.iter().all(|s| s.is_newline())
|
||||
&& pattern_extracted.after.iter().all(|s| s.is_newline())
|
||||
let is_unit_assignment = if let Pattern::RecordDestructure(collection) = pattern {
|
||||
collection.is_empty()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Don't format the `{} =` for defs with this pattern
|
||||
if is_unit_assignment {
|
||||
return body.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
if !is_unit_assignment {
|
||||
pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent);
|
||||
buf.indent(indent);
|
||||
buf.push_str(" =");
|
||||
}
|
||||
|
||||
pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent);
|
||||
buf.indent(indent);
|
||||
buf.push_str(" =");
|
||||
|
||||
let body = expr_lift_and_lower(Parens::NotNeeded, buf.text.bump(), body);
|
||||
|
||||
if body.is_multiline() {
|
||||
match body {
|
||||
Expr::SpaceBefore(sub_def, spaces) => {
|
||||
|
@ -1018,10 +634,7 @@ pub fn fmt_body<'a>(
|
|||
_ => false,
|
||||
};
|
||||
|
||||
if is_unit_assignment {
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
sub_def.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
} else if should_outdent {
|
||||
if should_outdent {
|
||||
buf.spaces(1);
|
||||
sub_def.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
} else {
|
||||
|
@ -1033,32 +646,6 @@ pub fn fmt_body<'a>(
|
|||
);
|
||||
}
|
||||
}
|
||||
Expr::Apply(
|
||||
Loc {
|
||||
value: Expr::Str(StrLiteral::Block(..)),
|
||||
..
|
||||
},
|
||||
..,
|
||||
) => {
|
||||
buf.spaces(1);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
}
|
||||
Expr::Str(s) => {
|
||||
if is_str_multiline(&s) {
|
||||
buf.ensure_ends_with_newline();
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
}
|
||||
_ if starts_with_block_string_literal(&body) => {
|
||||
buf.ensure_ends_with_newline();
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
}
|
||||
Expr::When(..) => {
|
||||
buf.ensure_ends_with_newline();
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
}
|
||||
Expr::Defs(..) | Expr::BinOps(_, _) | Expr::Backpassing(..) => {
|
||||
// Binop chains always get a newline. Otherwise you can have things like:
|
||||
//
|
||||
|
@ -1075,15 +662,9 @@ pub fn fmt_body<'a>(
|
|||
buf.newline();
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
}
|
||||
Expr::ParensAround(&Expr::SpaceBefore(sub_def, _)) => {
|
||||
let needs_indent = !sub_expr_requests_parens(sub_def);
|
||||
let indent = if needs_indent {
|
||||
indent + INDENT
|
||||
} else {
|
||||
indent
|
||||
};
|
||||
buf.spaces(1);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
Expr::When(..) | Expr::Str(StrLiteral::Block(_)) => {
|
||||
buf.ensure_ends_with_newline();
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
}
|
||||
_ => {
|
||||
buf.spaces(1);
|
||||
|
@ -1096,18 +677,6 @@ pub fn fmt_body<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn starts_with_block_string_literal(expr: &Expr<'_>) -> bool {
|
||||
match expr {
|
||||
Expr::Str(s) => is_str_multiline(s),
|
||||
Expr::SpaceAfter(inner, _) | Expr::SpaceBefore(inner, _) => {
|
||||
starts_with_block_string_literal(inner)
|
||||
}
|
||||
Expr::Apply(inner, _, _) => starts_with_block_string_literal(&inner.value),
|
||||
Expr::TrySuffix { target: _, expr } => starts_with_block_string_literal(expr),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Formattable for AbilityMember<'a> {
|
||||
fn is_multiline(&self) -> bool {
|
||||
self.name.value.is_multiline() || self.typ.is_multiline()
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,14 +18,12 @@ pub struct Buf<'a> {
|
|||
spaces_to_flush: usize,
|
||||
newlines_to_flush: usize,
|
||||
beginning_of_line: bool,
|
||||
line_indent: u16,
|
||||
}
|
||||
|
||||
impl<'a> Buf<'a> {
|
||||
pub fn new_in(arena: &'a Bump) -> Buf<'a> {
|
||||
Buf {
|
||||
text: String::new_in(arena),
|
||||
line_indent: 0,
|
||||
spaces_to_flush: 0,
|
||||
newlines_to_flush: 0,
|
||||
beginning_of_line: true,
|
||||
|
@ -42,18 +40,11 @@ impl<'a> Buf<'a> {
|
|||
|
||||
pub fn indent(&mut self, indent: u16) {
|
||||
if self.beginning_of_line {
|
||||
self.line_indent = indent;
|
||||
self.spaces_to_flush = indent as usize;
|
||||
}
|
||||
self.beginning_of_line = false;
|
||||
}
|
||||
|
||||
pub fn cur_line_indent(&self) -> u16 {
|
||||
debug_assert!(!self.beginning_of_line, "cur_line_indent before indent");
|
||||
self.line_indent
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn push(&mut self, ch: char) {
|
||||
debug_assert!(!self.beginning_of_line);
|
||||
debug_assert!(
|
||||
|
@ -70,7 +61,6 @@ impl<'a> Buf<'a> {
|
|||
self.text.push(ch);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn push_str_allow_spaces(&mut self, s: &str) {
|
||||
debug_assert!(
|
||||
!self.beginning_of_line,
|
||||
|
@ -83,7 +73,6 @@ impl<'a> Buf<'a> {
|
|||
self.text.push_str(s);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn push_str(&mut self, s: &str) {
|
||||
debug_assert!(
|
||||
!self.beginning_of_line,
|
||||
|
@ -140,12 +129,6 @@ impl<'a> Buf<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ensure_ends_with_whitespace(&mut self) {
|
||||
if !self.text.is_empty() && self.newlines_to_flush == 0 && self.spaces_to_flush == 0 {
|
||||
self.spaces_to_flush = 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn flush_spaces(&mut self) {
|
||||
for _ in 0..self.newlines_to_flush {
|
||||
self.text.push('\n');
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
use crate::annotation::{Formattable, Newlines, Parens};
|
||||
use crate::expr::{
|
||||
expr_is_multiline, expr_lift_spaces_after, fmt_str_literal, format_sq_literal, is_str_multiline,
|
||||
};
|
||||
use crate::expr::{fmt_str_literal, format_sq_literal, is_str_multiline};
|
||||
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,
|
||||
};
|
||||
use roc_parse::expr::merge_spaces;
|
||||
use roc_region::all::Loc;
|
||||
use roc_parse::ast::{Base, CommentOrNewline, Pattern, PatternAs};
|
||||
|
||||
pub fn fmt_pattern<'a>(buf: &mut Buf, pattern: &'a Pattern<'a>, indent: u16, parens: Parens) {
|
||||
pattern.format_with_options(buf, parens, Newlines::No, indent);
|
||||
|
@ -61,7 +54,7 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
Pattern::RecordDestructure(fields) => fields.iter().any(|f| f.is_multiline()),
|
||||
Pattern::RequiredField(_, subpattern) => subpattern.is_multiline(),
|
||||
|
||||
Pattern::OptionalField(_, expr) => expr_is_multiline(&expr.value, true),
|
||||
Pattern::OptionalField(_, expr) => expr.is_multiline(),
|
||||
|
||||
Pattern::As(pattern, pattern_as) => pattern.is_multiline() || pattern_as.is_multiline(),
|
||||
Pattern::ListRest(opt_pattern_as) => match opt_pattern_as {
|
||||
|
@ -93,307 +86,222 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, _newlines: Newlines, indent: u16) {
|
||||
fmt_pattern_inner(self, buf, parens, indent, self.is_multiline());
|
||||
}
|
||||
}
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
use self::Pattern::*;
|
||||
|
||||
fn fmt_pattern_inner(
|
||||
pat: &Pattern<'_>,
|
||||
buf: &mut Buf,
|
||||
parens: Parens,
|
||||
indent: u16,
|
||||
outer_is_multiline: bool,
|
||||
) {
|
||||
use self::Pattern::*;
|
||||
|
||||
let me = pattern_lift_spaces(buf.text.bump(), pat);
|
||||
|
||||
if !me.before.is_empty() {
|
||||
if !outer_is_multiline {
|
||||
fmt_comments_only(buf, me.before.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
fmt_spaces(buf, me.before.iter(), indent);
|
||||
}
|
||||
}
|
||||
|
||||
let is_multiline = me.item.is_multiline();
|
||||
|
||||
match me.item {
|
||||
Identifier { ident: string } => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
Tag(name) | OpaqueRef(name) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name);
|
||||
}
|
||||
Apply(loc_pattern, loc_arg_patterns) => {
|
||||
buf.indent(indent);
|
||||
// Sometimes, an Apply pattern needs parens around it.
|
||||
// In particular when an Apply's argument is itself an Apply (> 0) arguments
|
||||
let parens = !loc_arg_patterns.is_empty() && (parens == Parens::InApply);
|
||||
|
||||
let indent_more = if is_multiline {
|
||||
indent + INDENT
|
||||
} else {
|
||||
indent
|
||||
};
|
||||
|
||||
if parens {
|
||||
buf.push('(');
|
||||
match self {
|
||||
Identifier { ident: string } => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
Tag(name) | OpaqueRef(name) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name);
|
||||
}
|
||||
Apply(loc_pattern, loc_arg_patterns) => {
|
||||
buf.indent(indent);
|
||||
// Sometimes, an Apply pattern needs parens around it.
|
||||
// In particular when an Apply's argument is itself an Apply (> 0) arguments
|
||||
let parens = !loc_arg_patterns.is_empty() && (parens == Parens::InApply);
|
||||
|
||||
let pat = pattern_lift_spaces(buf.text.bump(), &loc_pattern.value);
|
||||
|
||||
if !pat.before.is_empty() {
|
||||
if !is_multiline {
|
||||
fmt_comments_only(buf, pat.before.iter(), NewlineAt::Bottom, indent)
|
||||
let indent_more = if self.is_multiline() {
|
||||
indent + INDENT
|
||||
} else {
|
||||
fmt_spaces(buf, pat.before.iter(), indent);
|
||||
indent
|
||||
};
|
||||
|
||||
if parens {
|
||||
buf.push('(');
|
||||
}
|
||||
|
||||
loc_pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent);
|
||||
|
||||
for loc_arg in loc_arg_patterns.iter() {
|
||||
buf.spaces(1);
|
||||
loc_arg.format_with_options(buf, Parens::InApply, Newlines::No, indent_more);
|
||||
}
|
||||
|
||||
if parens {
|
||||
buf.push(')');
|
||||
}
|
||||
}
|
||||
RecordDestructure(loc_patterns) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("{");
|
||||
|
||||
fmt_pattern_inner(&pat.item, buf, Parens::InApply, indent, is_multiline);
|
||||
if !loc_patterns.is_empty() {
|
||||
buf.spaces(1);
|
||||
let mut it = loc_patterns.iter().peekable();
|
||||
while let Some(loc_pattern) = it.next() {
|
||||
loc_pattern.format(buf, indent);
|
||||
|
||||
if !pat.after.is_empty() {
|
||||
if !is_multiline {
|
||||
fmt_comments_only(buf, pat.after.iter(), NewlineAt::Bottom, indent_more)
|
||||
} else {
|
||||
fmt_spaces(buf, pat.after.iter(), indent_more);
|
||||
}
|
||||
}
|
||||
|
||||
for loc_arg in loc_arg_patterns.iter() {
|
||||
buf.spaces(1);
|
||||
fmt_pattern_inner(
|
||||
&loc_arg.value,
|
||||
buf,
|
||||
Parens::InApply,
|
||||
indent_more,
|
||||
is_multiline,
|
||||
);
|
||||
}
|
||||
|
||||
if parens {
|
||||
buf.push(')');
|
||||
}
|
||||
}
|
||||
RecordDestructure(loc_patterns) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("{");
|
||||
|
||||
if !loc_patterns.is_empty() {
|
||||
buf.spaces(1);
|
||||
let mut it = loc_patterns.iter().peekable();
|
||||
while let Some(loc_pattern) = it.next() {
|
||||
let item = pattern_lift_spaces(buf.text.bump(), &loc_pattern.value);
|
||||
|
||||
if !item.before.is_empty() {
|
||||
if !is_multiline {
|
||||
fmt_comments_only(buf, item.before.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
fmt_spaces(buf, item.before.iter(), indent);
|
||||
if it.peek().is_some() {
|
||||
buf.push_str(",");
|
||||
buf.spaces(1);
|
||||
}
|
||||
}
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
fmt_pattern_inner(&item.item, buf, Parens::NotNeeded, indent, is_multiline);
|
||||
buf.push_str("}");
|
||||
}
|
||||
|
||||
let is_multiline = item.item.is_multiline();
|
||||
RequiredField(name, loc_pattern) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name);
|
||||
buf.push_str(":");
|
||||
buf.spaces(1);
|
||||
loc_pattern.format(buf, indent);
|
||||
}
|
||||
|
||||
OptionalField(name, loc_pattern) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name);
|
||||
buf.push_str(" ?");
|
||||
buf.spaces(1);
|
||||
loc_pattern.format(buf, indent);
|
||||
}
|
||||
|
||||
&NumLiteral(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
&NonBase10Literal {
|
||||
base,
|
||||
string,
|
||||
is_negative,
|
||||
} => {
|
||||
buf.indent(indent);
|
||||
if is_negative {
|
||||
buf.push('-');
|
||||
}
|
||||
|
||||
match base {
|
||||
Base::Hex => buf.push_str("0x"),
|
||||
Base::Octal => buf.push_str("0o"),
|
||||
Base::Binary => buf.push_str("0b"),
|
||||
Base::Decimal => { /* nothing */ }
|
||||
}
|
||||
|
||||
buf.push_str(string);
|
||||
}
|
||||
&FloatLiteral(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
StrLiteral(literal) => fmt_str_literal(buf, *literal, indent),
|
||||
SingleQuote(string) => {
|
||||
buf.indent(indent);
|
||||
format_sq_literal(buf, string);
|
||||
}
|
||||
Underscore(name) => {
|
||||
buf.indent(indent);
|
||||
buf.push('_');
|
||||
buf.push_str(name);
|
||||
}
|
||||
Tuple(loc_patterns) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("(");
|
||||
|
||||
let mut it = loc_patterns.iter().peekable();
|
||||
while let Some(loc_pattern) = it.next() {
|
||||
loc_pattern.format(buf, indent);
|
||||
|
||||
if it.peek().is_some() {
|
||||
buf.push_str(",");
|
||||
buf.spaces(1);
|
||||
}
|
||||
}
|
||||
|
||||
if !item.after.is_empty() {
|
||||
if starts_with_inline_comment(item.after.iter()) {
|
||||
buf.spaces(1);
|
||||
}
|
||||
buf.push_str(")");
|
||||
}
|
||||
List(loc_patterns) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("[");
|
||||
|
||||
if !is_multiline {
|
||||
fmt_comments_only(buf, item.after.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
fmt_spaces(buf, item.after.iter(), indent);
|
||||
}
|
||||
let mut it = loc_patterns.iter().peekable();
|
||||
while let Some(loc_pattern) = it.next() {
|
||||
loc_pattern.format(buf, indent);
|
||||
|
||||
if it.peek().is_some() {
|
||||
buf.push_str(",");
|
||||
buf.spaces(1);
|
||||
}
|
||||
}
|
||||
buf.spaces(1);
|
||||
|
||||
buf.push_str("]");
|
||||
}
|
||||
ListRest(opt_pattern_as) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("..");
|
||||
|
||||
buf.indent(indent);
|
||||
buf.push_str("}");
|
||||
}
|
||||
if let Some((list_rest_spaces, pattern_as)) = opt_pattern_as {
|
||||
// these spaces "belong" to the `..`, which can never be multiline
|
||||
fmt_comments_only(buf, list_rest_spaces.iter(), NewlineAt::Bottom, indent);
|
||||
|
||||
RequiredField(name, loc_pattern) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name);
|
||||
buf.push_str(":");
|
||||
buf.spaces(1);
|
||||
fmt_pattern_inner(
|
||||
&loc_pattern.value,
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
indent,
|
||||
is_multiline,
|
||||
);
|
||||
}
|
||||
|
||||
OptionalField(name, loc_pattern) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name);
|
||||
buf.push_str(" ?");
|
||||
buf.spaces(1);
|
||||
loc_pattern.format(buf, indent);
|
||||
}
|
||||
|
||||
NumLiteral(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
NonBase10Literal {
|
||||
base,
|
||||
string,
|
||||
is_negative,
|
||||
} => {
|
||||
buf.indent(indent);
|
||||
if is_negative {
|
||||
buf.push('-');
|
||||
}
|
||||
|
||||
match base {
|
||||
Base::Hex => buf.push_str("0x"),
|
||||
Base::Octal => buf.push_str("0o"),
|
||||
Base::Binary => buf.push_str("0b"),
|
||||
Base::Decimal => { /* nothing */ }
|
||||
}
|
||||
|
||||
buf.push_str(string);
|
||||
}
|
||||
FloatLiteral(string) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
StrLiteral(literal) => fmt_str_literal(buf, literal, indent),
|
||||
SingleQuote(string) => {
|
||||
buf.indent(indent);
|
||||
format_sq_literal(buf, string);
|
||||
}
|
||||
Underscore(name) => {
|
||||
buf.indent(indent);
|
||||
buf.push('_');
|
||||
buf.push_str(name);
|
||||
}
|
||||
Tuple(loc_patterns) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("(");
|
||||
|
||||
let mut it = loc_patterns.iter().peekable();
|
||||
while let Some(loc_pattern) = it.next() {
|
||||
fmt_pattern_inner(
|
||||
&loc_pattern.value,
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
indent,
|
||||
is_multiline,
|
||||
);
|
||||
|
||||
if it.peek().is_some() {
|
||||
buf.indent(indent);
|
||||
buf.push_str(",");
|
||||
buf.spaces(1);
|
||||
pattern_as.format(buf, indent + INDENT);
|
||||
}
|
||||
}
|
||||
|
||||
buf.indent(indent);
|
||||
buf.push_str(")");
|
||||
}
|
||||
List(loc_patterns) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("[");
|
||||
As(pattern, pattern_as) => {
|
||||
let needs_parens = parens == Parens::InAsPattern;
|
||||
|
||||
let mut it = loc_patterns.iter().peekable();
|
||||
while let Some(loc_pattern) = it.next() {
|
||||
fmt_pattern_inner(
|
||||
&loc_pattern.value,
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
indent,
|
||||
is_multiline,
|
||||
);
|
||||
|
||||
if it.peek().is_some() {
|
||||
buf.indent(indent);
|
||||
buf.push_str(",");
|
||||
buf.spaces(1);
|
||||
if needs_parens {
|
||||
buf.push('(');
|
||||
}
|
||||
}
|
||||
|
||||
buf.indent(indent);
|
||||
buf.push_str("]");
|
||||
}
|
||||
ListRest(opt_pattern_as) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("..");
|
||||
|
||||
if let Some((list_rest_spaces, pattern_as)) = opt_pattern_as {
|
||||
// these spaces "belong" to the `..`, which can never be multiline
|
||||
fmt_comments_only(buf, list_rest_spaces.iter(), NewlineAt::Bottom, indent);
|
||||
fmt_pattern(buf, &pattern.value, indent, parens);
|
||||
|
||||
pattern_as.format(buf, indent + INDENT);
|
||||
|
||||
if needs_parens {
|
||||
buf.push(')');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
As(pattern, pattern_as) => {
|
||||
let needs_parens = parens == Parens::InAsPattern;
|
||||
// Space
|
||||
SpaceBefore(sub_pattern, spaces) => {
|
||||
if !sub_pattern.is_multiline() {
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
fmt_spaces(buf, spaces.iter(), indent);
|
||||
}
|
||||
|
||||
if needs_parens {
|
||||
sub_pattern.format_with_options(buf, parens, newlines, indent);
|
||||
}
|
||||
SpaceAfter(sub_pattern, spaces) => {
|
||||
sub_pattern.format_with_options(buf, parens, newlines, indent);
|
||||
|
||||
if starts_with_inline_comment(spaces.iter()) {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
if !sub_pattern.is_multiline() {
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
fmt_spaces(buf, spaces.iter(), indent);
|
||||
}
|
||||
}
|
||||
|
||||
// Malformed
|
||||
Malformed(string) | MalformedIdent(string, _) => {
|
||||
buf.indent(indent);
|
||||
buf.push('(');
|
||||
buf.push_str(string);
|
||||
}
|
||||
|
||||
fmt_pattern(buf, &pattern.value, indent, parens);
|
||||
|
||||
pattern_as.format(buf, indent + INDENT);
|
||||
|
||||
if needs_parens {
|
||||
QualifiedIdentifier { module_name, ident } => {
|
||||
buf.indent(indent);
|
||||
buf.push(')');
|
||||
if !module_name.is_empty() {
|
||||
buf.push_str(module_name);
|
||||
buf.push('.');
|
||||
}
|
||||
|
||||
buf.push_str(ident);
|
||||
}
|
||||
}
|
||||
|
||||
SpaceBefore(..) | SpaceAfter(..) => unreachable!("handled by lift_spaces"),
|
||||
|
||||
// Malformed
|
||||
Malformed(string) | MalformedIdent(string, _) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
QualifiedIdentifier { module_name, ident } => {
|
||||
buf.indent(indent);
|
||||
if !module_name.is_empty() {
|
||||
buf.push_str(module_name);
|
||||
buf.push('.');
|
||||
}
|
||||
|
||||
buf.push_str(ident);
|
||||
}
|
||||
}
|
||||
|
||||
if !me.after.is_empty() {
|
||||
if starts_with_inline_comment(me.after.iter()) {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
if !outer_is_multiline {
|
||||
fmt_comments_only(buf, me.after.iter(), NewlineAt::Bottom, indent)
|
||||
} else {
|
||||
fmt_spaces(buf, me.after.iter(), indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn starts_with_inline_comment<'a, I: IntoIterator<Item = &'a CommentOrNewline<'a>>>(
|
||||
fn starts_with_inline_comment<'a, I: IntoIterator<Item = &'a CommentOrNewline<'a>>>(
|
||||
spaces: I,
|
||||
) -> bool {
|
||||
matches!(
|
||||
|
@ -401,102 +309,3 @@ pub fn starts_with_inline_comment<'a, I: IntoIterator<Item = &'a CommentOrNewlin
|
|||
Some(CommentOrNewline::LineComment(_))
|
||||
)
|
||||
}
|
||||
|
||||
pub fn pattern_lift_spaces<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
pat: &Pattern<'b>,
|
||||
) -> Spaces<'a, Pattern<'a>> {
|
||||
match pat {
|
||||
Pattern::Apply(func, args) => {
|
||||
let func_lifted = pattern_lift_spaces(arena, &func.value);
|
||||
let args = arena.alloc_slice_copy(args);
|
||||
let (before, func, after) = if let Some(last) = args.last_mut() {
|
||||
let last_lifted = pattern_lift_spaces(arena, &last.value);
|
||||
if last_lifted.before.is_empty() {
|
||||
*last = Loc::at(last.region, last_lifted.item)
|
||||
} else {
|
||||
*last = Loc::at(
|
||||
last.region,
|
||||
Pattern::SpaceBefore(arena.alloc(last_lifted.item), last_lifted.before),
|
||||
);
|
||||
}
|
||||
|
||||
let f = if func_lifted.after.is_empty() {
|
||||
func_lifted.item
|
||||
} else {
|
||||
Pattern::SpaceAfter(arena.alloc(func_lifted.item), func_lifted.after)
|
||||
};
|
||||
|
||||
(
|
||||
func_lifted.before,
|
||||
Loc::at(func.region, f),
|
||||
last_lifted.after,
|
||||
)
|
||||
} else {
|
||||
(
|
||||
func_lifted.before,
|
||||
Loc::at(func.region, func_lifted.item),
|
||||
func_lifted.after,
|
||||
)
|
||||
};
|
||||
Spaces {
|
||||
before,
|
||||
item: Pattern::Apply(arena.alloc(func), args),
|
||||
after,
|
||||
}
|
||||
}
|
||||
Pattern::OptionalField(name, expr) => {
|
||||
let lifted = expr_lift_spaces_after(Parens::NotNeeded, arena, &expr.value);
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: Pattern::OptionalField(name, arena.alloc(Loc::at(expr.region, lifted.item))),
|
||||
after: lifted.after,
|
||||
}
|
||||
}
|
||||
Pattern::RequiredField(name, pat) => {
|
||||
let lifted = pattern_lift_spaces_after(arena, &pat.value);
|
||||
Spaces {
|
||||
before: &[],
|
||||
item: Pattern::RequiredField(name, arena.alloc(Loc::at(pat.region, lifted.item))),
|
||||
after: lifted.after,
|
||||
}
|
||||
}
|
||||
Pattern::SpaceBefore(expr, spaces) => {
|
||||
let mut inner = pattern_lift_spaces(arena, expr);
|
||||
inner.before = merge_spaces(arena, spaces, inner.before);
|
||||
inner
|
||||
}
|
||||
Pattern::SpaceAfter(expr, spaces) => {
|
||||
let mut inner = pattern_lift_spaces(arena, expr);
|
||||
inner.after = merge_spaces(arena, inner.after, spaces);
|
||||
inner
|
||||
}
|
||||
_ => Spaces {
|
||||
before: &[],
|
||||
item: *pat,
|
||||
after: &[],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pattern_lift_spaces_before<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
pat: &Pattern<'b>,
|
||||
) -> SpacesBefore<'a, Pattern<'a>> {
|
||||
let lifted = pattern_lift_spaces(arena, pat);
|
||||
SpacesBefore {
|
||||
before: lifted.before,
|
||||
item: lifted.item.maybe_after(arena, lifted.after),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pattern_lift_spaces_after<'a, 'b: 'a>(
|
||||
arena: &'a Bump,
|
||||
pat: &Pattern<'b>,
|
||||
) -> SpacesAfter<'a, Pattern<'a>> {
|
||||
let lifted = pattern_lift_spaces(arena, pat);
|
||||
SpacesAfter {
|
||||
item: lifted.item.maybe_before(arena, lifted.before),
|
||||
after: lifted.after,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,26 +28,12 @@ pub struct Spaces<'a, T> {
|
|||
pub after: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
impl<'a, T: Copy> ExtractSpaces<'a> for Spaces<'a, T> {
|
||||
type Item = T;
|
||||
|
||||
fn extract_spaces(&self) -> Spaces<'a, T> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct SpacesBefore<'a, T> {
|
||||
pub before: &'a [CommentOrNewline<'a>],
|
||||
pub item: T,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct SpacesAfter<'a, T> {
|
||||
pub after: &'a [CommentOrNewline<'a>],
|
||||
pub item: T,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum Spaced<'a, T> {
|
||||
Item(T),
|
||||
|
@ -505,11 +491,7 @@ pub enum Expr<'a> {
|
|||
Backpassing(&'a [Loc<Pattern<'a>>], &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
Dbg,
|
||||
DbgStmt {
|
||||
first: &'a Loc<Expr<'a>>,
|
||||
extra_args: &'a [&'a Loc<Expr<'a>>],
|
||||
continuation: &'a Loc<Expr<'a>>,
|
||||
},
|
||||
DbgStmt(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
// This form of debug is a desugared call to roc_dbg
|
||||
LowLevelDbg(&'a (&'a str, &'a str), &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
@ -645,7 +627,7 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
|||
Expr::ParensAround(sub_loc_expr) => is_expr_suffixed(sub_loc_expr),
|
||||
|
||||
// expression in a closure
|
||||
Expr::Closure(_, _) => false,
|
||||
Expr::Closure(_, sub_loc_expr) => is_expr_suffixed(&sub_loc_expr.value),
|
||||
|
||||
// expressions inside a Defs
|
||||
Expr::Defs(defs, expr) => {
|
||||
|
@ -689,15 +671,7 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
|||
Expr::OpaqueRef(_) => false,
|
||||
Expr::Backpassing(_, _, _) => false, // TODO: we might want to check this?
|
||||
Expr::Dbg => false,
|
||||
Expr::DbgStmt {
|
||||
first,
|
||||
extra_args,
|
||||
continuation,
|
||||
} => {
|
||||
is_expr_suffixed(&first.value)
|
||||
|| extra_args.iter().any(|a| is_expr_suffixed(&a.value))
|
||||
|| is_expr_suffixed(&continuation.value)
|
||||
}
|
||||
Expr::DbgStmt(a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::LowLevelDbg(_, a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::Try => false,
|
||||
Expr::UnaryOp(a, _) => is_expr_suffixed(&a.value),
|
||||
|
@ -956,17 +930,10 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
expr_stack.push(&a.value);
|
||||
expr_stack.push(&b.value);
|
||||
}
|
||||
DbgStmt {
|
||||
first,
|
||||
extra_args,
|
||||
continuation,
|
||||
} => {
|
||||
DbgStmt(condition, cont) => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&first.value);
|
||||
for arg in extra_args.iter() {
|
||||
expr_stack.push(&arg.value);
|
||||
}
|
||||
expr_stack.push(&continuation.value);
|
||||
expr_stack.push(&condition.value);
|
||||
expr_stack.push(&cont.value);
|
||||
}
|
||||
LowLevelDbg(_, condition, cont) => {
|
||||
expr_stack.reserve(2);
|
||||
|
@ -2344,7 +2311,6 @@ impl_extract_spaces!(Tag);
|
|||
impl_extract_spaces!(AssignedField<T>);
|
||||
impl_extract_spaces!(TypeAnnotation);
|
||||
impl_extract_spaces!(ImplementsAbility);
|
||||
impl_extract_spaces!(ImplementsAbilities);
|
||||
|
||||
impl<'a, T: Copy> ExtractSpaces<'a> for Spaced<'a, T> {
|
||||
type Item = T;
|
||||
|
@ -2510,7 +2476,7 @@ impl<'a> Malformed for Expr<'a> {
|
|||
Defs(defs, body) => defs.is_malformed() || body.is_malformed(),
|
||||
Backpassing(args, call, body) => args.iter().any(|arg| arg.is_malformed()) || call.is_malformed() || body.is_malformed(),
|
||||
Dbg => false,
|
||||
DbgStmt { first, extra_args, continuation } => first.is_malformed() || extra_args.iter().any(|a| a.is_malformed()) || continuation.is_malformed(),
|
||||
DbgStmt(condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
LowLevelDbg(_, condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
Try => false,
|
||||
Return(return_value, after_return) => return_value.is_malformed() || after_return.is_some_and(|ar| ar.is_malformed()),
|
||||
|
|
|
@ -298,11 +298,8 @@ fn loc_possibly_negative_or_negated_term<'a>(
|
|||
let parse_unary_negate = move |arena, state: State<'a>, min_indent: u32| {
|
||||
let initial = state.clone();
|
||||
|
||||
let (_, (loc_op, loc_expr), state) = and(
|
||||
loc(unary_negate()),
|
||||
loc_possibly_negative_or_negated_term(options),
|
||||
)
|
||||
.parse(arena, state, min_indent)?;
|
||||
let (_, (loc_op, loc_expr), state) =
|
||||
and(loc(unary_negate()), loc_term(options)).parse(arena, state, min_indent)?;
|
||||
|
||||
let loc_expr = numeric_negate_expression(arena, initial, loc_op, loc_expr, &[]);
|
||||
|
||||
|
@ -310,23 +307,19 @@ fn loc_possibly_negative_or_negated_term<'a>(
|
|||
};
|
||||
|
||||
one_of![
|
||||
parse_unary_negate.trace("d"),
|
||||
parse_unary_negate,
|
||||
// this will parse negative numbers, which the unary negate thing up top doesn't (for now)
|
||||
loc(specialize_err(EExpr::Number, number_literal_help())).trace("c"),
|
||||
loc(specialize_err(EExpr::Number, number_literal_help())),
|
||||
loc(map_with_arena(
|
||||
and(
|
||||
loc(byte(b'!', EExpr::Start)),
|
||||
space0_before_e(
|
||||
loc_possibly_negative_or_negated_term(options),
|
||||
EExpr::IndentStart
|
||||
)
|
||||
space0_before_e(loc_term(options), EExpr::IndentStart)
|
||||
),
|
||||
|arena: &'a Bump, (loc_op, loc_expr): (Loc<_>, _)| {
|
||||
Expr::UnaryOp(arena.alloc(loc_expr), Loc::at(loc_op.region, UnaryOp::Not))
|
||||
}
|
||||
))
|
||||
.trace("b"),
|
||||
loc_term_or_underscore_or_conditional(options).trace("a")
|
||||
)),
|
||||
loc_term_or_underscore_or_conditional(options)
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -335,7 +328,7 @@ fn fail_expr_start_e<'a, T: 'a>() -> impl Parser<'a, T, EExpr<'a>> {
|
|||
}
|
||||
|
||||
fn unary_negate<'a>() -> impl Parser<'a, (), EExpr<'a>> {
|
||||
move |_arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| {
|
||||
// a minus is unary iff
|
||||
//
|
||||
// - it is preceded by whitespace (spaces, newlines, comments)
|
||||
|
@ -346,10 +339,7 @@ fn unary_negate<'a>() -> impl Parser<'a, (), EExpr<'a>> {
|
|||
.map(|c| c.is_ascii_whitespace() || *c == b'#')
|
||||
.unwrap_or(false);
|
||||
|
||||
if state.bytes().starts_with(b"-")
|
||||
&& !followed_by_whitespace
|
||||
&& state.column() >= min_indent
|
||||
{
|
||||
if state.bytes().starts_with(b"-") && !followed_by_whitespace {
|
||||
// the negate is only unary if it is not followed by whitespace
|
||||
let state = state.advance(1);
|
||||
Ok((MadeProgress, (), state))
|
||||
|
@ -469,7 +459,7 @@ fn parse_expr_after_apply<'a>(
|
|||
before_op: State<'a>,
|
||||
initial_state: State<'a>,
|
||||
) -> Result<(Progress, Expr<'a>, State<'a>), (Progress, EExpr<'a>)> {
|
||||
match loc(bin_op(check_for_defs)).parse(arena, state.clone(), call_min_indent) {
|
||||
match loc(bin_op(check_for_defs)).parse(arena, state.clone(), min_indent) {
|
||||
Err((MadeProgress, f)) => Err((MadeProgress, f)),
|
||||
Ok((_, loc_op, state)) => {
|
||||
expr_state.consume_spaces(arena);
|
||||
|
@ -855,13 +845,13 @@ fn numeric_negate_expression<'a, T>(
|
|||
let region = Region::new(start, expr.region.end());
|
||||
|
||||
let new_expr = match expr.value {
|
||||
Expr::Num(string) if !string.starts_with('-') => {
|
||||
Expr::Num(string) => {
|
||||
let new_string =
|
||||
unsafe { std::str::from_utf8_unchecked(&state.bytes()[..string.len() + 1]) };
|
||||
|
||||
Expr::Num(new_string)
|
||||
}
|
||||
Expr::Float(string) if !string.starts_with('-') => {
|
||||
Expr::Float(string) => {
|
||||
let new_string =
|
||||
unsafe { std::str::from_utf8_unchecked(&state.bytes()[..string.len() + 1]) };
|
||||
|
||||
|
@ -870,11 +860,11 @@ fn numeric_negate_expression<'a, T>(
|
|||
Expr::NonBase10Int {
|
||||
string,
|
||||
base,
|
||||
is_negative: false,
|
||||
is_negative,
|
||||
} => {
|
||||
// don't include the minus sign here; it will not be parsed right
|
||||
Expr::NonBase10Int {
|
||||
is_negative: true,
|
||||
is_negative: !is_negative,
|
||||
string,
|
||||
base,
|
||||
}
|
||||
|
@ -1161,7 +1151,9 @@ fn parse_stmt_alias_or_opaque<'a>(
|
|||
AliasOrOpaque::Alias => {
|
||||
let (_, signature, state) = alias_signature().parse(arena, state, min_indent)?;
|
||||
|
||||
let signature = signature.map(|v| v.maybe_before(arena, spaces_after_operator));
|
||||
// TODO: this code used to be broken and it dropped the spaces after the operator.
|
||||
// The formatter is not expecting this, so let's keep it as is for now.
|
||||
// let signature = signature.map(|v| v.maybe_before(arena, spaces_after_operator));
|
||||
|
||||
let header = TypeHeader {
|
||||
name: Loc::at(expr.region, name),
|
||||
|
@ -1180,7 +1172,9 @@ fn parse_stmt_alias_or_opaque<'a>(
|
|||
let (_, (signature, derived), state) =
|
||||
opaque_signature().parse(arena, state, indented_more)?;
|
||||
|
||||
let signature = signature.map(|v| v.maybe_before(arena, spaces_after_operator));
|
||||
// TODO: this code used to be broken and it dropped the spaces after the operator.
|
||||
// The formatter is not expecting this, so let's keep it as is for now.
|
||||
// let signature = signature.map(|v| v.maybe_before(arena, spaces_after_operator));
|
||||
|
||||
let header = TypeHeader {
|
||||
name: Loc::at(expr.region, name),
|
||||
|
@ -1861,7 +1855,7 @@ fn parse_expr_end<'a>(
|
|||
Err((NoProgress, _)) => {
|
||||
let before_op = state.clone();
|
||||
// try an operator
|
||||
match loc(bin_op(check_for_defs)).parse(arena, state.clone(), call_min_indent) {
|
||||
match loc(bin_op(check_for_defs)).parse(arena, state.clone(), min_indent) {
|
||||
Err((MadeProgress, f)) => Err((MadeProgress, f)),
|
||||
Ok((_, loc_op, state)) => {
|
||||
expr_state.consume_spaces(arena);
|
||||
|
@ -1905,7 +1899,7 @@ fn parse_stmt_after_apply<'a>(
|
|||
initial_state: State<'a>,
|
||||
) -> ParseResult<'a, Stmt<'a>, EExpr<'a>> {
|
||||
let before_op = state.clone();
|
||||
match loc(operator()).parse(arena, state.clone(), call_min_indent) {
|
||||
match loc(operator()).parse(arena, state.clone(), min_indent) {
|
||||
Err((MadeProgress, f)) => Err((MadeProgress, f)),
|
||||
Ok((_, loc_op, state)) => {
|
||||
expr_state.consume_spaces(arena);
|
||||
|
@ -2178,7 +2172,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::If { .. }
|
||||
| Expr::When(_, _)
|
||||
| Expr::Dbg
|
||||
| Expr::DbgStmt { .. }
|
||||
| Expr::DbgStmt(_, _)
|
||||
| Expr::LowLevelDbg(_, _, _)
|
||||
| Expr::Return(_, _)
|
||||
| Expr::MalformedSuffixed(..)
|
||||
|
@ -3092,13 +3086,16 @@ fn stmts_to_defs<'a>(
|
|||
_,
|
||||
) = e
|
||||
{
|
||||
if args.len() != 1 {
|
||||
// TODO: this should be done in can, not parsing!
|
||||
return Err(EExpr::Dbg(
|
||||
EExpect::DbgArity(sp_stmt.item.region.start()),
|
||||
sp_stmt.item.region.start(),
|
||||
));
|
||||
}
|
||||
let condition = &args[0];
|
||||
let rest = stmts_to_expr(&stmts[i + 1..], arena)?;
|
||||
let e = Expr::DbgStmt {
|
||||
first: condition,
|
||||
extra_args: &args[1..],
|
||||
continuation: arena.alloc(rest),
|
||||
};
|
||||
let e = Expr::DbgStmt(condition, arena.alloc(rest));
|
||||
|
||||
let e = if sp_stmt.before.is_empty() {
|
||||
e
|
||||
|
@ -3214,11 +3211,7 @@ fn stmts_to_defs<'a>(
|
|||
if exprify_dbg {
|
||||
let e = if i + 1 < stmts.len() {
|
||||
let rest = stmts_to_expr(&stmts[i + 1..], arena)?;
|
||||
Expr::DbgStmt {
|
||||
first: arena.alloc(condition),
|
||||
extra_args: &[],
|
||||
continuation: arena.alloc(rest),
|
||||
}
|
||||
Expr::DbgStmt(arena.alloc(condition), arena.alloc(rest))
|
||||
} else {
|
||||
Expr::Apply(
|
||||
arena.alloc(Loc {
|
||||
|
@ -3806,9 +3799,9 @@ enum OperatorOrDef {
|
|||
}
|
||||
|
||||
fn bin_op<'a>(check_for_defs: bool) -> impl Parser<'a, BinOp, EExpr<'a>> {
|
||||
move |_, state: State<'a>, min_indent| {
|
||||
move |_, state: State<'a>, _m| {
|
||||
let start = state.pos();
|
||||
let (_, op, state) = operator_help(EExpr::Start, EExpr::BadOperator, state, min_indent)?;
|
||||
let (_, op, state) = operator_help(EExpr::Start, EExpr::BadOperator, state)?;
|
||||
let err_progress = if check_for_defs {
|
||||
MadeProgress
|
||||
} else {
|
||||
|
@ -3829,8 +3822,7 @@ fn bin_op<'a>(check_for_defs: bool) -> impl Parser<'a, BinOp, EExpr<'a>> {
|
|||
}
|
||||
|
||||
fn operator<'a>() -> impl Parser<'a, OperatorOrDef, EExpr<'a>> {
|
||||
(move |_, state, min_indent| operator_help(EExpr::Start, EExpr::BadOperator, state, min_indent))
|
||||
.trace("operator")
|
||||
(move |_, state, _m| operator_help(EExpr::Start, EExpr::BadOperator, state)).trace("operator")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -3838,7 +3830,6 @@ fn operator_help<'a, F, G, E>(
|
|||
to_expectation: F,
|
||||
to_error: G,
|
||||
mut state: State<'a>,
|
||||
min_indent: u32,
|
||||
) -> ParseResult<'a, OperatorOrDef, E>
|
||||
where
|
||||
F: Fn(Position) -> E,
|
||||
|
@ -3864,21 +3855,7 @@ where
|
|||
match chomped {
|
||||
"" => Err((NoProgress, to_expectation(state.pos()))),
|
||||
"+" => good!(OperatorOrDef::BinOp(BinOp::Plus), 1),
|
||||
"-" => {
|
||||
// A unary minus must only match if we are at the correct indent level; indent level doesn't
|
||||
// matter for the rest of the operators.
|
||||
|
||||
// Note that a unary minus is distinguished by not having a space after it
|
||||
let has_whitespace = matches!(
|
||||
state.bytes().get(1),
|
||||
Some(b' ' | b'#' | b'\n' | b'\r' | b'\t') | None
|
||||
);
|
||||
if !has_whitespace && state.column() < min_indent {
|
||||
return Err((NoProgress, to_expectation(state.pos())));
|
||||
}
|
||||
|
||||
good!(OperatorOrDef::BinOp(BinOp::Minus), 1)
|
||||
}
|
||||
"-" => good!(OperatorOrDef::BinOp(BinOp::Minus), 1),
|
||||
"*" => good!(OperatorOrDef::BinOp(BinOp::Star), 1),
|
||||
"/" => good!(OperatorOrDef::BinOp(BinOp::Slash), 1),
|
||||
"%" => good!(OperatorOrDef::BinOp(BinOp::Percent), 1),
|
||||
|
@ -3906,10 +3883,6 @@ where
|
|||
}
|
||||
"<-" => good!(OperatorOrDef::Backpassing, 2),
|
||||
"!" => Err((NoProgress, to_error("!", state.pos()))),
|
||||
"&" => {
|
||||
// makes no progress, so it does not interfere with record updaters / `&foo`
|
||||
Err((NoProgress, to_error("&", state.pos())))
|
||||
}
|
||||
_ => bad_made_progress!(chomped),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -396,22 +396,10 @@ impl<'a> Normalize<'a> for ValueDef<'a> {
|
|||
|
||||
match *self {
|
||||
Annotation(a, b) => Annotation(a.normalize(arena), b.normalize(arena)),
|
||||
Body(a, b) => {
|
||||
let a = a.normalize(arena);
|
||||
let b = b.normalize(arena);
|
||||
|
||||
let is_unit_assignment = if let Pattern::RecordDestructure(collection) = a.value {
|
||||
collection.is_empty()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if is_unit_assignment {
|
||||
Stmt(arena.alloc(b))
|
||||
} else {
|
||||
Body(arena.alloc(a), arena.alloc(b))
|
||||
}
|
||||
}
|
||||
Body(a, b) => Body(
|
||||
arena.alloc(a.normalize(arena)),
|
||||
arena.alloc(b.normalize(arena)),
|
||||
),
|
||||
AnnotatedBody {
|
||||
ann_pattern,
|
||||
ann_type,
|
||||
|
@ -572,6 +560,26 @@ impl<'a> Normalize<'a> for StrLiteral<'a> {
|
|||
match *self {
|
||||
StrLiteral::PlainLine(t) => StrLiteral::PlainLine(t),
|
||||
StrLiteral::Line(t) => {
|
||||
let mut needs_merge = false;
|
||||
let mut last_was_mergable = false;
|
||||
for segment in t.iter() {
|
||||
let mergable = matches!(
|
||||
segment,
|
||||
StrSegment::Plaintext(_)
|
||||
| StrSegment::Unicode(_)
|
||||
| StrSegment::EscapedChar(_)
|
||||
);
|
||||
if mergable && last_was_mergable {
|
||||
needs_merge = true;
|
||||
break;
|
||||
}
|
||||
last_was_mergable = mergable;
|
||||
}
|
||||
|
||||
if !needs_merge {
|
||||
return StrLiteral::Line(t.normalize(arena));
|
||||
}
|
||||
|
||||
let mut new_segments = Vec::new_in(arena);
|
||||
let mut last_text = String::new_in(arena);
|
||||
|
||||
|
@ -705,22 +713,33 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
arena.alloc(b.normalize(arena)),
|
||||
),
|
||||
Expr::Crash => Expr::Crash,
|
||||
Expr::Defs(a, b) => fold_defs(arena, a.defs(), b.value.normalize(arena)),
|
||||
Expr::Defs(a, b) => {
|
||||
let mut defs = a.clone();
|
||||
defs.space_before = vec![Default::default(); defs.len()];
|
||||
defs.space_after = vec![Default::default(); defs.len()];
|
||||
defs.regions = vec![Region::zero(); defs.len()];
|
||||
defs.spaces.clear();
|
||||
|
||||
for type_def in defs.type_defs.iter_mut() {
|
||||
*type_def = type_def.normalize(arena);
|
||||
}
|
||||
|
||||
for value_def in defs.value_defs.iter_mut() {
|
||||
*value_def = value_def.normalize(arena);
|
||||
}
|
||||
|
||||
Expr::Defs(arena.alloc(defs), arena.alloc(b.normalize(arena)))
|
||||
}
|
||||
Expr::Backpassing(a, b, c) => Expr::Backpassing(
|
||||
arena.alloc(a.normalize(arena)),
|
||||
arena.alloc(b.normalize(arena)),
|
||||
arena.alloc(c.normalize(arena)),
|
||||
),
|
||||
Expr::Dbg => Expr::Dbg,
|
||||
Expr::DbgStmt {
|
||||
first,
|
||||
extra_args,
|
||||
continuation,
|
||||
} => Expr::DbgStmt {
|
||||
first: arena.alloc(first.normalize(arena)),
|
||||
extra_args: extra_args.normalize(arena),
|
||||
continuation: arena.alloc(continuation.normalize(arena)),
|
||||
},
|
||||
Expr::DbgStmt(a, b) => Expr::DbgStmt(
|
||||
arena.alloc(a.normalize(arena)),
|
||||
arena.alloc(b.normalize(arena)),
|
||||
),
|
||||
Expr::LowLevelDbg(x, a, b) => Expr::LowLevelDbg(
|
||||
x,
|
||||
arena.alloc(a.normalize(arena)),
|
||||
|
@ -736,22 +755,7 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
}
|
||||
Expr::BinOps(a, b) => Expr::BinOps(a.normalize(arena), arena.alloc(b.normalize(arena))),
|
||||
Expr::UnaryOp(a, b) => {
|
||||
let a = a.normalize(arena);
|
||||
match (a.value, b.value) {
|
||||
(Expr::Num(text), UnaryOp::Negate) if !text.starts_with('-') => {
|
||||
let mut res = String::new_in(arena);
|
||||
res.push('-');
|
||||
res.push_str(text);
|
||||
Expr::Num(res.into_bump_str())
|
||||
}
|
||||
(Expr::Float(text), UnaryOp::Negate) if !text.starts_with('-') => {
|
||||
let mut res = String::new_in(arena);
|
||||
res.push('-');
|
||||
res.push_str(text);
|
||||
Expr::Float(res.into_bump_str())
|
||||
}
|
||||
_ => Expr::UnaryOp(arena.alloc(a), b.normalize(arena)),
|
||||
}
|
||||
Expr::UnaryOp(arena.alloc(a.normalize(arena)), b.normalize(arena))
|
||||
}
|
||||
Expr::If {
|
||||
if_thens,
|
||||
|
@ -772,7 +776,7 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
Expr::PrecedenceConflict(a) => Expr::PrecedenceConflict(a),
|
||||
Expr::SpaceBefore(a, _) => a.normalize(arena),
|
||||
Expr::SpaceAfter(a, _) => a.normalize(arena),
|
||||
Expr::SingleQuote(a) => Expr::SingleQuote(a),
|
||||
Expr::SingleQuote(a) => Expr::Num(a),
|
||||
Expr::EmptyRecordBuilder(a) => {
|
||||
Expr::EmptyRecordBuilder(arena.alloc(a.normalize(arena)))
|
||||
}
|
||||
|
@ -787,61 +791,6 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_defs<'a>(
|
||||
arena: &'a Bump,
|
||||
mut defs: impl Iterator<Item = Result<&'a TypeDef<'a>, &'a ValueDef<'a>>>,
|
||||
final_expr: Expr<'a>,
|
||||
) -> Expr<'a> {
|
||||
let mut new_defs = Defs::default();
|
||||
|
||||
while let Some(def) = defs.next() {
|
||||
match def {
|
||||
Ok(td) => {
|
||||
let td = td.normalize(arena);
|
||||
new_defs.push_type_def(td, Region::zero(), &[], &[]);
|
||||
}
|
||||
Err(vd) => {
|
||||
let vd = vd.normalize(arena);
|
||||
|
||||
match vd {
|
||||
ValueDef::Stmt(&Loc {
|
||||
value:
|
||||
Expr::Apply(
|
||||
&Loc {
|
||||
value: Expr::Dbg, ..
|
||||
},
|
||||
args,
|
||||
_,
|
||||
),
|
||||
..
|
||||
}) => {
|
||||
let rest = fold_defs(arena, defs, final_expr);
|
||||
let new_final = Expr::DbgStmt {
|
||||
first: args[0],
|
||||
extra_args: &args[1..],
|
||||
continuation: arena.alloc(Loc::at_zero(rest)),
|
||||
};
|
||||
if new_defs.is_empty() {
|
||||
return new_final;
|
||||
}
|
||||
return Expr::Defs(
|
||||
arena.alloc(new_defs),
|
||||
arena.alloc(Loc::at_zero(new_final)),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
new_defs.push_value_def(vd, Region::zero(), &[], &[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if new_defs.is_empty() {
|
||||
return final_expr;
|
||||
}
|
||||
Expr::Defs(arena.alloc(new_defs), arena.alloc(Loc::at_zero(final_expr)))
|
||||
}
|
||||
|
||||
fn remove_spaces_bad_ident(ident: BadIdent) -> BadIdent {
|
||||
match ident {
|
||||
BadIdent::Start(_) => BadIdent::Start(Position::zero()),
|
||||
|
@ -898,7 +847,7 @@ impl<'a> Normalize<'a> for Pattern<'a> {
|
|||
is_negative,
|
||||
},
|
||||
Pattern::FloatLiteral(a) => Pattern::FloatLiteral(a),
|
||||
Pattern::StrLiteral(a) => Pattern::StrLiteral(a.normalize(arena)),
|
||||
Pattern::StrLiteral(a) => Pattern::StrLiteral(a),
|
||||
Pattern::Underscore(a) => Pattern::Underscore(a),
|
||||
Pattern::Malformed(a) => Pattern::Malformed(a),
|
||||
Pattern::MalformedIdent(a, b) => Pattern::MalformedIdent(a, remove_spaces_bad_ident(b)),
|
||||
|
@ -1516,6 +1465,7 @@ impl<'a> Normalize<'a> for EExpect<'a> {
|
|||
EExpect::Continuation(arena.alloc(inner_err.normalize(arena)), Position::zero())
|
||||
}
|
||||
EExpect::IndentCondition(_) => EExpect::IndentCondition(Position::zero()),
|
||||
EExpect::DbgArity(_) => EExpect::DbgArity(Position::zero()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -513,6 +513,7 @@ pub enum EExpect<'a> {
|
|||
Condition(&'a EExpr<'a>, Position),
|
||||
Continuation(&'a EExpr<'a>, Position),
|
||||
IndentCondition(Position),
|
||||
DbgArity(Position),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -835,7 +836,7 @@ where
|
|||
}
|
||||
|
||||
// This should be enough for anyone. Right? RIGHT?
|
||||
let indent_text = "| ; : ! ".repeat(100);
|
||||
let indent_text = "| ; : ! ".repeat(20);
|
||||
|
||||
let cur_indent = INDENT.with(|i| *i.borrow());
|
||||
|
||||
|
@ -1059,15 +1060,11 @@ where
|
|||
Some(
|
||||
b' ' | b'#' | b'\n' | b'\r' | b'\t' | b',' | b'(' | b')' | b'[' | b']' | b'{'
|
||||
| b'}' | b'"' | b'\'' | b'/' | b'\\' | b'+' | b'*' | b'%' | b'^' | b'&' | b'|'
|
||||
| b'<' | b'>' | b'=' | b'!' | b'~' | b'`' | b';' | b':' | b'?' | b'.' | b'@',
|
||||
| b'<' | b'>' | b'=' | b'!' | b'~' | b'`' | b';' | b':' | b'?' | b'.',
|
||||
) => {
|
||||
state = state.advance(width);
|
||||
Ok((MadeProgress, (), state))
|
||||
}
|
||||
Some(b'-') if keyword_str != "expect" => {
|
||||
state = state.advance(width);
|
||||
Ok((MadeProgress, (), state))
|
||||
}
|
||||
None => {
|
||||
state = state.advance(width);
|
||||
Ok((MadeProgress, (), state))
|
||||
|
@ -1672,21 +1669,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a parser that fails if the next byte is the given byte.
|
||||
pub fn error_on_byte<'a, T, E, F>(byte_to_match: u8, to_error: F) -> impl Parser<'a, T, E>
|
||||
where
|
||||
T: 'a,
|
||||
E: 'a,
|
||||
F: Fn(Position) -> E,
|
||||
{
|
||||
debug_assert_ne!(byte_to_match, b'\n');
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| match state.bytes().first() {
|
||||
Some(x) if *x == byte_to_match => Err((MadeProgress, to_error(state.pos()))),
|
||||
_ => Err((NoProgress, to_error(state.pos()))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs two parsers in succession. If both parsers succeed, the output is a tuple of both outputs.
|
||||
/// Both parsers must have the same error type.
|
||||
///
|
||||
|
|
|
@ -10,9 +10,9 @@ use crate::expr::record_field;
|
|||
use crate::ident::{lowercase_ident, lowercase_ident_keyword_e};
|
||||
use crate::keyword;
|
||||
use crate::parser::{
|
||||
absolute_column_min_indent, and, collection_trailing_sep_e, either, error_on_byte,
|
||||
increment_min_indent, indented_seq, loc, map, map_with_arena, skip_first, skip_second, succeed,
|
||||
then, zero_or_more, ERecord, ETypeAbilityImpl,
|
||||
absolute_column_min_indent, and, collection_trailing_sep_e, either, increment_min_indent,
|
||||
indented_seq, loc, map, map_with_arena, skip_first, skip_second, succeed, then, zero_or_more,
|
||||
ERecord, ETypeAbilityImpl,
|
||||
};
|
||||
use crate::parser::{
|
||||
allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes,
|
||||
|
@ -27,13 +27,13 @@ use roc_region::all::{Loc, Position, Region};
|
|||
pub fn located<'a>(
|
||||
is_trailing_comma_valid: bool,
|
||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||
expression(is_trailing_comma_valid, false).trace("a")
|
||||
expression(is_trailing_comma_valid, false)
|
||||
}
|
||||
|
||||
pub fn located_opaque_signature<'a>(
|
||||
is_trailing_comma_valid: bool,
|
||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||
expression(is_trailing_comma_valid, true).trace("b")
|
||||
expression(is_trailing_comma_valid, true)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -241,7 +241,7 @@ fn loc_type_in_parens<'a>(
|
|||
loc(and(
|
||||
collection_trailing_sep_e(
|
||||
byte(b'(', ETypeInParens::Open),
|
||||
specialize_err_ref(ETypeInParens::Type, expression(true, false).trace("c")),
|
||||
specialize_err_ref(ETypeInParens::Type, expression(true, false)),
|
||||
byte(b',', ETypeInParens::End),
|
||||
byte(b')', ETypeInParens::End),
|
||||
TypeAnnotation::SpaceBefore,
|
||||
|
@ -334,7 +334,7 @@ fn record_type_field<'a>() -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'
|
|||
))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let val_parser = specialize_err_ref(ETypeRecord::Type, expression(true, false).trace("d"));
|
||||
let val_parser = specialize_err_ref(ETypeRecord::Type, expression(true, false));
|
||||
|
||||
match opt_loc_val {
|
||||
Some(First(_)) => {
|
||||
|
@ -582,39 +582,37 @@ fn expression<'a>(
|
|||
let (p1, first, state) = space0_before_e(term(stop_at_surface_has), EType::TIndentStart)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let (p2, rest, rest_state) = zero_or_more(skip_first(
|
||||
backtrackable(byte(b',', EType::TFunctionArgument)),
|
||||
one_of![
|
||||
map_with_arena(
|
||||
and(
|
||||
backtrackable(space0_e(EType::TIndentStart)),
|
||||
and(term(stop_at_surface_has), space0_e(EType::TIndentEnd)),
|
||||
),
|
||||
comma_args_help,
|
||||
),
|
||||
error_on_byte(b',', EType::TFunctionArgument)
|
||||
],
|
||||
))
|
||||
.trace("type_annotation:expression:rest_args")
|
||||
.parse(arena, state.clone(), min_indent)?;
|
||||
|
||||
let result = and(
|
||||
space0_e(EType::TIndentStart),
|
||||
one_of![
|
||||
map(two_bytes(b'-', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Pure
|
||||
}),
|
||||
map(two_bytes(b'=', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Effectful
|
||||
}),
|
||||
],
|
||||
zero_or_more(skip_first(
|
||||
byte(b',', EType::TFunctionArgument),
|
||||
one_of![
|
||||
space0_around_ee(
|
||||
term(stop_at_surface_has),
|
||||
EType::TIndentStart,
|
||||
EType::TIndentEnd
|
||||
),
|
||||
fail(EType::TFunctionArgument)
|
||||
],
|
||||
))
|
||||
.trace("type_annotation:expression:rest_args"),
|
||||
and(
|
||||
space0_e(EType::TIndentStart),
|
||||
one_of![
|
||||
map(two_bytes(b'-', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Pure
|
||||
}),
|
||||
map(two_bytes(b'=', b'>', EType::TStart), |_| {
|
||||
FunctionArrow::Effectful
|
||||
}),
|
||||
],
|
||||
)
|
||||
.trace("type_annotation:expression:arrow"),
|
||||
)
|
||||
.trace("type_annotation:expression:arrow")
|
||||
.parse(arena, rest_state, min_indent);
|
||||
.parse(arena, state.clone(), min_indent);
|
||||
|
||||
let (progress, annot, state) = match result {
|
||||
Ok((p3, (space_before_arrow, arrow), state)) => {
|
||||
let (p4, return_type, state) =
|
||||
Ok((p2, (rest, (space_before_arrow, arrow)), state)) => {
|
||||
let (p3, return_type, state) =
|
||||
space0_before_e(term(stop_at_surface_has), EType::TIndentStart)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
|
@ -638,7 +636,7 @@ fn expression<'a>(
|
|||
region,
|
||||
value: TypeAnnotation::Function(output, arrow, arena.alloc(return_type)),
|
||||
};
|
||||
let progress = p1.or(p2).or(p3).or(p4);
|
||||
let progress = p1.or(p2).or(p3);
|
||||
(progress, result, state)
|
||||
}
|
||||
Err(err) => {
|
||||
|
@ -666,10 +664,7 @@ fn expression<'a>(
|
|||
|
||||
// Finally, try to parse a where clause if there is one.
|
||||
// The where clause must be at least as deep as where the type annotation started.
|
||||
match implements_clause_chain()
|
||||
.trace("implements_clause_chain")
|
||||
.parse(arena, state.clone(), min_indent)
|
||||
{
|
||||
match implements_clause_chain().parse(arena, state.clone(), min_indent) {
|
||||
Ok((where_progress, (spaces_before, implements_chain), state)) => {
|
||||
let region =
|
||||
Region::span_across(&annot.region, &implements_chain.last().unwrap().region);
|
||||
|
@ -699,36 +694,6 @@ fn expression<'a>(
|
|||
.trace("type_annotation:expression")
|
||||
}
|
||||
|
||||
fn comma_args_help<'a>(
|
||||
arena: &'a Bump,
|
||||
(spaces_before, (loc_val, spaces_after)): (
|
||||
&'a [CommentOrNewline<'a>],
|
||||
(Loc<TypeAnnotation<'a>>, &'a [CommentOrNewline<'a>]),
|
||||
),
|
||||
) -> Loc<TypeAnnotation<'a>> {
|
||||
if spaces_before.is_empty() {
|
||||
if spaces_after.is_empty() {
|
||||
loc_val
|
||||
} else {
|
||||
arena
|
||||
.alloc(loc_val.value)
|
||||
.with_spaces_after(spaces_after, loc_val.region)
|
||||
}
|
||||
} else if spaces_after.is_empty() {
|
||||
arena
|
||||
.alloc(loc_val.value)
|
||||
.with_spaces_before(spaces_before, loc_val.region)
|
||||
} else {
|
||||
let wrapped_expr = arena
|
||||
.alloc(loc_val.value)
|
||||
.with_spaces_after(spaces_after, loc_val.region);
|
||||
|
||||
arena
|
||||
.alloc(wrapped_expr.value)
|
||||
.with_spaces_before(spaces_before, wrapped_expr.region)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a basic type annotation that's a combination of variables
|
||||
/// (which are lowercase and unqualified, e.g. `a` in `List a`),
|
||||
/// type applications (which are uppercase and optionally qualified, e.g.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![no_main]
|
||||
use bumpalo::Bump;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use bumpalo::Bump;
|
||||
use test_syntax::test_helpers::Input;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
|
|
|
@ -102,12 +102,6 @@ fn round_trip_once(input: Input<'_>) -> Option<String> {
|
|||
return Some("Different ast".to_string());
|
||||
}
|
||||
|
||||
let reformatted = reparsed_ast.format();
|
||||
|
||||
if output != reformatted {
|
||||
return Some("Formatting not stable".to_string());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ impl<'a> Input<'a> {
|
|||
self.as_str(),
|
||||
output.as_ref().as_str(),
|
||||
actual,
|
||||
reparsed_ast
|
||||
reparsed_ast_normalized
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Expr(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(Type(TInParens(End(@78), @74), @72), @71), @69), @68), @66), @65), @61), @60), @58), @57), @53), @52), @50), @49), @47), @46), @44), @43), @41), @40), @39), @38), @36), @35), @31), @30), @28), @27), @23), @22), @20), @19), @17), @16), @11), @10), @8), @7), @3), @2), @2), @0)
|
|
@ -1 +0,0 @@
|
|||
.:(i,i,(i,(i,ii,(i,(i,(i,i,(i,(i,i,(i,(J(i,(i,(i,(i,(i,i,(i,(i,i,(i,(i,(i,(J[]
|
|
@ -1,2 +0,0 @@
|
|||
M : r
|
||||
h
|
|
@ -1,43 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-6,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "M",
|
||||
vars: [],
|
||||
},
|
||||
ann: @4-5 SpaceBefore(
|
||||
BoundVariable(
|
||||
"r",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@7-8 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "h",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
M:(
|
||||
r)
|
||||
h
|
|
@ -1,3 +0,0 @@
|
|||
A #
|
||||
p : e
|
||||
A
|
|
@ -1,48 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-7,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "A",
|
||||
vars: [
|
||||
@4-5 SpaceBefore(
|
||||
Identifier {
|
||||
ident: "p",
|
||||
},
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
},
|
||||
ann: @6-7 BoundVariable(
|
||||
"e",
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@8-9 SpaceBefore(
|
||||
Tag(
|
||||
"A",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
A#
|
||||
p:e
|
||||
A
|
|
@ -1,3 +0,0 @@
|
|||
K : #
|
||||
s
|
||||
K
|
|
@ -1,44 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-7,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "K",
|
||||
vars: [],
|
||||
},
|
||||
ann: @5-6 SpaceBefore(
|
||||
BoundVariable(
|
||||
"s",
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@8-9 SpaceBefore(
|
||||
Tag(
|
||||
"K",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
K:(#
|
||||
s)
|
||||
K
|
|
@ -1,4 +0,0 @@
|
|||
O : O z
|
||||
#
|
||||
|
||||
b #
|
|
@ -1,59 +0,0 @@
|
|||
SpaceAfter(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-9,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "O",
|
||||
vars: [],
|
||||
},
|
||||
ann: @2-9 Apply(
|
||||
"",
|
||||
"O",
|
||||
[
|
||||
@4-5 SpaceAfter(
|
||||
BoundVariable(
|
||||
"z",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@10-11 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "b",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
)
|
|
@ -1,4 +0,0 @@
|
|||
O:O(z
|
||||
#
|
||||
)
|
||||
b#
|
|
@ -1,2 +0,0 @@
|
|||
p
|
||||
! .p!!
|
|
@ -1,47 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-1,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Stmt(
|
||||
@0-1 Var {
|
||||
module_name: "",
|
||||
ident: "p",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
@2-8 SpaceBefore(
|
||||
UnaryOp(
|
||||
@4-7 SpaceBefore(
|
||||
TrySuffix {
|
||||
target: Task,
|
||||
expr: AccessorFunction(
|
||||
RecordField(
|
||||
"p!",
|
||||
),
|
||||
),
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
@2-3 Not,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
p
|
||||
!
|
||||
.p!!
|
|
@ -1,6 +0,0 @@
|
|||
r :
|
||||
r
|
||||
#
|
||||
#
|
||||
|
||||
h
|
|
@ -1,58 +0,0 @@
|
|||
SpaceAfter(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-11,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Identifier {
|
||||
ident: "r",
|
||||
},
|
||||
@4-5 SpaceBefore(
|
||||
SpaceAfter(
|
||||
BoundVariable(
|
||||
"r",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@12-13 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "h",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -1,6 +0,0 @@
|
|||
r:(
|
||||
r
|
||||
#
|
||||
#
|
||||
)
|
||||
h
|
|
@ -1,3 +0,0 @@
|
|||
{ l: s #
|
||||
} : s
|
||||
o
|
|
@ -1,51 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-9,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-7 RecordDestructure(
|
||||
[
|
||||
@1-6 SpaceAfter(
|
||||
RequiredField(
|
||||
"l",
|
||||
@5-6 Identifier {
|
||||
ident: "s",
|
||||
},
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
@8-9 BoundVariable(
|
||||
"s",
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@10-11 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "o",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
{l#
|
||||
:s}:s
|
||||
o
|
|
@ -1,4 +0,0 @@
|
|||
k : [
|
||||
T,
|
||||
]m #
|
||||
D
|
|
@ -1,58 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-9,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Identifier {
|
||||
ident: "k",
|
||||
},
|
||||
@3-9 SpaceBefore(
|
||||
TagUnion {
|
||||
ext: Some(
|
||||
@8-9 BoundVariable(
|
||||
"m",
|
||||
),
|
||||
),
|
||||
tags: Collection {
|
||||
items: [
|
||||
@4-5 Apply {
|
||||
name: @4-5 "T",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
final_comments: [
|
||||
Newline,
|
||||
],
|
||||
},
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@11-12 SpaceBefore(
|
||||
Tag(
|
||||
"D",
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,4 +0,0 @@
|
|||
k:
|
||||
[T,
|
||||
]m#
|
||||
D
|
|
@ -1,5 +0,0 @@
|
|||
1 : (
|
||||
f,
|
||||
(ww -> p),
|
||||
)e
|
||||
Mh
|
|
@ -1,61 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-13,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 NumLiteral(
|
||||
"1",
|
||||
),
|
||||
@2-13 Tuple {
|
||||
elems: [
|
||||
@3-4 SpaceAfter(
|
||||
BoundVariable(
|
||||
"f",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
@6-11 Function(
|
||||
[
|
||||
@6-8 BoundVariable(
|
||||
"ww",
|
||||
),
|
||||
],
|
||||
Pure,
|
||||
@10-11 BoundVariable(
|
||||
"p",
|
||||
),
|
||||
),
|
||||
],
|
||||
ext: Some(
|
||||
@12-13 BoundVariable(
|
||||
"e",
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
@14-16 SpaceBefore(
|
||||
Tag(
|
||||
"Mh",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
1:(f
|
||||
,ww->p)e
|
||||
Mh
|
|
@ -1,3 +0,0 @@
|
|||
E : B
|
||||
{} = B
|
||||
B
|
|
@ -1,50 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-8,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
AnnotatedBody {
|
||||
ann_pattern: Apply(
|
||||
@0-1 Tag(
|
||||
"E",
|
||||
),
|
||||
[],
|
||||
),
|
||||
ann_type: @2-3 Apply(
|
||||
"",
|
||||
"B",
|
||||
[],
|
||||
),
|
||||
lines_between: [
|
||||
Newline,
|
||||
],
|
||||
body_pattern: @4-6 RecordDestructure(
|
||||
[],
|
||||
),
|
||||
body_expr: @7-8 Tag(
|
||||
"B",
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
@9-10 SpaceBefore(
|
||||
Tag(
|
||||
"B",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
E:B
|
||||
{}=B
|
||||
B
|
|
@ -1,2 +0,0 @@
|
|||
A p : e
|
||||
A
|
|
@ -1,51 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-7,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "A",
|
||||
vars: [
|
||||
@3-4 SpaceBefore(
|
||||
Identifier {
|
||||
ident: "p",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
],
|
||||
},
|
||||
ann: @6-7 SpaceBefore(
|
||||
BoundVariable(
|
||||
"e",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@8-9 SpaceBefore(
|
||||
Tag(
|
||||
"A",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,4 +0,0 @@
|
|||
A
|
||||
p:
|
||||
e
|
||||
A
|
|
@ -1,3 +0,0 @@
|
|||
A e # g
|
||||
: A
|
||||
AA
|
|
@ -1,55 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-9,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "A",
|
||||
vars: [
|
||||
@3-4 SpaceAfter(
|
||||
SpaceBefore(
|
||||
Identifier {
|
||||
ident: "e",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
"g",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
},
|
||||
ann: @8-9 Apply(
|
||||
"",
|
||||
"A",
|
||||
[],
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@10-12 SpaceBefore(
|
||||
Tag(
|
||||
"AA",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,4 +0,0 @@
|
|||
A
|
||||
e#g
|
||||
:A
|
||||
AA
|
|
@ -1,5 +0,0 @@
|
|||
3 :
|
||||
( #
|
||||
)n
|
||||
-> n
|
||||
0
|
|
@ -1,56 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-10,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 NumLiteral(
|
||||
"3",
|
||||
),
|
||||
@2-10 Function(
|
||||
[
|
||||
@2-7 Tuple {
|
||||
elems: Collection {
|
||||
items: [],
|
||||
final_comments: [
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
},
|
||||
ext: Some(
|
||||
@6-7 BoundVariable(
|
||||
"n",
|
||||
),
|
||||
),
|
||||
},
|
||||
],
|
||||
Pure,
|
||||
@9-10 BoundVariable(
|
||||
"n",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@12-13 SpaceBefore(
|
||||
Num(
|
||||
"0",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
3:(#
|
||||
)n->n
|
||||
0
|
|
@ -1,4 +0,0 @@
|
|||
d : (
|
||||
J,
|
||||
)g
|
||||
2
|
|
@ -1,52 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-8,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Identifier {
|
||||
ident: "d",
|
||||
},
|
||||
@2-8 Tuple {
|
||||
elems: Collection {
|
||||
items: [
|
||||
@3-4 Apply(
|
||||
"",
|
||||
"J",
|
||||
[],
|
||||
),
|
||||
],
|
||||
final_comments: [
|
||||
Newline,
|
||||
],
|
||||
},
|
||||
ext: Some(
|
||||
@7-8 BoundVariable(
|
||||
"g",
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
@9-10 SpaceBefore(
|
||||
Num(
|
||||
"2",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
d:(J,
|
||||
)g
|
||||
2
|
|
@ -1,4 +0,0 @@
|
|||
p : (
|
||||
)(
|
||||
i)
|
||||
{}
|
|
@ -1,51 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-9,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Identifier {
|
||||
ident: "p",
|
||||
},
|
||||
@2-9 Tuple {
|
||||
elems: Collection {
|
||||
items: [],
|
||||
final_comments: [
|
||||
Newline,
|
||||
],
|
||||
},
|
||||
ext: Some(
|
||||
@7-8 SpaceBefore(
|
||||
BoundVariable(
|
||||
"i",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
@10-12 SpaceBefore(
|
||||
Record(
|
||||
[],
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,4 +0,0 @@
|
|||
p:(
|
||||
)(
|
||||
i)
|
||||
{}
|
|
@ -1,3 +0,0 @@
|
|||
Str.getUnsafe haystack haystackIndex
|
||||
==
|
||||
Str.getUnsafe needle needleIndex
|
|
@ -1,56 +0,0 @@
|
|||
SpaceAfter(
|
||||
BinOps(
|
||||
[
|
||||
(
|
||||
@0-36 SpaceAfter(
|
||||
Apply(
|
||||
@0-13 Var {
|
||||
module_name: "Str",
|
||||
ident: "getUnsafe",
|
||||
},
|
||||
[
|
||||
@14-22 Var {
|
||||
module_name: "",
|
||||
ident: "haystack",
|
||||
},
|
||||
@23-36 Var {
|
||||
module_name: "",
|
||||
ident: "haystackIndex",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
@37-39 Equals,
|
||||
),
|
||||
],
|
||||
@40-72 Apply(
|
||||
@40-53 SpaceBefore(
|
||||
Var {
|
||||
module_name: "Str",
|
||||
ident: "getUnsafe",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
[
|
||||
@54-60 Var {
|
||||
module_name: "",
|
||||
ident: "needle",
|
||||
},
|
||||
@61-72 Var {
|
||||
module_name: "",
|
||||
ident: "needleIndex",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
Str.getUnsafe haystack haystackIndex
|
||||
==
|
||||
Str.getUnsafe needle needleIndex
|
|
@ -1,2 +0,0 @@
|
|||
i < 2
|
||||
-6
|
|
@ -1,51 +0,0 @@
|
|||
SpaceAfter(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-3,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Stmt(
|
||||
@0-3 BinOps(
|
||||
[
|
||||
(
|
||||
@0-1 Var {
|
||||
module_name: "",
|
||||
ident: "i",
|
||||
},
|
||||
@1-2 LessThan,
|
||||
),
|
||||
],
|
||||
@2-3 Num(
|
||||
"2",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@4-8 SpaceBefore(
|
||||
ParensAround(
|
||||
Num(
|
||||
"-6",
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -1,2 +0,0 @@
|
|||
i<2
|
||||
(-6)
|
|
@ -1,2 +0,0 @@
|
|||
foo
|
||||
|> Dict.keepIf \(k, _v) -> List.contains keysToDelete k |> Bool.not
|
|
@ -1,72 +0,0 @@
|
|||
SpaceAfter(
|
||||
BinOps(
|
||||
[
|
||||
(
|
||||
@0-3 SpaceAfter(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "foo",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
@4-6 Pizza,
|
||||
),
|
||||
],
|
||||
@7-71 Apply(
|
||||
@7-18 Var {
|
||||
module_name: "Dict",
|
||||
ident: "keepIf",
|
||||
},
|
||||
[
|
||||
@19-71 Closure(
|
||||
[
|
||||
@20-27 Tuple(
|
||||
[
|
||||
@21-22 Identifier {
|
||||
ident: "k",
|
||||
},
|
||||
@24-26 Underscore(
|
||||
"v",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
@31-71 BinOps(
|
||||
[
|
||||
(
|
||||
@31-59 Apply(
|
||||
@31-44 Var {
|
||||
module_name: "List",
|
||||
ident: "contains",
|
||||
},
|
||||
[
|
||||
@45-57 Var {
|
||||
module_name: "",
|
||||
ident: "keysToDelete",
|
||||
},
|
||||
@58-59 Var {
|
||||
module_name: "",
|
||||
ident: "k",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@60-62 Pizza,
|
||||
),
|
||||
],
|
||||
@63-71 Var {
|
||||
module_name: "Bool",
|
||||
ident: "not",
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -1,2 +0,0 @@
|
|||
foo
|
||||
|> Dict.keepIf \(k, _v) -> List.contains keysToDelete k |> Bool.not
|
|
@ -1,5 +0,0 @@
|
|||
a :
|
||||
N {
|
||||
h,
|
||||
}
|
||||
g
|
|
@ -1,58 +0,0 @@
|
|||
SpaceAfter(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-8,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-1 Identifier {
|
||||
ident: "a",
|
||||
},
|
||||
@2-8 Apply(
|
||||
"",
|
||||
"N",
|
||||
[
|
||||
@3-8 Record {
|
||||
fields: Collection {
|
||||
items: [
|
||||
@4-5 LabelOnly(
|
||||
@4-5 "h",
|
||||
),
|
||||
],
|
||||
final_comments: [
|
||||
Newline,
|
||||
],
|
||||
},
|
||||
ext: None,
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@9-10 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "g",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
a:N{h,
|
||||
}
|
||||
g
|
|
@ -1,4 +0,0 @@
|
|||
ex <- f #
|
||||
s # q
|
||||
<- f #
|
||||
s
|
|
@ -1,52 +0,0 @@
|
|||
SpaceBefore(
|
||||
Backpassing(
|
||||
[
|
||||
@1-3 Identifier {
|
||||
ident: "ex",
|
||||
},
|
||||
],
|
||||
@5-6 Var {
|
||||
module_name: "",
|
||||
ident: "f",
|
||||
},
|
||||
@8-18 SpaceBefore(
|
||||
Backpassing(
|
||||
[
|
||||
@8-9 SpaceAfter(
|
||||
Identifier {
|
||||
ident: "s",
|
||||
},
|
||||
[
|
||||
LineComment(
|
||||
"q",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
@14-15 Var {
|
||||
module_name: "",
|
||||
ident: "f",
|
||||
},
|
||||
@17-18 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "s",
|
||||
},
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
LineComment(
|
||||
"",
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
ex<-f#
|
||||
s#q
|
||||
<-f#
|
||||
s
|
|
@ -1,3 +0,0 @@
|
|||
0
|
||||
! .d
|
||||
.d
|
|
@ -1,56 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
EitherIndex(2147483649),
|
||||
],
|
||||
regions: [
|
||||
@0-1,
|
||||
@2-6,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 1 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 1, length: 0 },
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Stmt(
|
||||
@0-1 Num(
|
||||
"0",
|
||||
),
|
||||
),
|
||||
Stmt(
|
||||
@2-6 UnaryOp(
|
||||
@4-6 SpaceBefore(
|
||||
AccessorFunction(
|
||||
RecordField(
|
||||
"d",
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
@2-3 Not,
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@7-9 SpaceBefore(
|
||||
AccessorFunction(
|
||||
RecordField(
|
||||
"d",
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,4 +0,0 @@
|
|||
0
|
||||
!
|
||||
.d
|
||||
.d
|
|
@ -1 +0,0 @@
|
|||
N < l (r * N)
|
|
@ -1,40 +0,0 @@
|
|||
SpaceAfter(
|
||||
BinOps(
|
||||
[
|
||||
(
|
||||
@0-1 Tag(
|
||||
"N",
|
||||
),
|
||||
@1-2 LessThan,
|
||||
),
|
||||
],
|
||||
@2-7 Apply(
|
||||
@2-3 Var {
|
||||
module_name: "",
|
||||
ident: "l",
|
||||
},
|
||||
[
|
||||
@4-7 ParensAround(
|
||||
BinOps(
|
||||
[
|
||||
(
|
||||
@4-5 Var {
|
||||
module_name: "",
|
||||
ident: "r",
|
||||
},
|
||||
@5-6 Star,
|
||||
),
|
||||
],
|
||||
@6-7 Tag(
|
||||
"N",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -1 +0,0 @@
|
|||
N<l(r*N)
|
|
@ -1,8 +0,0 @@
|
|||
5
|
||||
- (
|
||||
(
|
||||
e =
|
||||
r
|
||||
1
|
||||
)
|
||||
)
|
|
@ -1,60 +0,0 @@
|
|||
BinOps(
|
||||
[
|
||||
(
|
||||
@0-1 Num(
|
||||
"5",
|
||||
),
|
||||
@1-2 Minus,
|
||||
),
|
||||
],
|
||||
@3-15 ParensAround(
|
||||
ParensAround(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@4-12,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@4-5 Identifier {
|
||||
ident: "e",
|
||||
},
|
||||
@6-12 ParensAround(
|
||||
ParensAround(
|
||||
SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "r",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@13-14 SpaceBefore(
|
||||
Num(
|
||||
"1",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
5-((e=((
|
||||
r))
|
||||
1))
|
|
@ -1,2 +0,0 @@
|
|||
"$(g)" : q
|
||||
f
|
|
@ -1,51 +0,0 @@
|
|||
SpaceAfter(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-12,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Annotation(
|
||||
@0-10 StrLiteral(
|
||||
Line(
|
||||
[
|
||||
Interpolated(
|
||||
@5-6 Var {
|
||||
module_name: "",
|
||||
ident: "g",
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@11-12 BoundVariable(
|
||||
"q",
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@13-14 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "f",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -1,2 +0,0 @@
|
|||
"""$(g)""":q
|
||||
f
|
|
@ -1,6 +0,0 @@
|
|||
t =
|
||||
"""
|
||||
"
|
||||
"""
|
||||
""
|
||||
S
|
|
@ -1,48 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-12,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@0-1 Identifier {
|
||||
ident: "t",
|
||||
},
|
||||
@2-12 Apply(
|
||||
@2-10 Str(
|
||||
PlainLine(
|
||||
"\" ",
|
||||
),
|
||||
),
|
||||
[
|
||||
@10-12 Str(
|
||||
PlainLine(
|
||||
"",
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@13-14 SpaceBefore(
|
||||
Tag(
|
||||
"S",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,2 +0,0 @@
|
|||
t="""" """""
|
||||
S
|
|
@ -1,3 +0,0 @@
|
|||
a =
|
||||
6
|
||||
a
|
|
@ -1,44 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-6,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@0-1 Identifier {
|
||||
ident: "a",
|
||||
},
|
||||
@2-6 ParensAround(
|
||||
SpaceBefore(
|
||||
Num(
|
||||
"6",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@7-8 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "a",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
a=(
|
||||
6)
|
||||
a
|
|
@ -1,2 +0,0 @@
|
|||
m0 \w -> w? e
|
||||
/ s
|
|
@ -1,48 +0,0 @@
|
|||
BinOps(
|
||||
[
|
||||
(
|
||||
@0-9 SpaceAfter(
|
||||
Apply(
|
||||
@0-2 Var {
|
||||
module_name: "",
|
||||
ident: "m0",
|
||||
},
|
||||
[
|
||||
@2-9 Closure(
|
||||
[
|
||||
@3-4 Identifier {
|
||||
ident: "w",
|
||||
},
|
||||
],
|
||||
@6-9 Apply(
|
||||
@6-7 TrySuffix {
|
||||
target: Result,
|
||||
expr: Var {
|
||||
module_name: "",
|
||||
ident: "w",
|
||||
},
|
||||
},
|
||||
[
|
||||
@8-9 Var {
|
||||
module_name: "",
|
||||
ident: "e",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
@10-11 Slash,
|
||||
),
|
||||
],
|
||||
@11-12 Var {
|
||||
module_name: "",
|
||||
ident: "s",
|
||||
},
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue