diff --git a/Cargo.lock b/Cargo.lock index e4d0918599..ff10f73565 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2559,6 +2559,7 @@ dependencies = [ "roc_module", "roc_parse", "roc_region", + "soa", ] [[package]] diff --git a/crates/compiler/can/src/desugar.rs b/crates/compiler/can/src/desugar.rs index 84d99bdc09..2c4bf6e7d8 100644 --- a/crates/compiler/can/src/desugar.rs +++ b/crates/compiler/can/src/desugar.rs @@ -1104,10 +1104,21 @@ pub fn desugar_expr<'a>( // Allow naked dbg, necessary for piping values into dbg with the `Pizza` binop loc_expr } - DbgStmt(condition, continuation) => { + DbgStmt { + first: condition, + extra_args, + 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, diff --git a/crates/compiler/can/src/expr.rs b/crates/compiler/can/src/expr.rs index 8a12083f78..952f15b5b4 100644 --- a/crates/compiler/can/src/expr.rs +++ b/crates/compiler/can/src/expr.rs @@ -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(_, _) diff --git a/crates/compiler/fmt/Cargo.toml b/crates/compiler/fmt/Cargo.toml index cc12215785..ca27ce3373 100644 --- a/crates/compiler/fmt/Cargo.toml +++ b/crates/compiler/fmt/Cargo.toml @@ -15,3 +15,4 @@ roc_region.workspace = true roc_error_macros.workspace = true bumpalo.workspace = true +soa.workspace = true diff --git a/crates/compiler/fmt/src/annotation.rs b/crates/compiler/fmt/src/annotation.rs index 3bf76938ca..b95552009f 100644 --- a/crates/compiler/fmt/src/annotation.rs +++ b/crates/compiler/fmt/src/annotation.rs @@ -1,11 +1,14 @@ 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, Expr, ExtractSpaces, FunctionArrow, - ImplementsAbilities, ImplementsAbility, ImplementsClause, Tag, TypeAnnotation, TypeHeader, + AbilityImpls, AssignedField, Collection, CommentOrNewline, Expr, ExtractSpaces, FunctionArrow, + ImplementsAbilities, ImplementsAbility, ImplementsClause, Spaceable, Spaces, SpacesAfter, + SpacesBefore, Tag, TypeAnnotation, TypeHeader, }; use roc_parse::ident::UppercaseIdent; use roc_region::all::Loc; @@ -35,6 +38,7 @@ use roc_region::all::Loc; #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum Parens { NotNeeded, + InCollection, InFunctionType, InApply, InOperator, @@ -148,7 +152,10 @@ impl<'a> Formattable for TypeAnnotation<'a> { true } - Wildcard | Inferred | BoundVariable(_) | Malformed(_) => false, + TypeAnnotation::Wildcard + | TypeAnnotation::Inferred + | BoundVariable(_) + | Malformed(_) => false, Function(args, _arrow, result) => { result.value.is_multiline() || args.iter().any(|loc_arg| loc_arg.value.is_multiline()) @@ -165,8 +172,7 @@ impl<'a> Formattable for TypeAnnotation<'a> { Some(ann) if ann.value.is_multiline() => return true, _ => {} } - - fields.items.iter().any(|field| field.value.is_multiline()) + is_collection_multiline(fields) } Record { fields, ext } => { @@ -175,7 +181,7 @@ impl<'a> Formattable for TypeAnnotation<'a> { _ => {} } - fields.items.iter().any(|field| field.value.is_multiline()) + is_collection_multiline(fields) } TagUnion { tags, ext } => { @@ -184,221 +190,333 @@ impl<'a> Formattable for TypeAnnotation<'a> { _ => {} } - tags.iter().any(|tag| tag.value.is_multiline()) + !tags.final_comments().is_empty() || tags.iter().any(|tag| tag.value.is_multiline()) } } } fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) { - use roc_parse::ast::TypeAnnotation::*; + fmt_ty_ann(self, buf, indent, parens, newlines, false); + } +} - let self_is_multiline = self.is_multiline(); +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); - match self { - Function(args, arrow, ret) => { - let needs_parens = parens != Parens::NotNeeded; + let self_is_multiline = me.item.is_multiline(); - buf.indent(indent); + 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(); + } - if needs_parens { - buf.push('(') - } + match &me.item { + TypeAnnotation::SpaceBefore(_ann, _spaces) | TypeAnnotation::SpaceAfter(_ann, _spaces) => { + unreachable!() + } + TypeAnnotation::Function(args, arrow, ret) => { + let needs_parens = parens != Parens::NotNeeded; - let mut it = args.iter().enumerate().peekable(); + buf.indent(indent); - while let Some((index, argument)) = it.next() { - let is_first = index == 0; - let is_multiline = &argument.value.is_multiline(); - - if !is_first && !is_multiline && self_is_multiline { - buf.newline(); - } - - 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); - } - } - } - - 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(')') - } + if needs_parens { + buf.push('(') } - Apply(pkg, name, arguments) => { - buf.indent(indent); - let write_parens = parens == Parens::InApply && !arguments.is_empty(); - if write_parens { - buf.push('(') - } + for (index, argument) in args.iter().enumerate() { + let is_first = index == 0; - 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 { + if !is_first { + buf.push_str(","); + if !self_is_multiline { buf.spaces(1); - arg.format_with_options(buf, Parens::InApply, Newlines::No, arg_indent); } } - if write_parens { - buf.push(')') - } + let newline_at_top = !is_first && self_is_multiline; + + fmt_ty_ann( + &argument.value, + buf, + indent, + Parens::InFunctionType, + Newlines::Yes, + newline_at_top, + ); } - BoundVariable(v) => { + + if self_is_multiline { + buf.newline(); 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); + } else { 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); - } } - 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); + 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); } 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); + arg.format_with_options(buf, Parens::InApply, Newlines::No, arg_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) + if write_parens { + buf.push(')') } - SpaceAfter(ann, spaces) => { - ann.format_with_options(buf, parens, newlines, indent); - fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent); + } + 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); } - Malformed(raw) => { + } + + TypeAnnotation::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); - buf.push_str(raw) + } 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); + } + } + 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 fmt_ty_collection( + buf: &mut Buf<'_>, + indent: u16, + braces: Braces, + items: Collection<'_, Loc>>, + 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>>, 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 is_outdentable(ann: &TypeAnnotation) -> bool { - matches!( - ann.extract_spaces().item, - TypeAnnotation::Tuple { .. } | TypeAnnotation::Record { .. } - ) +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: @@ -466,6 +584,7 @@ fn format_assigned_field_help( } buf.spaces(separator_spaces); + buf.indent(indent); buf.push(':'); buf.spaces(1); ann.value.format(buf, indent); @@ -483,6 +602,7 @@ fn format_assigned_field_help( } buf.spaces(separator_spaces); + buf.indent(indent); buf.push('?'); buf.spaces(1); ann.value.format(buf, indent); @@ -704,3 +824,279 @@ pub fn except_last(items: &[T]) -> impl Iterator { 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); + } +} diff --git a/crates/compiler/fmt/src/collection.rs b/crates/compiler/fmt/src/collection.rs index ac58bbe6bc..65366f6ec6 100644 --- a/crates/compiler/fmt/src/collection.rs +++ b/crates/compiler/fmt/src/collection.rs @@ -1,11 +1,13 @@ -use roc_parse::ast::{Collection, CommentOrNewline, ExtractSpaces}; +use roc_parse::{ + ast::{Collection, CommentOrNewline, ExtractSpaces}, + expr::merge_spaces, +}; 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, @@ -13,26 +15,35 @@ pub enum Braces { Curly, } -pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>( +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>( buf: &mut Buf<'buf>, indent: u16, braces: Braces, items: Collection<'a, T>, newline: Newlines, ) where - >::Item: Formattable, + >::Item: Formattable + std::fmt::Debug, { - let start = match braces { - Braces::Round => '(', - Braces::Curly => '{', - Braces::Square => '[', - }; - - let end = match braces { - Braces::Round => ')', - Braces::Curly => '}', - Braces::Square => ']', - }; + let start = braces.start(); + let end = braces.end(); if is_collection_multiline(&items) { let braces_indent = indent; @@ -43,10 +54,21 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>( 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(); @@ -64,13 +86,14 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>( 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.newline(); + buf.ensure_ends_with_blank_line(); } } @@ -91,32 +114,30 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>( buf.indent(item_indent); buf.push(','); - if !item.after.is_empty() { - if item.after.iter().any(|s| s.is_newline()) { - buf.newline(); - } + last_after = item.after; + } - 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(); + } - if items - .final_comments() - .starts_with(&[CommentOrNewline::Newline, CommentOrNewline::Newline]) + items.final_comments() + }; + + if has_comments(final_comments) + && final_comments.starts_with(&[CommentOrNewline::Newline, CommentOrNewline::Newline]) { - buf.newline(); + buf.ensure_ends_with_blank_line(); } - fmt_comments_only( - buf, - items.final_comments().iter(), - NewlineAt::None, - item_indent, - ); + fmt_comments_only(buf, final_comments.iter(), NewlineAt::None, item_indent); buf.ensure_ends_with_newline(); buf.indent(braces_indent); @@ -144,3 +165,13 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>( buf.push(end); } + +fn has_comments(spaces: &[CommentOrNewline<'_>]) -> bool { + for space in spaces { + match space { + CommentOrNewline::Newline => {} + CommentOrNewline::LineComment(_) | CommentOrNewline::DocComment(_) => return true, + } + } + false +} diff --git a/crates/compiler/fmt/src/def.rs b/crates/compiler/fmt/src/def.rs index 1c5e2da889..0eb782504e 100644 --- a/crates/compiler/fmt/src/def.rs +++ b/crates/compiler/fmt/src/def.rs @@ -1,15 +1,27 @@ -use crate::annotation::{is_collection_multiline, Formattable, Newlines, Parens}; +use crate::annotation::{ + ann_lift_spaces, ann_lift_spaces_after, is_collection_multiline, ty_is_outdentable, + Formattable, Newlines, Parens, +}; use crate::collection::{fmt_collection, Braces}; -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::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::Buf; +use bumpalo::Bump; use roc_error_macros::internal_error; use roc_parse::ast::{ - AbilityMember, Defs, Expr, ExtractSpaces, ImportAlias, ImportAsKeyword, ImportExposingKeyword, - ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport, - ModuleImportParams, Pattern, Spaces, StrLiteral, TypeAnnotation, TypeDef, TypeHeader, ValueDef, + AbilityMember, CommentOrNewline, Defs, Expr, ExtractSpaces, ImportAlias, ImportAsKeyword, + ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, + ModuleImport, ModuleImportParams, Pattern, Spaceable, Spaces, SpacesAfter, SpacesBefore, + StrLiteral, TypeAnnotation, TypeDef, TypeHeader, ValueDef, }; +use roc_parse::expr::merge_spaces; use roc_parse::header::Keyword; use roc_region::all::Loc; @@ -28,18 +40,24 @@ 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 { + match def.item { Ok(type_def) => type_def.format(buf, indent), Err(value_def) => value_def.format(buf, indent), } @@ -51,6 +69,339 @@ 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, 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, >::Item> +where + >::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::*; @@ -66,34 +417,23 @@ impl<'a> Formattable for TypeDef<'a> { use roc_parse::ast::TypeDef::*; match self { - Alias { - header: TypeHeader { name, vars }, - ann, - } => { + Alias { header, ann } => { + header.format(buf, indent); + 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); - ann.format(buf, indent) + 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); } Opaque { header, @@ -127,17 +467,11 @@ impl<'a> Formattable for TypeDef<'a> { } } Ability { - header: TypeHeader { name, vars }, + header, loc_implements: _, members, } => { - 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); - } + header.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent); buf.spaces(1); buf.push_str(roc_parse::keyword::IMPLEMENTS); @@ -180,10 +514,62 @@ 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() { - buf.spaces(1); - fmt_pattern(buf, &var.value, indent, Parens::NotNeeded); - buf.indent(indent); + 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); + } } } } @@ -441,7 +827,7 @@ impl<'a> Formattable for ValueDef<'a> { ); } Body(loc_pattern, loc_expr) => { - fmt_body(buf, &loc_pattern.value, &loc_expr.value, indent); + fmt_body(buf, true, &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), @@ -457,7 +843,7 @@ impl<'a> Formattable for ValueDef<'a> { fmt_annotated_body_comment(buf, indent, lines_between); buf.newline(); - fmt_body(buf, &body_pattern.value, &body_expr.value, indent); + fmt_body(buf, false, &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), @@ -483,20 +869,25 @@ fn fmt_general_def( buf.push_str(sep); buf.spaces(1); - let should_outdent = should_outdent(rhs); + let rhs_lifted = ann_lift_spaces(buf.text.bump(), rhs); - 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); - } - } + 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); } else { - rhs.format_with_options(buf, Parens::NotNeeded, newlines, indent + INDENT); + 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); } + fmt_comments_only(buf, rhs_lifted.after.iter(), NewlineAt::Bottom, indent); } else { buf.spaces(1); buf.push_str(sep); @@ -505,28 +896,6 @@ fn fmt_general_def( } } -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>, _: bool, indent: u16) { buf.ensure_ends_with_newline(); buf.indent(indent); @@ -608,21 +977,36 @@ pub fn fmt_annotated_body_comment<'a>( } } -pub fn fmt_body<'a>(buf: &mut Buf, pattern: &'a Pattern<'a>, body: &'a Expr<'a>, indent: u16) { +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(); // Check if this is an assignment into the unit value - let is_unit_assignment = if let Pattern::RecordDestructure(collection) = pattern { - collection.is_empty() + 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()) } else { false }; // Don't format the `{} =` for defs with this pattern - if !is_unit_assignment { - pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent); - buf.indent(indent); - buf.push_str(" ="); + if is_unit_assignment { + return body.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent); } + 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) => { @@ -634,7 +1018,10 @@ pub fn fmt_body<'a>(buf: &mut Buf, pattern: &'a Pattern<'a>, body: &'a Expr<'a>, _ => false, }; - if should_outdent { + 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 { buf.spaces(1); sub_def.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent); } else { @@ -646,6 +1033,32 @@ pub fn fmt_body<'a>(buf: &mut Buf, pattern: &'a Pattern<'a>, body: &'a Expr<'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: // @@ -662,9 +1075,15 @@ pub fn fmt_body<'a>(buf: &mut Buf, pattern: &'a Pattern<'a>, body: &'a Expr<'a>, buf.newline(); body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT); } - Expr::When(..) | Expr::Str(StrLiteral::Block(_)) => { - buf.ensure_ends_with_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); } _ => { buf.spaces(1); @@ -677,6 +1096,18 @@ pub fn fmt_body<'a>(buf: &mut Buf, pattern: &'a Pattern<'a>, body: &'a Expr<'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() diff --git a/crates/compiler/fmt/src/expr.rs b/crates/compiler/fmt/src/expr.rs index d4a2a999b8..6809f26386 100644 --- a/crates/compiler/fmt/src/expr.rs +++ b/crates/compiler/fmt/src/expr.rs @@ -1,176 +1,49 @@ use crate::annotation::{except_last, is_collection_multiline, Formattable, Newlines, Parens}; use crate::collection::{fmt_collection, Braces}; -use crate::def::fmt_defs; -use crate::pattern::fmt_pattern; +use crate::def::{fmt_defs, valdef_lift_spaces_before}; +use crate::pattern::{fmt_pattern, pattern_lift_spaces, starts_with_inline_comment}; use crate::spaces::{ count_leading_newlines, fmt_comments_only, fmt_spaces, fmt_spaces_no_blank_lines, NewlineAt, INDENT, }; use crate::Buf; -use roc_module::called_via::{self, BinOp}; +use bumpalo::collections::Vec; +use bumpalo::Bump; +use roc_module::called_via::{self, BinOp, UnaryOp}; use roc_parse::ast::{ - is_expr_suffixed, AssignedField, Base, Collection, CommentOrNewline, Expr, ExtractSpaces, - Pattern, TryTarget, WhenBranch, + AssignedField, Base, Collection, CommentOrNewline, Expr, ExtractSpaces, Pattern, Spaceable, + Spaces, SpacesAfter, SpacesBefore, TryTarget, WhenBranch, }; use roc_parse::ast::{StrLiteral, StrSegment}; +use roc_parse::expr::merge_spaces; use roc_parse::ident::Accessor; use roc_parse::keyword; use roc_region::all::Loc; +use soa::Slice; impl<'a> Formattable for Expr<'a> { fn is_multiline(&self) -> bool { - use roc_parse::ast::Expr::*; // TODO cache these answers using a Map, so // we don't have to traverse subexpressions repeatedly - - match self { - // Return whether these spaces contain any Newlines - SpaceBefore(_sub_expr, spaces) | SpaceAfter(_sub_expr, spaces) => { - debug_assert!(!spaces.is_empty()); - - // "spaces" always contain either a newline or comment, and comments have newlines - true - } - - MalformedSuffixed(loc_expr) => loc_expr.is_multiline(), - - // These expressions never have newlines - Float(..) - | Num(..) - | NonBase10Int { .. } - | SingleQuote(_) - | AccessorFunction(_) - | RecordUpdater(_) - | Var { .. } - | Underscore { .. } - | MalformedIdent(_, _) - | Tag(_) - | OpaqueRef(_) - | Crash - | Dbg - | Try => false, - - RecordAccess(inner, _) | TupleAccess(inner, _) | TrySuffix { expr: inner, .. } => { - inner.is_multiline() - } - - // These expressions always have newlines - Defs(_, _) | When(_, _) => true, - - List(items) => is_collection_multiline(items), - - Str(literal) => is_str_multiline(literal), - Apply(loc_expr, args, _) => { - loc_expr.is_multiline() || args.iter().any(|loc_arg| loc_arg.is_multiline()) - } - - DbgStmt(condition, _) => condition.is_multiline(), - LowLevelDbg(_, _, _) => unreachable!( - "LowLevelDbg should only exist after desugaring, not during formatting" - ), - Return(_return_value, _after_return) => true, - - If { - if_thens: branches, - final_else, - .. - } => { - final_else.is_multiline() - || branches - .iter() - .any(|(c, t)| c.is_multiline() || t.is_multiline()) - } - - BinOps(lefts, loc_right) => { - lefts.iter().any(|(loc_expr, _)| loc_expr.is_multiline()) - || loc_right.is_multiline() - } - - UnaryOp(loc_subexpr, _) - | PrecedenceConflict(roc_parse::ast::PrecedenceConflict { - expr: loc_subexpr, .. - }) - | EmptyRecordBuilder(loc_subexpr) - | SingleFieldRecordBuilder(loc_subexpr) - | OptionalFieldInRecordBuilder(_, loc_subexpr) => loc_subexpr.is_multiline(), - - ParensAround(subexpr) => subexpr.is_multiline(), - - Closure(loc_patterns, loc_body) => { - // check the body first because it's more likely to be multiline - loc_body.is_multiline() - || loc_patterns - .iter() - .any(|loc_pattern| loc_pattern.is_multiline()) - } - Backpassing(loc_patterns, loc_body, loc_ret) => { - // check the body first because it's more likely to be multiline - loc_body.is_multiline() - || loc_ret.is_multiline() - || loc_patterns - .iter() - .any(|loc_pattern| loc_pattern.is_multiline()) - } - - Record(fields) => is_collection_multiline(fields), - Tuple(fields) => is_collection_multiline(fields), - RecordUpdate { fields, .. } => is_collection_multiline(fields), - RecordBuilder { fields, .. } => is_collection_multiline(fields), - } + expr_is_multiline(self, false) } fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) { use self::Expr::*; - let apply_needs_parens = parens == Parens::InApply; + let me = expr_lift_spaces(parens, buf.text.bump(), self); - match self { - SpaceBefore(sub_expr, spaces) => { - format_spaces(buf, spaces, newlines, indent); - sub_expr.format_with_options(buf, parens, newlines, indent); - } - SpaceAfter(sub_expr, spaces) => { - sub_expr.format_with_options(buf, parens, newlines, indent); - format_spaces(buf, spaces, newlines, indent); - } + if !me.before.is_empty() { + format_spaces(buf, me.before, newlines, indent); + } + + match &me.item { + SpaceBefore(_sub_expr, _spaces) | SpaceAfter(_sub_expr, _spaces) => unreachable!(), ParensAround(sub_expr) => { if parens == Parens::NotNeeded && !sub_expr_requests_parens(sub_expr) { sub_expr.format_with_options(buf, Parens::NotNeeded, newlines, indent); } else { - let should_add_newlines = match sub_expr { - Expr::Closure(..) - | Expr::SpaceBefore(..) - | Expr::SpaceAfter(Closure(..), ..) => false, - _ => sub_expr.is_multiline(), - }; - - buf.indent(indent); - buf.push('('); - if should_add_newlines { - buf.newline(); - } - - let next_indent = if starts_with_newline(sub_expr) || should_add_newlines { - match sub_expr { - Expr::Closure(..) | Expr::SpaceAfter(Closure(..), ..) => indent, - _ => indent + INDENT, - } - } else { - indent - }; - - sub_expr.format_with_options( - buf, - Parens::NotNeeded, - Newlines::Yes, - next_indent, - ); - - if !matches!(sub_expr, Expr::SpaceAfter(..)) && should_add_newlines { - buf.newline(); - } - buf.indent(indent); - buf.push(')'); + fmt_parens(sub_expr, buf, indent); } } Str(literal) => { @@ -199,129 +72,12 @@ impl<'a> Formattable for Expr<'a> { buf.push_str("try"); } Apply(loc_expr, loc_args, _) => { - // Sadly this assertion fails in practice. The fact that the parser produces code like this is going to - // confuse the formatter, because it depends on being able to "see" spaces that logically come before the inner - // expr in several places - which is necessarily the case when the `loc_expr` of the apply itself has - // SpaceBefore. - // - // TODO: enforce in the type system that spaces must be pushed to the "outside". - // In other words, Expr::Apply should look something like the following, and there shouldn't be Expr::SpaceBefore and ::SpaceAfter. - // - // ``` - // Apply(&'a SpaceAfter>>, &'a [&'a SpaceBefore>>], CalledVia), - // ``` - // - // assert!(loc_expr.extract_spaces().before.is_empty(), "{:#?}", self); + let apply_needs_parens = parens == Parens::InApply; - buf.indent(indent); if apply_needs_parens && !loc_args.is_empty() { - buf.push('('); - } - - // should_reflow_outdentable, aka should we transform this: - // - // ``` - // foo bar - // [ - // 1, - // 2, - // ] - // ``` - // - // Into this: - // - // ``` - // foo bar [ - // 1, - // 2, - // ] - // ``` - let should_reflow_outdentable = loc_expr.extract_spaces().after.is_empty() - && except_last(loc_args).all(|a| !a.is_multiline()) - && loc_args - .last() - .map(|a| { - a.extract_spaces().item.is_multiline() - && matches!( - a.value.extract_spaces().item, - Expr::Tuple(_) | Expr::List(_) | Expr::Record(_) - ) - && a.extract_spaces().before == [CommentOrNewline::Newline] - }) - .unwrap_or_default(); - - let needs_indent = !should_reflow_outdentable - && (!loc_expr.extract_spaces().after.is_empty() - || except_last(loc_args).any(|a| a.is_multiline()) - || loc_args - .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 + fmt_parens(self, buf, indent); } else { - indent - }; - - let expr_needs_parens = - matches!(loc_expr.value.extract_spaces().item, Expr::Closure(..)) - && !loc_args.is_empty(); - - if expr_needs_parens { - buf.push('('); - } - - loc_expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent); - - if expr_needs_parens { - buf.indent(indent); - buf.push(')'); - } - - for loc_arg in loc_args.iter() { - if should_reflow_outdentable { - buf.spaces(1); - - // Ignore any comments+newlines before/after. - // We checked above that there's only a single newline before the last arg, - // which we're intentionally ignoring. - - let arg = loc_arg.extract_spaces(); - arg.item.format_with_options( - buf, - Parens::InApply, - Newlines::Yes, - arg_indent, - ); - } else if needs_indent { - let arg = loc_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); - loc_arg.format_with_options( - buf, - Parens::InApply, - Newlines::Yes, - arg_indent, - ); - } - } - - if apply_needs_parens && !loc_args.is_empty() { - buf.push(')'); + fmt_apply(loc_expr, loc_args, indent, buf); } } &Num(string) => { @@ -396,16 +152,11 @@ impl<'a> Formattable for Expr<'a> { fmt_backpassing(buf, loc_patterns, loc_body, loc_ret, indent); } Defs(defs, ret) => { - { - let indent = if parens == Parens::InOperator { - buf.indent(indent); - buf.push('('); - buf.newline(); - indent + INDENT - } else { - indent - }; + let defs_needs_parens = parens == Parens::InOperator || parens == Parens::InApply; + if defs_needs_parens { + fmt_parens(self, buf, indent) + } else { // It should theoretically be impossible to *parse* an empty defs list. // (Canonicalization can remove defs later, but that hasn't happened yet!) debug_assert!(!defs.is_empty()); @@ -435,19 +186,17 @@ impl<'a> Formattable for Expr<'a> { } } } - - if parens == Parens::InOperator { - buf.ensure_ends_with_newline(); - buf.indent(indent); - buf.push(')'); - } } Dbg => { buf.indent(indent); buf.push_str("dbg"); } - DbgStmt(condition, continuation) => { - fmt_dbg_stmt(buf, condition, continuation, parens, indent); + DbgStmt { + first, + extra_args, + continuation, + } => { + fmt_dbg_stmt(buf, first, extra_args, continuation, parens, indent); } LowLevelDbg(_, _, _) => unreachable!( "LowLevelDbg should only exist after desugaring, not during formatting" @@ -470,9 +219,9 @@ impl<'a> Formattable for Expr<'a> { ); } When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, indent), - Tuple(items) => fmt_collection(buf, indent, Braces::Round, *items, Newlines::No), - List(items) => fmt_collection(buf, indent, Braces::Square, *items, Newlines::No), - BinOps(lefts, right) => fmt_binops(buf, lefts, right, false, indent), + Tuple(items) => fmt_expr_collection(buf, indent, Braces::Round, *items, Newlines::No), + List(items) => fmt_expr_collection(buf, indent, Braces::Square, *items, Newlines::No), + BinOps(lefts, right) => fmt_binops(buf, lefts, right, indent), UnaryOp(sub_expr, unary_op) => { buf.indent(indent); match &unary_op.value { @@ -484,30 +233,58 @@ impl<'a> Formattable for Expr<'a> { } } - let needs_newline = match &sub_expr.value { - SpaceBefore(..) => true, - Str(text) => is_str_multiline(text), - _ => false, - }; - let needs_parens = - needs_newline && matches!(unary_op.value, called_via::UnaryOp::Negate); + let lifted = expr_lift_spaces(Parens::InOperator, buf.text.bump(), &sub_expr.value); + + let before_all_newlines = lifted.before.iter().all(|s| s.is_newline()); + + let needs_newline = !before_all_newlines + || match &lifted.item { + Str(text) => is_str_multiline(text), + _ => false, + }; + + let needs_parens = (needs_newline + && matches!(unary_op.value, called_via::UnaryOp::Negate)) + || matches!( + lifted.item, + Expr::Apply(..) | Expr::BinOps(..) | Expr::Defs(..) + ) + || (matches!(unary_op.value, called_via::UnaryOp::Negate) + && requires_space_after_unary(&lifted.item)); if needs_parens { // Unary negation can't be followed by whitespace (which is what a newline is) - so // we need to wrap the negated value in parens. - buf.push('('); - } - - let inner_indent = if needs_parens { - indent + INDENT + fmt_parens(&sub_expr.value, buf, indent); } else { - indent - }; + if matches!(unary_op.value, called_via::UnaryOp::Not) + && requires_space_after_unary(&lifted.item) + { + // If the subexpression is an accessor function, we need to add a space, + // since `!.foo` doesn't parse. Yes, this wouldn't be valid anyway, + // but the formatter needs to be able to format invalid code. + buf.spaces(1); + } - sub_expr.format_with_options(buf, Parens::InApply, newlines, inner_indent); + let inner_indent = if needs_newline { + indent + INDENT + } else { + indent + }; - if needs_parens { - buf.push(')'); + let inner_parens = if needs_parens { + Parens::NotNeeded + } else { + Parens::InApply + }; + + if !before_all_newlines { + format_spaces(buf, lifted.before, newlines, inner_indent); + } + lifted + .item + .format_with_options(buf, inner_parens, newlines, inner_indent); + format_spaces(buf, lifted.after, newlines, inner_indent); } } AccessorFunction(key) => { @@ -553,9 +330,333 @@ impl<'a> Formattable for Expr<'a> { SingleFieldRecordBuilder { .. } => {} OptionalFieldInRecordBuilder(_, _) => {} } + + if !me.after.is_empty() { + format_spaces(buf, me.after, newlines, indent); + } } } +pub fn expr_is_multiline(me: &Expr<'_>, comments_only: bool) -> bool { + match me { + // Return whether these spaces contain any Newlines + Expr::SpaceBefore(sub_expr, spaces) | Expr::SpaceAfter(sub_expr, spaces) => { + debug_assert!(!spaces.is_empty()); + + if comments_only { + spaces.iter().any(|s| s.is_comment()) || expr_is_multiline(sub_expr, comments_only) + } else { + true + } + } + + Expr::MalformedSuffixed(loc_expr) => expr_is_multiline(&loc_expr.value, comments_only), + + // These expressions never have newlines + Expr::Float(..) + | Expr::Num(..) + | Expr::NonBase10Int { .. } + | Expr::SingleQuote(_) + | Expr::AccessorFunction(_) + | Expr::RecordUpdater(_) + | Expr::Var { .. } + | Expr::Underscore { .. } + | Expr::MalformedIdent(_, _) + | Expr::Tag(_) + | Expr::OpaqueRef(_) + | Expr::Crash + | Expr::Dbg + | Expr::Try => false, + + Expr::RecordAccess(inner, _) + | Expr::TupleAccess(inner, _) + | Expr::TrySuffix { expr: inner, .. } => expr_is_multiline(inner, comments_only), + + // These expressions always have newlines + Expr::Defs(_, _) | Expr::When(_, _) => true, + + Expr::List(items) => is_collection_multiline(items), + + Expr::Str(literal) => is_str_multiline(literal), + Expr::Apply(loc_expr, args, _) => { + expr_is_multiline(&loc_expr.value, comments_only) + || args + .iter() + .any(|loc_arg| expr_is_multiline(&loc_arg.value, comments_only)) + } + + Expr::DbgStmt { + first: condition, .. + } => expr_is_multiline(&condition.value, comments_only), + Expr::LowLevelDbg(_, _, _) => { + unreachable!("LowLevelDbg should only exist after desugaring, not during formatting") + } + Expr::Return(_return_value, _after_return) => true, + + Expr::If { + if_thens: branches, + final_else, + .. + } => { + expr_is_multiline(&final_else.value, comments_only) + || branches.iter().any(|(c, t)| { + expr_is_multiline(&c.value, comments_only) + || expr_is_multiline(&t.value, comments_only) + }) + } + + Expr::BinOps(lefts, loc_right) => { + lefts + .iter() + .any(|(loc_expr, _)| expr_is_multiline(&loc_expr.value, comments_only)) + || expr_is_multiline(&loc_right.value, comments_only) + } + + Expr::UnaryOp(loc_subexpr, _) + | Expr::PrecedenceConflict(roc_parse::ast::PrecedenceConflict { + expr: loc_subexpr, .. + }) + | Expr::EmptyRecordBuilder(loc_subexpr) + | Expr::SingleFieldRecordBuilder(loc_subexpr) + | Expr::OptionalFieldInRecordBuilder(_, loc_subexpr) => { + expr_is_multiline(&loc_subexpr.value, comments_only) + } + + Expr::ParensAround(subexpr) => expr_is_multiline(subexpr, comments_only), + + Expr::Closure(loc_patterns, loc_body) => { + // check the body first because it's more likely to be multiline + expr_is_multiline(&loc_body.value, comments_only) + || loc_patterns + .iter() + .any(|loc_pattern| loc_pattern.value.is_multiline()) + } + Expr::Backpassing(loc_patterns, loc_body, loc_ret) => { + // check the body first because it's more likely to be multiline + expr_is_multiline(&loc_body.value, comments_only) + || expr_is_multiline(&loc_ret.value, comments_only) + || loc_patterns + .iter() + .any(|loc_pattern| loc_pattern.value.is_multiline()) + } + + Expr::Record(fields) => is_collection_multiline(fields), + Expr::Tuple(fields) => is_collection_multiline(fields), + Expr::RecordUpdate { fields, .. } => is_collection_multiline(fields), + Expr::RecordBuilder { fields, .. } => is_collection_multiline(fields), + } +} + +fn lower<'a, 'b: 'a>(arena: &'b Bump, lifted: Spaces<'b, Expr<'b>>) -> Expr<'b> { + if lifted.before.is_empty() && lifted.after.is_empty() { + return lifted.item; + } + if lifted.before.is_empty() { + return Expr::SpaceAfter(arena.alloc(lifted.item), lifted.after); + } + if lifted.after.is_empty() { + return Expr::SpaceBefore(arena.alloc(lifted.item), lifted.before); + } + Expr::SpaceBefore( + arena.alloc(Expr::SpaceAfter(arena.alloc(lifted.item), lifted.after)), + lifted.before, + ) +} + +fn fmt_expr_collection( + buf: &mut Buf<'_>, + indent: u16, + braces: Braces, + items: Collection<'_, &Loc>>, + newlines: Newlines, +) { + let arena = buf.text.bump(); + let mut new_items: Vec<'_, &Expr<'_>> = Vec::with_capacity_in(items.len(), arena); + + let mut last_after: &[CommentOrNewline<'_>] = &[]; + + for item in items.items { + let mut lifted = expr_lift_spaces(Parens::InCollection, arena, &item.value); + lifted.before = merge_spaces_conservative(arena, last_after, lifted.before); + last_after = lifted.after; + lifted.after = &[]; + new_items.push(arena.alloc(lower(arena, lifted))); + } + + 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 requires_space_after_unary(item: &Expr<'_>) -> bool { + match item { + Expr::AccessorFunction(_) | Expr::UnaryOp(..) => true, + Expr::Num(text) | Expr::Float(text) => text.starts_with('-'), + Expr::NonBase10Int { + string: _, + base: _, + is_negative, + } => *is_negative, + Expr::RecordUpdater(..) => true, + Expr::Apply(inner, _, _) => requires_space_after_unary(&inner.value), + Expr::TrySuffix { target: _, expr } => requires_space_after_unary(expr), + Expr::SpaceAfter(inner, _) | Expr::SpaceBefore(inner, _) => { + requires_space_after_unary(inner) + } + _ => false, + } +} + +fn fmt_apply( + loc_expr: &Loc>, + loc_args: &[&Loc>], + indent: u16, + buf: &mut Buf<'_>, +) { + // should_reflow_outdentable, aka should we transform this: + // + // ``` + // foo bar + // [ + // 1, + // 2, + // ] + // ``` + // + // Into this: + // + // ``` + // foo bar [ + // 1, + // 2, + // ] + // ``` + let should_reflow_outdentable = loc_expr.extract_spaces().after.is_empty() + && except_last(loc_args).all(|a| !a.is_multiline()) + && loc_args + .last() + .map(|a| { + a.extract_spaces().item.is_multiline() + && is_outdentable_collection(&a.value.extract_spaces().item) + && (a.extract_spaces().before == [CommentOrNewline::Newline] + || a.extract_spaces().before.is_empty()) + }) + .unwrap_or_default(); + + let needs_indent = !should_reflow_outdentable + && (!loc_expr.extract_spaces().after.is_empty() + || except_last(loc_args).any(|a| a.is_multiline()) + || loc_expr.is_multiline() + || loc_args + .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 + }; + + let expr_needs_parens = (expr_ends_in_closure(&loc_expr.value) && !loc_args.is_empty()) + || expr_needs_parens_in_apply(&loc_expr.value); + + if expr_needs_parens { + fmt_parens(&loc_expr.value, buf, indent); + } else { + loc_expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent); + } + + for loc_arg in loc_args.iter() { + if should_reflow_outdentable { + buf.spaces(1); + + // Ignore any comments+newlines before/after. + // We checked above that there's only a single newline before the last arg, + // which we're intentionally ignoring. + + let arg = loc_arg.extract_spaces(); + arg.item + .format_with_options(buf, Parens::InApply, Newlines::Yes, arg_indent); + } else if needs_indent { + let arg = loc_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); + loc_arg.format_with_options(buf, Parens::InApply, Newlines::Yes, arg_indent); + } + } +} + +fn expr_needs_parens_in_apply(expr: &Expr<'_>) -> bool { + match expr { + Expr::SpaceBefore(inner, _) | Expr::SpaceAfter(inner, _) => { + expr_needs_parens_in_apply(inner) + } + Expr::If { .. } | Expr::When(_, _) | Expr::Return(_, _) => true, + _ => false, + } +} + +fn is_outdentable_collection(expr: &Expr<'_>) -> bool { + match expr { + Expr::Tuple(items) => is_collection_multiline(items), + Expr::List(items) => is_collection_multiline(items), + Expr::Record(items) => is_collection_multiline(items), + _ => false, + } +} + +fn expr_ends_in_closure(expr: &Expr<'_>) -> bool { + match expr.extract_spaces().item { + Expr::Closure(..) => true, + Expr::UnaryOp(expr, _) => expr_ends_in_closure(&expr.value), + _ => false, + } +} + +fn fmt_parens(sub_expr: &Expr<'_>, buf: &mut Buf<'_>, indent: u16) { + let should_add_newlines = match sub_expr { + Expr::Closure(..) | Expr::SpaceBefore(..) | Expr::SpaceAfter(Expr::Closure(..), ..) => { + false + } + _ => sub_expr.is_multiline(), + }; + + buf.indent(indent); + buf.push('('); + if should_add_newlines { + buf.newline(); + } + + let next_indent = if starts_with_newline(sub_expr) || should_add_newlines { + match sub_expr { + Expr::Closure(..) | Expr::SpaceAfter(Expr::Closure(..), ..) => indent, + _ => indent + INDENT, + } + } else { + indent + }; + + sub_expr.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, next_indent); + + if !matches!(sub_expr, Expr::SpaceAfter(..)) && should_add_newlines { + buf.newline(); + } + buf.indent(indent); + buf.push(')'); +} + pub fn is_str_multiline(literal: &StrLiteral) -> bool { use roc_parse::ast::StrLiteral::*; @@ -758,43 +859,222 @@ pub fn fmt_str_literal(buf: &mut Buf, literal: StrLiteral, indent: u16) { } } +pub fn expr_lift_and_lower<'a, 'b: 'a>( + _parens: Parens, + arena: &'a Bump, + expr: &Expr<'b>, +) -> Expr<'a> { + lower(arena, expr_lift_spaces(Parens::NotNeeded, arena, expr)) +} + +pub fn expr_lift_spaces<'a, 'b: 'a>( + parens: Parens, + arena: &'a Bump, + expr: &Expr<'b>, +) -> Spaces<'a, Expr<'a>> { + match expr { + Expr::Apply(func, args, called_via) => { + let func_lifted = expr_lift_spaces(Parens::InApply, arena, &func.value); + let args = arena.alloc_slice_copy(args); + if let Some(last) = args.last_mut() { + let last_lifted = expr_lift_spaces(Parens::InApply, arena, &last.value); + if last_lifted.before.is_empty() { + *last = arena.alloc(Loc::at(last.region, last_lifted.item)); + } else { + *last = arena.alloc(Loc::at( + last.region, + Expr::SpaceBefore(arena.alloc(last_lifted.item), last_lifted.before), + )); + } + + let func_fixed = if func_lifted.after.is_empty() { + func_lifted.item + } else { + Expr::SpaceAfter(arena.alloc(func_lifted.item), func_lifted.after) + }; + + Spaces { + before: func_lifted.before, + item: Expr::Apply( + arena.alloc(Loc::at(func.region, func_fixed)), + args, + *called_via, + ), + after: last_lifted.after, + } + } else { + Spaces { + before: func_lifted.before, + item: Expr::Apply( + arena.alloc(Loc::at(func.region, func_lifted.item)), + args, + *called_via, + ), + after: func_lifted.after, + } + } + } + Expr::Defs(defs, final_expr) => { + let mut defs = (*defs).clone(); + let mut before: &[CommentOrNewline] = &[]; + if let Some(spaces_range) = defs.space_before.first_mut() { + if !spaces_range.is_empty() { + before = &defs.spaces[spaces_range.indices()]; + *spaces_range = Slice::empty(); + } + } + + let inner_before = match defs.tags[0].split() { + Ok(_td) => &[], + Err(vd) => { + let lifted = valdef_lift_spaces_before(arena, defs.value_defs[vd.index()]); + defs.value_defs[vd.index()] = lifted.item; + lifted.before + } + }; + + let final_expr_lifted = expr_lift_spaces(Parens::NotNeeded, arena, &final_expr.value); + + let new_final_expr = if final_expr_lifted.before.is_empty() { + final_expr_lifted.item + } else { + Expr::SpaceBefore( + arena.alloc(final_expr_lifted.item), + final_expr_lifted.before, + ) + }; + + let before = merge_spaces(arena, arena.alloc_slice_copy(before), inner_before); + + let mut item = Expr::Defs( + arena.alloc(defs), + arena.alloc(Loc::at(final_expr.region, new_final_expr)), + ); + + if parens == Parens::InCollection { + item = Expr::ParensAround(arena.alloc(item)); + } + + Spaces { + before, + item, + after: final_expr_lifted.after, + } + } + Expr::SpaceBefore(expr, spaces) => { + let mut inner = expr_lift_spaces(parens, arena, expr); + inner.before = merge_spaces_conservative(arena, spaces, inner.before); + inner + } + Expr::SpaceAfter(expr, spaces) => { + let mut inner = expr_lift_spaces(parens, arena, expr); + inner.after = merge_spaces_conservative(arena, inner.after, spaces); + inner + } + Expr::ParensAround(inner) => { + if (parens == Parens::NotNeeded || parens == Parens::InCollection) + && !sub_expr_requests_parens(inner) + { + expr_lift_spaces(Parens::NotNeeded, arena, inner) + } else { + Spaces { + before: &[], + item: *expr, + after: &[], + } + } + } + _ => Spaces { + before: &[], + item: *expr, + after: &[], + }, + } +} + +pub fn expr_lift_spaces_before<'a, 'b: 'a>( + parens: Parens, + arena: &'a Bump, + expr: &Expr<'b>, +) -> SpacesBefore<'a, Expr<'a>> { + let lifted = expr_lift_spaces(parens, arena, expr); + SpacesBefore { + before: lifted.before, + item: lifted.item.maybe_after(arena, lifted.after), + } +} + +pub fn expr_lift_spaces_after<'a, 'b: 'a>( + parens: Parens, + arena: &'a Bump, + expr: &Expr<'b>, +) -> SpacesAfter<'a, Expr<'a>> { + let lifted = expr_lift_spaces(parens, arena, expr); + SpacesAfter { + item: lifted.item.maybe_before(arena, lifted.before), + after: lifted.after, + } +} + +pub fn merge_spaces_conservative<'a>( + arena: &'a Bump, + a: &'a [CommentOrNewline<'a>], + b: &'a [CommentOrNewline<'a>], +) -> &'a [CommentOrNewline<'a>] { + if a.is_empty() { + b + } else if b.is_empty() { + a + } else { + let mut merged = Vec::with_capacity_in(a.len() + b.len(), arena); + merged.extend_from_slice(a); + let mut it = b.iter(); + for item in it.by_ref() { + if item.is_comment() { + merged.push(*item); + break; + } + } + merged.extend(it); + merged.into_bump_slice() + } +} + fn fmt_binops<'a>( buf: &mut Buf, lefts: &'a [(Loc>, Loc)], loc_right_side: &'a Loc>, - part_of_multi_line_binops: bool, indent: u16, ) { - let is_multiline = part_of_multi_line_binops - || loc_right_side.value.is_multiline() + let is_multiline = loc_right_side.value.is_multiline() || lefts.iter().any(|(expr, _)| expr.value.is_multiline()); - let is_any_lefts_suffixed = lefts.iter().any(|(left, _)| is_expr_suffixed(&left.value)); - let is_right_suffixed = is_expr_suffixed(&loc_right_side.value); - let is_any_suffixed = is_any_lefts_suffixed || is_right_suffixed; - - let mut is_first = false; - let mut adjusted_indent = indent; - - if is_any_suffixed { - // we only want to indent the remaining lines if this is a suffixed expression. - is_first = true; - } - for (loc_left_side, loc_binop) in lefts { let binop = loc_binop.value; - loc_left_side.format_with_options(buf, Parens::InOperator, Newlines::No, adjusted_indent); + let lifted_left_side = + expr_lift_spaces(Parens::InOperator, buf.text.bump(), &loc_left_side.value); + format_spaces(buf, lifted_left_side.before, Newlines::Yes, indent); - if is_first { - // indent the remaining lines, but only if the expression is suffixed. - is_first = false; - adjusted_indent = indent + 4; + let need_parens = matches!(lifted_left_side.item, Expr::BinOps(..)) + || starts_with_unary_minus(lifted_left_side.item); + + if need_parens { + fmt_parens(&lifted_left_side.item, buf, indent); + } else { + lifted_left_side.item.format_with_options( + buf, + Parens::InOperator, + Newlines::Yes, + indent, + ); } + format_spaces(buf, lifted_left_side.after, Newlines::Yes, indent); + if is_multiline { buf.ensure_ends_with_newline(); - buf.indent(adjusted_indent); + buf.indent(indent); } else { buf.spaces(1); } @@ -804,10 +1084,43 @@ fn fmt_binops<'a>( buf.spaces(1); } - loc_right_side.format_with_options(buf, Parens::InOperator, Newlines::Yes, adjusted_indent); + let lifted_right_side = + expr_lift_spaces(Parens::InOperator, buf.text.bump(), &loc_right_side.value); + format_spaces(buf, lifted_right_side.before, Newlines::Yes, indent); + + let need_parens = matches!(lifted_right_side.item, Expr::BinOps(..)) + || starts_with_unary_minus(lifted_right_side.item); + + if need_parens { + fmt_parens(&lifted_right_side.item, buf, indent); + } else { + lifted_right_side + .item + .format_with_options(buf, Parens::InOperator, Newlines::Yes, indent); + } + + format_spaces(buf, lifted_right_side.after, Newlines::Yes, indent); } -fn format_spaces(buf: &mut Buf, spaces: &[CommentOrNewline], newlines: Newlines, indent: u16) { +fn starts_with_unary_minus(item: Expr<'_>) -> bool { + match item { + Expr::UnaryOp( + _, + Loc { + value: UnaryOp::Negate, + .. + }, + ) => true, + Expr::SpaceAfter(expr, _) | Expr::SpaceBefore(expr, _) => starts_with_unary_minus(*expr), + Expr::Apply(expr, _args, _) => starts_with_unary_minus(expr.value), + Expr::BinOps(lefts, _right) => lefts + .first() + .map_or(false, |(expr, _)| starts_with_unary_minus(expr.value)), + _ => false, + } +} + +pub fn format_spaces(buf: &mut Buf, spaces: &[CommentOrNewline], newlines: Newlines, indent: u16) { match newlines { Newlines::Yes => { fmt_spaces(buf, spaces.iter(), indent); @@ -1021,19 +1334,24 @@ fn fmt_when<'a>( fn fmt_dbg_stmt<'a>( buf: &mut Buf, condition: &'a Loc>, + extra_args: &'a [&'a Loc>], continuation: &'a Loc>, parens: Parens, indent: u16, ) { + let mut args = Vec::with_capacity_in(extra_args.len() + 1, buf.text.bump()); + args.push(condition); + args.extend_from_slice(extra_args); + Expr::Apply( &Loc::at_zero(Expr::Dbg), - &[condition], + args.into_bump_slice(), called_via::CalledVia::Space, ) .format_with_options(buf, parens, Newlines::Yes, indent); - // Always put a blank line after the `dbg` line(s) - buf.ensure_ends_with_blank_line(); + // Always put a newline after the `dbg` line(s) + buf.ensure_ends_with_newline(); continuation.format(buf, indent); } @@ -1050,7 +1368,11 @@ fn fmt_return<'a>( buf.indent(indent); buf.push_str(keyword::RETURN); - buf.spaces(1); + if matches!(return_value.value.extract_spaces().item, Expr::Defs(..)) { + buf.ensure_ends_with_newline(); + } else { + buf.spaces(1); + } let return_indent = if return_value.is_multiline() { indent + INDENT @@ -1058,13 +1380,21 @@ fn fmt_return<'a>( indent }; - return_value.format(buf, return_indent); + return_value.format_with_options(buf, parens, Newlines::No, return_indent); if let Some(after_return) = after_return { - if after_return.value.extract_spaces().before.is_empty() { + let lifted = expr_lift_spaces(Parens::NotNeeded, buf.text.bump(), &after_return.value); + if lifted.before.is_empty() { buf.ensure_ends_with_newline(); + } else { + fmt_spaces(buf, lifted.before.iter(), indent); } - after_return.format_with_options(buf, parens, newlines, indent); + lifted + .item + .format_with_options(buf, parens, newlines, indent); + fmt_spaces(buf, lifted.after.iter(), indent); + } else if parens != Parens::NotNeeded { + buf.ensure_ends_with_newline(); } } @@ -1246,12 +1576,10 @@ fn fmt_closure<'a>( indent }; - let mut it = loc_patterns.iter().peekable(); + let mut first = true; - while let Some(loc_pattern) = it.next() { - loc_pattern.format_with_options(buf, Parens::InAsPattern, Newlines::No, indent); - - if it.peek().is_some() { + for loc_pattern in loc_patterns.iter() { + if !first { buf.indent(indent); if arguments_are_multiline { buf.push(','); @@ -1261,10 +1589,27 @@ fn fmt_closure<'a>( buf.spaces(1); } } + first = false; + + let arg = pattern_lift_spaces(buf.text.bump(), &loc_pattern.value); + + if !arg.before.is_empty() { + fmt_comments_only(buf, arg.before.iter(), NewlineAt::Bottom, indent) + } + + arg.item + .format_with_options(buf, Parens::InAsPattern, Newlines::No, indent); + + if !arg.after.is_empty() { + if starts_with_inline_comment(arg.after.iter()) { + buf.spaces(1); + } + fmt_comments_only(buf, arg.after.iter(), NewlineAt::Bottom, indent) + } } if arguments_are_multiline { - buf.newline(); + buf.ensure_ends_with_newline(); buf.indent(indent); } else { buf.spaces(1); @@ -1330,7 +1675,7 @@ fn fmt_backpassing<'a>( loc_patterns: &'a [Loc>], loc_body: &'a Loc>, loc_ret: &'a Loc>, - indent: u16, + outer_indent: u16, ) { use self::Expr::*; @@ -1339,37 +1684,52 @@ fn fmt_backpassing<'a>( .any(|loc_pattern| loc_pattern.is_multiline()); // If the arguments are multiline, go down a line and indent. - let indent = if arguments_are_multiline { - indent + INDENT + let arg_indent = if arguments_are_multiline { + outer_indent + INDENT } else { - indent + outer_indent }; - let mut it = loc_patterns.iter().peekable(); + let mut first = true; - while let Some(loc_pattern) = it.next() { + for loc_pattern in loc_patterns.iter() { let needs_parens = if pattern_needs_parens_when_backpassing(&loc_pattern.value) { Parens::InApply } else { Parens::NotNeeded }; - loc_pattern.format_with_options(buf, needs_parens, Newlines::No, indent); + let pat = loc_pattern.value.extract_spaces(); - if it.peek().is_some() { + if !first { + buf.indent(arg_indent); + buf.push(','); + } + + fmt_comments_only(buf, pat.before.iter(), NewlineAt::Bottom, arg_indent); + + if !first { if arguments_are_multiline { - buf.push(','); - buf.newline(); + buf.ensure_ends_with_newline(); } else { - buf.push_str(","); buf.spaces(1); } } + + pat.item.format_with_options( + buf, + needs_parens, + Newlines::No, + if first { outer_indent } else { arg_indent }, + ); + fmt_comments_only(buf, pat.after.iter(), NewlineAt::Bottom, arg_indent); + + first = false; } if arguments_are_multiline { - buf.newline(); - buf.indent(indent); + buf.ensure_ends_with_newline(); + buf.indent(arg_indent); } else { buf.spaces(1); } @@ -1380,9 +1740,9 @@ fn fmt_backpassing<'a>( // If the body is multiline, go down a line and indent. let body_indent = if is_multiline { - indent + INDENT + arg_indent + INDENT } else { - indent + arg_indent }; // the body of the Backpass can be on the same line, or @@ -1400,7 +1760,7 @@ fn fmt_backpassing<'a>( }; loc_body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, body_indent); - loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent); + loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, outer_indent); } fn pattern_needs_parens_when_backpassing(pat: &Pattern) -> bool { @@ -1433,7 +1793,7 @@ fn fmt_record_like<'a, Field, Format, ToSpaceBefore>( let loc_fields = fields.items; let final_comments = fields.final_comments(); buf.indent(indent); - if loc_fields.is_empty() && final_comments.iter().all(|c| c.is_newline()) && prefix.is_none() { + if loc_fields.is_empty() && final_comments.is_empty() && prefix.is_none() { buf.push_str("{}"); } else { buf.push('{'); @@ -1447,11 +1807,13 @@ fn fmt_record_like<'a, Field, Format, ToSpaceBefore>( Some(RecordPrefix::Update(record_var)) => { buf.spaces(1); record_var.format(buf, indent); + buf.indent(indent); buf.push_str(" &"); } Some(RecordPrefix::Mapper(mapper_var)) => { buf.spaces(1); mapper_var.format(buf, indent); + buf.indent(indent); buf.push_str(" <-"); } } @@ -1623,7 +1985,7 @@ fn assigned_field_to_space_before<'a, T>( } } -fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool { +pub fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool { match expr { Expr::BinOps(left_side, _) => { left_side @@ -1649,6 +2011,12 @@ fn sub_expr_requests_parens(expr: &Expr<'_>) -> bool { } Expr::If { .. } => true, Expr::Defs(_, _) => true, + Expr::Return(..) | Expr::Backpassing(..) | Expr::DbgStmt { .. } => { + // This is because e.g. (return x)\nfoo would be de-parenthesized and cause the `after_return` to be `foo`. + // That _is_ a semantic change technically right now, because that transform is done in the parser. + // When that's moved to `can`, we can remove this + true + } Expr::SpaceBefore(e, _) => sub_expr_requests_parens(e), Expr::SpaceAfter(e, _) => sub_expr_requests_parens(e), _ => false, diff --git a/crates/compiler/fmt/src/lib.rs b/crates/compiler/fmt/src/lib.rs index d92b0152ad..8e47e7ac8f 100644 --- a/crates/compiler/fmt/src/lib.rs +++ b/crates/compiler/fmt/src/lib.rs @@ -18,12 +18,14 @@ 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, @@ -40,11 +42,18 @@ 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!( @@ -61,6 +70,7 @@ 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, @@ -73,6 +83,7 @@ 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, @@ -129,6 +140,12 @@ 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'); diff --git a/crates/compiler/fmt/src/pattern.rs b/crates/compiler/fmt/src/pattern.rs index dbde68c8fa..ad9aff4f4e 100644 --- a/crates/compiler/fmt/src/pattern.rs +++ b/crates/compiler/fmt/src/pattern.rs @@ -1,8 +1,15 @@ use crate::annotation::{Formattable, Newlines, Parens}; -use crate::expr::{fmt_str_literal, format_sq_literal, is_str_multiline}; +use crate::expr::{ + expr_is_multiline, expr_lift_spaces_after, fmt_str_literal, format_sq_literal, is_str_multiline, +}; use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt, INDENT}; use crate::Buf; -use roc_parse::ast::{Base, CommentOrNewline, Pattern, PatternAs}; +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; 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); @@ -54,7 +61,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(), + Pattern::OptionalField(_, expr) => expr_is_multiline(&expr.value, true), Pattern::As(pattern, pattern_as) => pattern.is_multiline() || pattern_as.is_multiline(), Pattern::ListRest(opt_pattern_as) => match opt_pattern_as { @@ -86,222 +93,307 @@ impl<'a> Formattable for Pattern<'a> { } } - fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) { - use self::Pattern::*; + fn format_with_options(&self, buf: &mut Buf, parens: Parens, _newlines: Newlines, indent: u16) { + fmt_pattern_inner(self, buf, parens, indent, self.is_multiline()); + } +} - 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); +fn fmt_pattern_inner( + pat: &Pattern<'_>, + buf: &mut Buf, + parens: Parens, + indent: u16, + outer_is_multiline: bool, +) { + use self::Pattern::*; - let indent_more = if self.is_multiline() { - indent + INDENT + 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('('); + } + + 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) } else { - 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(')'); + fmt_spaces(buf, pat.before.iter(), indent); } } - 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() { - loc_pattern.format(buf, indent); + fmt_pattern_inner(&pat.item, buf, Parens::InApply, indent, is_multiline); - if it.peek().is_some() { - buf.push_str(","); - buf.spaces(1); + 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); } } + + fmt_pattern_inner(&item.item, buf, Parens::NotNeeded, indent, is_multiline); + + let is_multiline = item.item.is_multiline(); + + 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); + } + + if !is_multiline { + fmt_comments_only(buf, item.after.iter(), NewlineAt::Bottom, indent) + } else { + fmt_spaces(buf, item.after.iter(), indent); + } + } + } + buf.spaces(1); + } + + buf.indent(indent); + buf.push_str("}"); + } + + 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); } - - buf.push_str("}"); } - RequiredField(name, loc_pattern) => { - buf.indent(indent); - buf.push_str(name); - buf.push_str(":"); - buf.spaces(1); - loc_pattern.format(buf, indent); - } + buf.indent(indent); + buf.push_str(")"); + } + List(loc_patterns) => { + buf.indent(indent); + buf.push_str("["); - OptionalField(name, loc_pattern) => { - buf.indent(indent); - buf.push_str(name); - buf.push_str(" ?"); - buf.spaces(1); - loc_pattern.format(buf, indent); - } + 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, + ); - &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); - } - } - - buf.push_str(")"); - } - List(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); - } - } - - 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); - - pattern_as.format(buf, indent + INDENT); + if it.peek().is_some() { + buf.indent(indent); + buf.push_str(","); + buf.spaces(1); } } - As(pattern, pattern_as) => { - let needs_parens = parens == Parens::InAsPattern; + buf.indent(indent); + buf.push_str("]"); + } + ListRest(opt_pattern_as) => { + buf.indent(indent); + buf.push_str(".."); - if needs_parens { - buf.push('('); - } - - fmt_pattern(buf, &pattern.value, indent, parens); + 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); pattern_as.format(buf, indent + INDENT); - - if needs_parens { - buf.push(')'); - } } + } - // 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); - } + As(pattern, pattern_as) => { + let needs_parens = parens == Parens::InAsPattern; - 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, _) => { + if needs_parens { buf.indent(indent); - buf.push_str(string); + buf.push('('); } - QualifiedIdentifier { module_name, ident } => { - buf.indent(indent); - if !module_name.is_empty() { - buf.push_str(module_name); - buf.push('.'); - } - buf.push_str(ident); + fmt_pattern(buf, &pattern.value, indent, parens); + + pattern_as.format(buf, indent + INDENT); + + if needs_parens { + buf.indent(indent); + buf.push(')'); } } + + 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); + } } } -fn starts_with_inline_comment<'a, I: IntoIterator>>( +pub fn starts_with_inline_comment<'a, I: IntoIterator>>( spaces: I, ) -> bool { matches!( @@ -309,3 +401,102 @@ fn starts_with_inline_comment<'a, I: IntoIterator( + 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, + } +} diff --git a/crates/compiler/parse/src/ast.rs b/crates/compiler/parse/src/ast.rs index ee8dd2cb4e..f67a95c573 100644 --- a/crates/compiler/parse/src/ast.rs +++ b/crates/compiler/parse/src/ast.rs @@ -28,12 +28,26 @@ 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), @@ -491,7 +505,11 @@ pub enum Expr<'a> { Backpassing(&'a [Loc>], &'a Loc>, &'a Loc>), Dbg, - DbgStmt(&'a Loc>, &'a Loc>), + DbgStmt { + first: &'a Loc>, + extra_args: &'a [&'a Loc>], + continuation: &'a Loc>, + }, // This form of debug is a desugared call to roc_dbg LowLevelDbg(&'a (&'a str, &'a str), &'a Loc>, &'a Loc>), @@ -671,7 +689,15 @@ 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(a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value), + 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::LowLevelDbg(_, a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value), Expr::Try => false, Expr::UnaryOp(a, _) => is_expr_suffixed(&a.value), @@ -930,10 +956,17 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> { expr_stack.push(&a.value); expr_stack.push(&b.value); } - DbgStmt(condition, cont) => { + DbgStmt { + first, + extra_args, + continuation, + } => { expr_stack.reserve(2); - expr_stack.push(&condition.value); - expr_stack.push(&cont.value); + expr_stack.push(&first.value); + for arg in extra_args.iter() { + expr_stack.push(&arg.value); + } + expr_stack.push(&continuation.value); } LowLevelDbg(_, condition, cont) => { expr_stack.reserve(2); @@ -2311,6 +2344,7 @@ impl_extract_spaces!(Tag); impl_extract_spaces!(AssignedField); 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; @@ -2476,7 +2510,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(condition, continuation) => condition.is_malformed() || continuation.is_malformed(), + DbgStmt { first, extra_args, continuation } => first.is_malformed() || extra_args.iter().any(|a| a.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()), diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 87691c07b6..2d66fc9bae 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -298,8 +298,11 @@ 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_term(options)).parse(arena, state, min_indent)?; + let (_, (loc_op, loc_expr), state) = and( + loc(unary_negate()), + loc_possibly_negative_or_negated_term(options), + ) + .parse(arena, state, min_indent)?; let loc_expr = numeric_negate_expression(arena, initial, loc_op, loc_expr, &[]); @@ -307,19 +310,23 @@ fn loc_possibly_negative_or_negated_term<'a>( }; one_of![ - parse_unary_negate, + parse_unary_negate.trace("d"), // this will parse negative numbers, which the unary negate thing up top doesn't (for now) - loc(specialize_err(EExpr::Number, number_literal_help())), + loc(specialize_err(EExpr::Number, number_literal_help())).trace("c"), loc(map_with_arena( and( loc(byte(b'!', EExpr::Start)), - space0_before_e(loc_term(options), EExpr::IndentStart) + space0_before_e( + loc_possibly_negative_or_negated_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)) } - )), - loc_term_or_underscore_or_conditional(options) + )) + .trace("b"), + loc_term_or_underscore_or_conditional(options).trace("a") ] } @@ -328,7 +335,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) @@ -339,7 +346,10 @@ 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 { + if state.bytes().starts_with(b"-") + && !followed_by_whitespace + && state.column() >= min_indent + { // the negate is only unary if it is not followed by whitespace let state = state.advance(1); Ok((MadeProgress, (), state)) @@ -459,7 +469,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(), min_indent) { + match loc(bin_op(check_for_defs)).parse(arena, state.clone(), call_min_indent) { Err((MadeProgress, f)) => Err((MadeProgress, f)), Ok((_, loc_op, state)) => { expr_state.consume_spaces(arena); @@ -845,13 +855,13 @@ fn numeric_negate_expression<'a, T>( let region = Region::new(start, expr.region.end()); let new_expr = match expr.value { - Expr::Num(string) => { + Expr::Num(string) if !string.starts_with('-') => { let new_string = unsafe { std::str::from_utf8_unchecked(&state.bytes()[..string.len() + 1]) }; Expr::Num(new_string) } - Expr::Float(string) => { + Expr::Float(string) if !string.starts_with('-') => { let new_string = unsafe { std::str::from_utf8_unchecked(&state.bytes()[..string.len() + 1]) }; @@ -860,11 +870,11 @@ fn numeric_negate_expression<'a, T>( Expr::NonBase10Int { string, base, - is_negative, + is_negative: false, } => { // don't include the minus sign here; it will not be parsed right Expr::NonBase10Int { - is_negative: !is_negative, + is_negative: true, string, base, } @@ -1151,9 +1161,7 @@ fn parse_stmt_alias_or_opaque<'a>( AliasOrOpaque::Alias => { let (_, signature, state) = alias_signature().parse(arena, state, min_indent)?; - // 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 signature = signature.map(|v| v.maybe_before(arena, spaces_after_operator)); let header = TypeHeader { name: Loc::at(expr.region, name), @@ -1172,9 +1180,7 @@ fn parse_stmt_alias_or_opaque<'a>( let (_, (signature, derived), state) = opaque_signature().parse(arena, state, indented_more)?; - // 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 signature = signature.map(|v| v.maybe_before(arena, spaces_after_operator)); let header = TypeHeader { name: Loc::at(expr.region, name), @@ -1855,7 +1861,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(), min_indent) { + match loc(bin_op(check_for_defs)).parse(arena, state.clone(), call_min_indent) { Err((MadeProgress, f)) => Err((MadeProgress, f)), Ok((_, loc_op, state)) => { expr_state.consume_spaces(arena); @@ -1899,7 +1905,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(), min_indent) { + match loc(operator()).parse(arena, state.clone(), call_min_indent) { Err((MadeProgress, f)) => Err((MadeProgress, f)), Ok((_, loc_op, state)) => { expr_state.consume_spaces(arena); @@ -2172,7 +2178,7 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result( _, ) = 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(condition, arena.alloc(rest)); + let e = Expr::DbgStmt { + first: condition, + extra_args: &args[1..], + continuation: arena.alloc(rest), + }; let e = if sp_stmt.before.is_empty() { e @@ -3211,7 +3214,11 @@ 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(arena.alloc(condition), arena.alloc(rest)) + Expr::DbgStmt { + first: arena.alloc(condition), + extra_args: &[], + continuation: arena.alloc(rest), + } } else { Expr::Apply( arena.alloc(Loc { @@ -3799,9 +3806,9 @@ enum OperatorOrDef { } fn bin_op<'a>(check_for_defs: bool) -> impl Parser<'a, BinOp, EExpr<'a>> { - move |_, state: State<'a>, _m| { + move |_, state: State<'a>, min_indent| { let start = state.pos(); - let (_, op, state) = operator_help(EExpr::Start, EExpr::BadOperator, state)?; + let (_, op, state) = operator_help(EExpr::Start, EExpr::BadOperator, state, min_indent)?; let err_progress = if check_for_defs { MadeProgress } else { @@ -3822,7 +3829,8 @@ 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, _m| operator_help(EExpr::Start, EExpr::BadOperator, state)).trace("operator") + (move |_, state, min_indent| operator_help(EExpr::Start, EExpr::BadOperator, state, min_indent)) + .trace("operator") } #[inline(always)] @@ -3830,6 +3838,7 @@ 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, @@ -3855,7 +3864,21 @@ where match chomped { "" => Err((NoProgress, to_expectation(state.pos()))), "+" => good!(OperatorOrDef::BinOp(BinOp::Plus), 1), - "-" => good!(OperatorOrDef::BinOp(BinOp::Minus), 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::Star), 1), "/" => good!(OperatorOrDef::BinOp(BinOp::Slash), 1), "%" => good!(OperatorOrDef::BinOp(BinOp::Percent), 1), @@ -3883,6 +3906,10 @@ 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), } } diff --git a/crates/compiler/parse/src/normalize.rs b/crates/compiler/parse/src/normalize.rs index 6c5780ad8a..3de850a216 100644 --- a/crates/compiler/parse/src/normalize.rs +++ b/crates/compiler/parse/src/normalize.rs @@ -396,10 +396,22 @@ impl<'a> Normalize<'a> for ValueDef<'a> { match *self { Annotation(a, b) => Annotation(a.normalize(arena), b.normalize(arena)), - Body(a, b) => Body( - arena.alloc(a.normalize(arena)), - arena.alloc(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)) + } + } AnnotatedBody { ann_pattern, ann_type, @@ -560,26 +572,6 @@ 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); @@ -713,33 +705,22 @@ impl<'a> Normalize<'a> for Expr<'a> { arena.alloc(b.normalize(arena)), ), Expr::Crash => Expr::Crash, - 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::Defs(a, b) => fold_defs(arena, a.defs(), b.value.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(a, b) => Expr::DbgStmt( - arena.alloc(a.normalize(arena)), - arena.alloc(b.normalize(arena)), - ), + 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::LowLevelDbg(x, a, b) => Expr::LowLevelDbg( x, arena.alloc(a.normalize(arena)), @@ -755,7 +736,22 @@ 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) => { - Expr::UnaryOp(arena.alloc(a.normalize(arena)), b.normalize(arena)) + 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::If { if_thens, @@ -776,7 +772,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::Num(a), + Expr::SingleQuote(a) => Expr::SingleQuote(a), Expr::EmptyRecordBuilder(a) => { Expr::EmptyRecordBuilder(arena.alloc(a.normalize(arena))) } @@ -791,6 +787,61 @@ impl<'a> Normalize<'a> for Expr<'a> { } } +fn fold_defs<'a>( + arena: &'a Bump, + mut defs: impl Iterator, &'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()), @@ -847,7 +898,7 @@ impl<'a> Normalize<'a> for Pattern<'a> { is_negative, }, Pattern::FloatLiteral(a) => Pattern::FloatLiteral(a), - Pattern::StrLiteral(a) => Pattern::StrLiteral(a), + Pattern::StrLiteral(a) => Pattern::StrLiteral(a.normalize(arena)), Pattern::Underscore(a) => Pattern::Underscore(a), Pattern::Malformed(a) => Pattern::Malformed(a), Pattern::MalformedIdent(a, b) => Pattern::MalformedIdent(a, remove_spaces_bad_ident(b)), @@ -1465,7 +1516,6 @@ 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()), } } } diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index e21cfb222b..461e516efb 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -513,7 +513,6 @@ pub enum EExpect<'a> { Condition(&'a EExpr<'a>, Position), Continuation(&'a EExpr<'a>, Position), IndentCondition(Position), - DbgArity(Position), } #[derive(Debug, Clone, PartialEq, Eq)] @@ -836,7 +835,7 @@ where } // This should be enough for anyone. Right? RIGHT? - let indent_text = "| ; : ! ".repeat(20); + let indent_text = "| ; : ! ".repeat(100); let cur_indent = INDENT.with(|i| *i.borrow()); @@ -1060,7 +1059,7 @@ 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'@' | b'-', ) => { state = state.advance(width); Ok((MadeProgress, (), state)) @@ -1669,6 +1668,21 @@ 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. /// diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 2a978442a4..61e80c94e5 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -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, 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, error_on_byte, + 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, @@ -582,37 +582,39 @@ fn expression<'a>( let (p1, first, state) = space0_before_e(term(stop_at_surface_has), EType::TIndentStart) .parse(arena, state, min_indent)?; - let result = and( - zero_or_more(skip_first( - byte(b',', EType::TFunctionArgument), - one_of![ - space0_around_ee( - term(stop_at_surface_has), - EType::TIndentStart, - EType::TIndentEnd + 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)), ), - 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"), + 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 + }), + ], ) - .parse(arena, state.clone(), min_indent); + .trace("type_annotation:expression:arrow") + .parse(arena, rest_state, min_indent); let (progress, annot, state) = match result { - Ok((p2, (rest, (space_before_arrow, arrow)), state)) => { - let (p3, return_type, state) = + Ok((p3, (space_before_arrow, arrow), state)) => { + let (p4, return_type, state) = space0_before_e(term(stop_at_surface_has), EType::TIndentStart) .parse(arena, state, min_indent)?; @@ -636,7 +638,7 @@ fn expression<'a>( region, value: TypeAnnotation::Function(output, arrow, arena.alloc(return_type)), }; - let progress = p1.or(p2).or(p3); + let progress = p1.or(p2).or(p3).or(p4); (progress, result, state) } Err(err) => { @@ -694,6 +696,36 @@ 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>, &'a [CommentOrNewline<'a>]), + ), +) -> Loc> { + 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. diff --git a/crates/compiler/test_syntax/fuzz/fuzz_targets/fuzz_module.rs b/crates/compiler/test_syntax/fuzz/fuzz_targets/fuzz_module.rs index 034974911f..406b571fa7 100644 --- a/crates/compiler/test_syntax/fuzz/fuzz_targets/fuzz_module.rs +++ b/crates/compiler/test_syntax/fuzz/fuzz_targets/fuzz_module.rs @@ -1,6 +1,6 @@ #![no_main] -use libfuzzer_sys::fuzz_target; use bumpalo::Bump; +use libfuzzer_sys::fuzz_target; use test_syntax::test_helpers::Input; fuzz_target!(|data: &[u8]| { diff --git a/crates/compiler/test_syntax/src/minimize.rs b/crates/compiler/test_syntax/src/minimize.rs index 7cd87bd922..81d09b35ad 100644 --- a/crates/compiler/test_syntax/src/minimize.rs +++ b/crates/compiler/test_syntax/src/minimize.rs @@ -102,6 +102,12 @@ fn round_trip_once(input: Input<'_>) -> Option { return Some("Different ast".to_string()); } + let reformatted = reparsed_ast.format(); + + if output != reformatted { + return Some("Formatting not stable".to_string()); + } + None } diff --git a/crates/compiler/test_syntax/src/test_helpers.rs b/crates/compiler/test_syntax/src/test_helpers.rs index c16c17d001..187c2e32da 100644 --- a/crates/compiler/test_syntax/src/test_helpers.rs +++ b/crates/compiler/test_syntax/src/test_helpers.rs @@ -239,7 +239,7 @@ impl<'a> Input<'a> { self.as_str(), output.as_ref().as_str(), actual, - reparsed_ast_normalized + reparsed_ast ); } diff --git a/crates/compiler/test_syntax/tests/snapshots/fail/nested_tuples_annotation_terrible_perf.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/fail/nested_tuples_annotation_terrible_perf.expr.result-ast new file mode 100644 index 0000000000..dfa8868018 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/fail/nested_tuples_annotation_terrible_perf.expr.result-ast @@ -0,0 +1 @@ +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) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/fail/nested_tuples_annotation_terrible_perf.expr.roc b/crates/compiler/test_syntax/tests/snapshots/fail/nested_tuples_annotation_terrible_perf.expr.roc new file mode 100644 index 0000000000..97d5a05d6c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/fail/nested_tuples_annotation_terrible_perf.expr.roc @@ -0,0 +1 @@ +.:(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[] \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_ann_in_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/alias_ann_in_parens.expr.formatted.roc new file mode 100644 index 0000000000..869bf9d3b5 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_ann_in_parens.expr.formatted.roc @@ -0,0 +1,2 @@ +M : r +h \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_ann_in_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/alias_ann_in_parens.expr.result-ast new file mode 100644 index 0000000000..eecf4d943e --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_ann_in_parens.expr.result-ast @@ -0,0 +1,43 @@ +Defs( + Defs { + tags: [ + EitherIndex(0), + ], + regions: [ + @0-6, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_ann_in_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/alias_ann_in_parens.expr.roc new file mode 100644 index 0000000000..9d636018cf --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_ann_in_parens.expr.roc @@ -0,0 +1,3 @@ +M:( +r) +h \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_comment_after_head.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/alias_comment_after_head.expr.formatted.roc new file mode 100644 index 0000000000..9e90399a25 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_comment_after_head.expr.formatted.roc @@ -0,0 +1,3 @@ +A # + p : e +A \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_comment_after_head.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/alias_comment_after_head.expr.result-ast new file mode 100644 index 0000000000..9ba579e7dc --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_comment_after_head.expr.result-ast @@ -0,0 +1,48 @@ +Defs( + Defs { + tags: [ + EitherIndex(0), + ], + regions: [ + @0-7, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_comment_after_head.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/alias_comment_after_head.expr.roc new file mode 100644 index 0000000000..f2a502371d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_comment_after_head.expr.roc @@ -0,0 +1,3 @@ +A# + p:e +A \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment.expr.formatted.roc new file mode 100644 index 0000000000..1256b0f5a8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment.expr.formatted.roc @@ -0,0 +1,3 @@ +K : # + s +K \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment.expr.result-ast new file mode 100644 index 0000000000..76ff0140da --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment.expr.result-ast @@ -0,0 +1,44 @@ +Defs( + Defs { + tags: [ + EitherIndex(0), + ], + regions: [ + @0-7, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment.expr.roc new file mode 100644 index 0000000000..46ea649312 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment.expr.roc @@ -0,0 +1,3 @@ +K:(# +s) +K \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment_indent.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment_indent.expr.formatted.roc new file mode 100644 index 0000000000..8c1f3b9104 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment_indent.expr.formatted.roc @@ -0,0 +1,4 @@ +O : O z +# + +b # \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment_indent.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment_indent.expr.result-ast new file mode 100644 index 0000000000..324afb4bb8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment_indent.expr.result-ast @@ -0,0 +1,59 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(0), + ], + regions: [ + @0-9, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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( + "", + ), + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment_indent.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment_indent.expr.roc new file mode 100644 index 0000000000..2c607ec800 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/alias_parens_comment_indent.expr.roc @@ -0,0 +1,4 @@ +O:O(z +# +) +b# \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/all_the_bangs.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/all_the_bangs.expr.formatted.roc new file mode 100644 index 0000000000..c61275fdf6 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/all_the_bangs.expr.formatted.roc @@ -0,0 +1,2 @@ +p +! .p!! \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/all_the_bangs.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/all_the_bangs.expr.result-ast new file mode 100644 index 0000000000..2ef0406f61 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/all_the_bangs.expr.result-ast @@ -0,0 +1,47 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-1, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/all_the_bangs.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/all_the_bangs.expr.roc new file mode 100644 index 0000000000..a73d30e9bf --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/all_the_bangs.expr.roc @@ -0,0 +1,3 @@ +p +! +.p!! \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/ann_parens_comments.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/ann_parens_comments.expr.formatted.roc new file mode 100644 index 0000000000..020f882e98 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/ann_parens_comments.expr.formatted.roc @@ -0,0 +1,6 @@ +r : + r +# +# + +h \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/ann_parens_comments.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/ann_parens_comments.expr.result-ast new file mode 100644 index 0000000000..3848bb0653 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/ann_parens_comments.expr.result-ast @@ -0,0 +1,58 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-11, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/ann_parens_comments.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/ann_parens_comments.expr.roc new file mode 100644 index 0000000000..6938130c55 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/ann_parens_comments.expr.roc @@ -0,0 +1,6 @@ +r:( +r +# +# +) +h diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/ann_record_pat_with_comment.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/ann_record_pat_with_comment.expr.formatted.roc new file mode 100644 index 0000000000..33a0452484 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/ann_record_pat_with_comment.expr.formatted.roc @@ -0,0 +1,3 @@ +{ l: s # +} : s +o \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/ann_record_pat_with_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/ann_record_pat_with_comment.expr.result-ast new file mode 100644 index 0000000000..fb980291b2 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/ann_record_pat_with_comment.expr.result-ast @@ -0,0 +1,51 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-9, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/ann_record_pat_with_comment.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/ann_record_pat_with_comment.expr.roc new file mode 100644 index 0000000000..c828caccc8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/ann_record_pat_with_comment.expr.roc @@ -0,0 +1,3 @@ +{l# +:s}:s +o \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/ann_tag_union_newline_comment.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/ann_tag_union_newline_comment.expr.formatted.roc new file mode 100644 index 0000000000..6ff6f4f630 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/ann_tag_union_newline_comment.expr.formatted.roc @@ -0,0 +1,4 @@ +k : [ + T, +]m # +D \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/ann_tag_union_newline_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/ann_tag_union_newline_comment.expr.result-ast new file mode 100644 index 0000000000..385ccad45a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/ann_tag_union_newline_comment.expr.result-ast @@ -0,0 +1,58 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-9, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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( + "", + ), + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/ann_tag_union_newline_comment.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/ann_tag_union_newline_comment.expr.roc new file mode 100644 index 0000000000..60c1edd661 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/ann_tag_union_newline_comment.expr.roc @@ -0,0 +1,4 @@ +k: +[T, +]m# +D \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotate_tuple_func.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotate_tuple_func.expr.formatted.roc new file mode 100644 index 0000000000..8e092a05b1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotate_tuple_func.expr.formatted.roc @@ -0,0 +1,5 @@ +1 : ( + f, + (ww -> p), +)e +Mh \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotate_tuple_func.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/annotate_tuple_func.expr.result-ast new file mode 100644 index 0000000000..8eb2143f17 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotate_tuple_func.expr.result-ast @@ -0,0 +1,61 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-13, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotate_tuple_func.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotate_tuple_func.expr.roc new file mode 100644 index 0000000000..762fe3c733 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotate_tuple_func.expr.roc @@ -0,0 +1,3 @@ +1:(f +,ww->p)e +Mh \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.formatted.roc new file mode 100644 index 0000000000..5834f91713 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.formatted.roc @@ -0,0 +1,3 @@ +E : B +{} = B +B \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.result-ast new file mode 100644 index 0000000000..088733fb63 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.result-ast @@ -0,0 +1,50 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-8, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.roc new file mode 100644 index 0000000000..03a35bcd46 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotated_empty_record_destructure.expr.roc @@ -0,0 +1,3 @@ +E:B +{}=B +B \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_apply_newlines.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_apply_newlines.expr.formatted.roc new file mode 100644 index 0000000000..525a3b4bfc --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_apply_newlines.expr.formatted.roc @@ -0,0 +1,2 @@ +A p : e +A \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_apply_newlines.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_apply_newlines.expr.result-ast new file mode 100644 index 0000000000..aebe7e8593 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_apply_newlines.expr.result-ast @@ -0,0 +1,51 @@ +Defs( + Defs { + tags: [ + EitherIndex(0), + ], + regions: [ + @0-7, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_apply_newlines.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_apply_newlines.expr.roc new file mode 100644 index 0000000000..f414f3d1e3 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_apply_newlines.expr.roc @@ -0,0 +1,4 @@ +A + p: +e +A \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_comment_before_colon.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_comment_before_colon.expr.formatted.roc new file mode 100644 index 0000000000..61a65c9a66 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_comment_before_colon.expr.formatted.roc @@ -0,0 +1,3 @@ +A e # g + : A +AA \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_comment_before_colon.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_comment_before_colon.expr.result-ast new file mode 100644 index 0000000000..bf989377f4 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_comment_before_colon.expr.result-ast @@ -0,0 +1,55 @@ +Defs( + Defs { + tags: [ + EitherIndex(0), + ], + regions: [ + @0-9, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_comment_before_colon.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_comment_before_colon.expr.roc new file mode 100644 index 0000000000..56ebd69d3a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_comment_before_colon.expr.roc @@ -0,0 +1,4 @@ +A + e#g +:A +AA \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_comment.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_comment.expr.formatted.roc new file mode 100644 index 0000000000..d3b16c84ac --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_comment.expr.formatted.roc @@ -0,0 +1,5 @@ +3 : + ( # + )n + -> n +0 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_comment.expr.result-ast new file mode 100644 index 0000000000..15063d577f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_comment.expr.result-ast @@ -0,0 +1,56 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-10, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_comment.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_comment.expr.roc new file mode 100644 index 0000000000..7fee023c92 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_comment.expr.roc @@ -0,0 +1,3 @@ +3:(# +)n->n +0 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_newline.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_newline.expr.formatted.roc new file mode 100644 index 0000000000..7310dda3ff --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_newline.expr.formatted.roc @@ -0,0 +1,4 @@ +d : ( + J, +)g +2 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_newline.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_newline.expr.result-ast new file mode 100644 index 0000000000..2083437163 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_newline.expr.result-ast @@ -0,0 +1,52 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-8, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_newline.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_newline.expr.roc new file mode 100644 index 0000000000..2938db91c4 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_newline.expr.roc @@ -0,0 +1,3 @@ +d:(J, +)g +2 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_parens_newlines.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_parens_newlines.expr.formatted.roc new file mode 100644 index 0000000000..4c72df30a0 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_parens_newlines.expr.formatted.roc @@ -0,0 +1,4 @@ +p : ( +)( + i) +{} \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_parens_newlines.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_parens_newlines.expr.result-ast new file mode 100644 index 0000000000..3fec134ee7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_parens_newlines.expr.result-ast @@ -0,0 +1,51 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-9, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_parens_newlines.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_parens_newlines.expr.roc new file mode 100644 index 0000000000..a781da7a8c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/annotation_tuple_parens_newlines.expr.roc @@ -0,0 +1,4 @@ +p:( +)( +i) +{} \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/applies_in_binop.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/applies_in_binop.expr.formatted.roc new file mode 100644 index 0000000000..95f4944619 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/applies_in_binop.expr.formatted.roc @@ -0,0 +1,3 @@ +Str.getUnsafe haystack haystackIndex +== +Str.getUnsafe needle needleIndex \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/applies_in_binop.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/applies_in_binop.expr.result-ast new file mode 100644 index 0000000000..b261a4dc0f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/applies_in_binop.expr.result-ast @@ -0,0 +1,56 @@ +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, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/applies_in_binop.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/applies_in_binop.expr.roc new file mode 100644 index 0000000000..ee8a202625 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/applies_in_binop.expr.roc @@ -0,0 +1,3 @@ +Str.getUnsafe haystack haystackIndex +== +Str.getUnsafe needle needleIndex diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_binop_switch.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_binop_switch.expr.formatted.roc new file mode 100644 index 0000000000..47d2994151 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_binop_switch.expr.formatted.roc @@ -0,0 +1,2 @@ +i < 2 +-6 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_binop_switch.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/apply_binop_switch.expr.result-ast new file mode 100644 index 0000000000..c39926426f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_binop_switch.expr.result-ast @@ -0,0 +1,51 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-3, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_binop_switch.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_binop_switch.expr.roc new file mode 100644 index 0000000000..df21d9308c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_binop_switch.expr.roc @@ -0,0 +1,2 @@ +i<2 +(-6) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_closure_pizza.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_closure_pizza.expr.formatted.roc new file mode 100644 index 0000000000..836ea6495f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_closure_pizza.expr.formatted.roc @@ -0,0 +1,2 @@ +foo +|> Dict.keepIf \(k, _v) -> List.contains keysToDelete k |> Bool.not \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_closure_pizza.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/apply_closure_pizza.expr.result-ast new file mode 100644 index 0000000000..1d2fa43441 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_closure_pizza.expr.result-ast @@ -0,0 +1,72 @@ +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, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_closure_pizza.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_closure_pizza.expr.roc new file mode 100644 index 0000000000..26042cfa46 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_closure_pizza.expr.roc @@ -0,0 +1,2 @@ +foo +|> Dict.keepIf \(k, _v) -> List.contains keysToDelete k |> Bool.not diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_record_ann.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_record_ann.expr.formatted.roc new file mode 100644 index 0000000000..63e7dabd0d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_record_ann.expr.formatted.roc @@ -0,0 +1,5 @@ +a : + N { + h, + } +g \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_record_ann.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/apply_record_ann.expr.result-ast new file mode 100644 index 0000000000..523172ef16 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_record_ann.expr.result-ast @@ -0,0 +1,58 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-8, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/apply_record_ann.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/apply_record_ann.expr.roc new file mode 100644 index 0000000000..ead858c443 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/apply_record_ann.expr.roc @@ -0,0 +1,3 @@ +a:N{h, +} +g diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/backpassing_bananza.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/backpassing_bananza.expr.formatted.roc new file mode 100644 index 0000000000..b50df3b3d5 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/backpassing_bananza.expr.formatted.roc @@ -0,0 +1,4 @@ +ex <- f # +s # q + <- f # +s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/backpassing_bananza.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/backpassing_bananza.expr.result-ast new file mode 100644 index 0000000000..853c82c410 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/backpassing_bananza.expr.result-ast @@ -0,0 +1,52 @@ +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, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/backpassing_bananza.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/backpassing_bananza.expr.roc new file mode 100644 index 0000000000..d36d029263 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/backpassing_bananza.expr.roc @@ -0,0 +1,5 @@ + +ex<-f# +s#q +<-f# +s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/bang_newline_double_accessor.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/bang_newline_double_accessor.expr.formatted.roc new file mode 100644 index 0000000000..18db8ffa41 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/bang_newline_double_accessor.expr.formatted.roc @@ -0,0 +1,3 @@ +0 +! .d +.d \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/bang_newline_double_accessor.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/bang_newline_double_accessor.expr.result-ast new file mode 100644 index 0000000000..271732b0e7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/bang_newline_double_accessor.expr.result-ast @@ -0,0 +1,56 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + EitherIndex(2147483649), + ], + regions: [ + @0-1, + @2-6, + ], + space_before: [ + Slice { start: 0, length: 0 }, + Slice { start: 0, length: 1 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/bang_newline_double_accessor.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/bang_newline_double_accessor.expr.roc new file mode 100644 index 0000000000..2d2d7e0aba --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/bang_newline_double_accessor.expr.roc @@ -0,0 +1,4 @@ +0 +! +.d +.d \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/binop_apply_complex.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/binop_apply_complex.expr.formatted.roc new file mode 100644 index 0000000000..c2645f2964 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/binop_apply_complex.expr.formatted.roc @@ -0,0 +1 @@ +N < l (r * N) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/binop_apply_complex.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/binop_apply_complex.expr.result-ast new file mode 100644 index 0000000000..18efde9439 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/binop_apply_complex.expr.result-ast @@ -0,0 +1,40 @@ +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, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/binop_apply_complex.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/binop_apply_complex.expr.roc new file mode 100644 index 0000000000..83324e5c04 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/binop_apply_complex.expr.roc @@ -0,0 +1 @@ +N { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), + ), + ), + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/binop_assign_defs_nested.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/binop_assign_defs_nested.expr.roc new file mode 100644 index 0000000000..40f10a7dff --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/binop_assign_defs_nested.expr.roc @@ -0,0 +1,3 @@ +5-((e=(( +r)) +1)) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/block_string_ann.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/block_string_ann.expr.formatted.roc new file mode 100644 index 0000000000..6dcec3e360 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/block_string_ann.expr.formatted.roc @@ -0,0 +1,2 @@ +"$(g)" : q +f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/block_string_ann.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/block_string_ann.expr.result-ast new file mode 100644 index 0000000000..69bd9a75c8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/block_string_ann.expr.result-ast @@ -0,0 +1,51 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-12, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/block_string_ann.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/block_string_ann.expr.roc new file mode 100644 index 0000000000..d02c902bc9 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/block_string_ann.expr.roc @@ -0,0 +1,2 @@ +"""$(g)""":q +f diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/body_block_string_apply_string.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/body_block_string_apply_string.expr.formatted.roc new file mode 100644 index 0000000000..1872d0386b --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/body_block_string_apply_string.expr.formatted.roc @@ -0,0 +1,6 @@ +t = + """ + " + """ + "" +S \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/body_block_string_apply_string.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/body_block_string_apply_string.expr.result-ast new file mode 100644 index 0000000000..7757853c1c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/body_block_string_apply_string.expr.result-ast @@ -0,0 +1,48 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-12, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/body_block_string_apply_string.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/body_block_string_apply_string.expr.roc new file mode 100644 index 0000000000..543728a347 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/body_block_string_apply_string.expr.roc @@ -0,0 +1,2 @@ +t="""" """"" +S \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/body_with_unneeded_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/body_with_unneeded_parens.expr.formatted.roc new file mode 100644 index 0000000000..8c233013ad --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/body_with_unneeded_parens.expr.formatted.roc @@ -0,0 +1,3 @@ +a = + 6 +a \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/body_with_unneeded_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/body_with_unneeded_parens.expr.result-ast new file mode 100644 index 0000000000..ae74b7a280 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/body_with_unneeded_parens.expr.result-ast @@ -0,0 +1,44 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-6, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { 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, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/body_with_unneeded_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/body_with_unneeded_parens.expr.roc new file mode 100644 index 0000000000..df1f7bd089 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/body_with_unneeded_parens.expr.roc @@ -0,0 +1,3 @@ +a=( +6) +a \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_apply_in_binop.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_apply_in_binop.expr.formatted.roc new file mode 100644 index 0000000000..5cfdcd614c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_apply_in_binop.expr.formatted.roc @@ -0,0 +1,2 @@ +m0 \w -> w? e +/ s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_apply_in_binop.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_apply_in_binop.expr.result-ast new file mode 100644 index 0000000000..a38c1c233c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_apply_in_binop.expr.result-ast @@ -0,0 +1,48 @@ +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", + }, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_apply_in_binop.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_apply_in_binop.expr.roc new file mode 100644 index 0000000000..7f2e9bd2aa --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_apply_in_binop.expr.roc @@ -0,0 +1,2 @@ +m0\w->w?e +/s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_binop_with_spaces.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_binop_with_spaces.expr.formatted.roc index f44f1344c3..263baae2b4 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_binop_with_spaces.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_binop_with_spaces.expr.formatted.roc @@ -1,4 +1,2 @@ -i -> (\s -> s -) - -a \ No newline at end of file +i > \s -> s +-a \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_binop_with_spaces.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_binop_with_spaces.expr.result-ast index 8f28d9c753..33a1b5c16e 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_binop_with_spaces.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/closure_in_binop_with_spaces.expr.result-ast @@ -1,39 +1,56 @@ -BinOps( - [ - ( - @0-1 Var { - module_name: "", - ident: "i", - }, - @1-2 GreaterThan, - ), - ], - @2-10 Apply( - @2-7 SpaceAfter( - Closure( - [ - @3-4 Identifier { - ident: "s", - }, - ], - @6-7 Var { - module_name: "", - ident: "s", - }, - ), - [ - Newline, - ], - ), - [ - @8-10 UnaryOp( - @9-10 Var { - module_name: "", - ident: "a", - }, - @8-9 Negate, +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-7, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-7 BinOps( + [ + ( + @0-1 Var { + module_name: "", + ident: "i", + }, + @1-2 GreaterThan, + ), + ], + @2-7 Closure( + [ + @3-4 Identifier { + ident: "s", + }, + ], + @6-7 Var { + module_name: "", + ident: "s", + }, + ), + ), ), ], - Space, + }, + @8-10 SpaceBefore( + UnaryOp( + @9-10 Var { + module_name: "", + ident: "a", + }, + @8-9 Negate, + ), + [ + Newline, + ], ), ) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comma_prefixed_indented_record.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/comma_prefixed_indented_record.expr.result-ast index 46c57cca11..66eb2cd1e9 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/comma_prefixed_indented_record.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comma_prefixed_indented_record.expr.result-ast @@ -24,91 +24,96 @@ SpaceAfter( }, ], }, - ann: @21-164 Record { - fields: [ - @23-47 SpaceAfter( - RequiredValue( - @23-32 "evaluated", - [], - @35-47 Apply( - "", - "Set", - [ - @39-47 BoundVariable( - "position", - ), - ], + ann: @21-164 SpaceBefore( + Record { + fields: [ + @23-47 SpaceAfter( + RequiredValue( + @23-32 "evaluated", + [], + @35-47 Apply( + "", + "Set", + [ + @39-47 BoundVariable( + "position", + ), + ], + ), ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - @54-76 SpaceAfter( - RequiredValue( - @54-61 "openSet", - [], - @64-76 Apply( - "", - "Set", - [ - @68-76 BoundVariable( - "position", - ), - ], + @54-76 SpaceAfter( + RequiredValue( + @54-61 "openSet", + [], + @64-76 Apply( + "", + "Set", + [ + @68-76 BoundVariable( + "position", + ), + ], + ), ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - @83-113 SpaceAfter( - RequiredValue( - @83-88 "costs", - [], - @91-113 Apply( - "Dict", - "Dict", - [ - @101-109 BoundVariable( - "position", - ), - @110-113 Apply( - "", - "F64", - [], - ), - ], + @83-113 SpaceAfter( + RequiredValue( + @83-88 "costs", + [], + @91-113 Apply( + "Dict", + "Dict", + [ + @101-109 BoundVariable( + "position", + ), + @110-113 Apply( + "", + "F64", + [], + ), + ], + ), ), + [ + Newline, + ], ), - [ - Newline, - ], - ), - @120-158 SpaceAfter( - RequiredValue( - @120-128 "cameFrom", - [], - @131-158 Apply( - "Dict", - "Dict", - [ - @141-149 BoundVariable( - "position", - ), - @150-158 BoundVariable( - "position", - ), - ], + @120-158 SpaceAfter( + RequiredValue( + @120-128 "cameFrom", + [], + @131-158 Apply( + "Dict", + "Dict", + [ + @141-149 BoundVariable( + "position", + ), + @150-158 BoundVariable( + "position", + ), + ], + ), ), + [ + Newline, + ], ), - [ - Newline, - ], - ), + ], + ext: None, + }, + [ + Newline, ], - ext: None, - }, + ), }, ], value_defs: [], diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_before_pat_in_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_before_pat_in_parens.expr.formatted.roc new file mode 100644 index 0000000000..441ea0a893 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_before_pat_in_parens.expr.formatted.roc @@ -0,0 +1,3 @@ +# +6 : s +h \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_before_pat_in_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/comment_before_pat_in_parens.expr.result-ast new file mode 100644 index 0000000000..bb7bf263dd --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_before_pat_in_parens.expr.result-ast @@ -0,0 +1,50 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-8, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @4-5 SpaceBefore( + NumLiteral( + "6", + ), + [ + Newline, + LineComment( + "", + ), + ], + ), + @7-8 BoundVariable( + "s", + ), + ), + ], + }, + @9-10 SpaceBefore( + Var { + module_name: "", + ident: "h", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_before_pat_in_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_before_pat_in_parens.expr.roc new file mode 100644 index 0000000000..e2819c2447 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_before_pat_in_parens.expr.roc @@ -0,0 +1,4 @@ +( +# +6):s +h diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_backpassing_args.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_backpassing_args.expr.formatted.roc new file mode 100644 index 0000000000..265ee78e3f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_backpassing_args.expr.formatted.roc @@ -0,0 +1,5 @@ +a, + (M # + c) + <- t +a \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_backpassing_args.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_backpassing_args.expr.result-ast new file mode 100644 index 0000000000..42a81514fd --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_backpassing_args.expr.result-ast @@ -0,0 +1,37 @@ +Backpassing( + [ + @0-1 Identifier { + ident: "a", + }, + @2-6 Apply( + @2-3 Tag( + "M", + ), + [ + @5-6 SpaceBefore( + Identifier { + ident: "c", + }, + [ + LineComment( + "", + ), + ], + ), + ], + ), + ], + @8-9 Var { + module_name: "", + ident: "t", + }, + @10-11 SpaceBefore( + Var { + module_name: "", + ident: "a", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_backpassing_args.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_backpassing_args.expr.roc new file mode 100644 index 0000000000..8bedbac5bb --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_backpassing_args.expr.roc @@ -0,0 +1,3 @@ +a,M# +c<-t +a \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.formatted.roc new file mode 100644 index 0000000000..2805fd0029 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.formatted.roc @@ -0,0 +1,3 @@ +\L # + i + -> -e \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.result-ast new file mode 100644 index 0000000000..2b2651a46d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.result-ast @@ -0,0 +1,28 @@ +Closure( + [ + @1-6 Apply( + @1-2 Tag( + "L", + ), + [ + @5-6 SpaceBefore( + Identifier { + ident: "i", + }, + [ + LineComment( + "", + ), + ], + ), + ], + ), + ], + @8-10 UnaryOp( + @9-10 Var { + module_name: "", + ident: "e", + }, + @8-9 Negate, + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.roc new file mode 100644 index 0000000000..229d292f63 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat.expr.roc @@ -0,0 +1,2 @@ +\L# + i->-e \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.formatted.roc new file mode 100644 index 0000000000..cb606517d6 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.formatted.roc @@ -0,0 +1,4 @@ +\L, + M # + Q + -> f8 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.result-ast new file mode 100644 index 0000000000..248f7a235d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.result-ast @@ -0,0 +1,28 @@ +Closure( + [ + @1-2 Tag( + "L", + ), + @3-8 Apply( + @3-4 Tag( + "M", + ), + [ + @7-8 SpaceBefore( + Tag( + "Q", + ), + [ + LineComment( + "", + ), + ], + ), + ], + ), + ], + @10-12 Var { + module_name: "", + ident: "f8", + }, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.roc new file mode 100644 index 0000000000..323bca27d3 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_in_closure_pat_apply.expr.roc @@ -0,0 +1,2 @@ +\L,M# + Q->f8 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.formatted.roc new file mode 100644 index 0000000000..51e264b710 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.formatted.roc @@ -0,0 +1,4 @@ +1 0 # +# + : gi +M \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.result-ast new file mode 100644 index 0000000000..b6b9223b82 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.result-ast @@ -0,0 +1,53 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-13, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-1 Apply( + @0-1 NumLiteral( + "1", + ), + [ + @2-7 SpaceAfter( + NumLiteral( + "0", + ), + [ + LineComment( + "", + ), + LineComment( + "", + ), + ], + ), + ], + ), + @11-13 BoundVariable( + "gi", + ), + ), + ], + }, + @14-15 SpaceBefore( + Tag( + "M", + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.roc new file mode 100644 index 0000000000..5ae4f717a8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/comment_indent_in_parens.expr.roc @@ -0,0 +1,4 @@ +1((0# +)# +):gi +M \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/compare_apply_record.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/compare_apply_record.expr.formatted.roc new file mode 100644 index 0000000000..6470886af5 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/compare_apply_record.expr.formatted.roc @@ -0,0 +1,6 @@ +x +> +x { + +} +< r \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/compare_apply_record.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/compare_apply_record.expr.result-ast new file mode 100644 index 0000000000..72652d7fbe --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/compare_apply_record.expr.result-ast @@ -0,0 +1,46 @@ +SpaceAfter( + BinOps( + [ + ( + @0-1 Var { + module_name: "", + ident: "x", + }, + @1-2 GreaterThan, + ), + ( + @3-8 Apply( + @3-4 SpaceBefore( + Var { + module_name: "", + ident: "x", + }, + [ + Newline, + ], + ), + [ + @4-8 Record( + Collection { + items: [], + final_comments: [ + Newline, + Newline, + ], + }, + ), + ], + Space, + ), + @8-9 LessThan, + ), + ], + @9-10 Var { + module_name: "", + ident: "r", + }, + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/compare_apply_record.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/compare_apply_record.expr.roc new file mode 100644 index 0000000000..9923666144 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/compare_apply_record.expr.roc @@ -0,0 +1,4 @@ +x> +x{ + +} { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-1 Apply( + @0-1 NumLiteral( + "1", + ), + [ + @2-11 SpaceAfter( + Apply( + @3-4 NumLiteral( + "0", + ), + [ + @7-8 SpaceBefore( + NumLiteral( + "0", + ), + [ + LineComment( + "", + ), + ], + ), + ], + ), + [ + Newline, + ], + ), + @12-13 Identifier { + ident: "f", + }, + ], + ), + @14-15 BoundVariable( + "f", + ), + ), + ], + }, + @16-17 SpaceBefore( + Var { + module_name: "", + ident: "t", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.roc new file mode 100644 index 0000000000..97eda2719b --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left.expr.roc @@ -0,0 +1,4 @@ +1((0(# +0) +))f:f +t diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.formatted.roc new file mode 100644 index 0000000000..d7d9effcad --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.formatted.roc @@ -0,0 +1,6 @@ +1 (ts 0) + + # + + f : i7f +e \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.result-ast new file mode 100644 index 0000000000..afed0988b7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.result-ast @@ -0,0 +1,68 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-20, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-1 Apply( + @0-1 NumLiteral( + "1", + ), + [ + @2-13 SpaceAfter( + Apply( + @2-4 Identifier { + ident: "ts", + }, + [ + @5-9 SpaceAfter( + NumLiteral( + "0", + ), + [ + Newline, + Newline, + LineComment( + "", + ), + ], + ), + ], + ), + [ + Newline, + ], + ), + @15-16 Identifier { + ident: "f", + }, + ], + ), + @17-20 BoundVariable( + "i7f", + ), + ), + ], + }, + @21-22 SpaceBefore( + Var { + module_name: "", + ident: "e", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.roc new file mode 100644 index 0000000000..a53ecb8cbf --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_annotation_left2.expr.roc @@ -0,0 +1,6 @@ +1(ts((0 +) +# +) +)f:i7f +e \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_backpassing_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_backpassing_parens.expr.formatted.roc new file mode 100644 index 0000000000..fc7dfb3726 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_backpassing_parens.expr.formatted.roc @@ -0,0 +1,4 @@ +( + M0 <- f + 1) +1 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_backpassing_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_backpassing_parens.expr.result-ast new file mode 100644 index 0000000000..2aa664224d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_backpassing_parens.expr.result-ast @@ -0,0 +1,63 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-10, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-10 ParensAround( + SpaceBefore( + Backpassing( + [ + @2-4 Tag( + "M0", + ), + ], + @6-7 Var { + module_name: "", + ident: "f", + }, + @8-9 SpaceBefore( + Num( + "1", + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], + ), + ), + ), + ], + }, + @11-15 SpaceBefore( + ParensAround( + SpaceBefore( + Num( + "1", + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_backpassing_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_backpassing_parens.expr.roc new file mode 100644 index 0000000000..c994b5e17a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_backpassing_parens.expr.roc @@ -0,0 +1,5 @@ +( +M0<-f +1) +( +1) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.formatted.roc new file mode 100644 index 0000000000..c884366eca --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.formatted.roc @@ -0,0 +1,4 @@ +0 + # + f : f +t \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.result-ast new file mode 100644 index 0000000000..b0c55ee11f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.result-ast @@ -0,0 +1,57 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-15, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @1-11 Apply( + @1-11 SpaceAfter( + NumLiteral( + "0", + ), + [ + Newline, + LineComment( + "", + ), + ], + ), + [ + @12-13 Identifier { + ident: "f", + }, + ], + ), + @14-15 BoundVariable( + "f", + ), + ), + ], + }, + @16-17 SpaceBefore( + Var { + module_name: "", + ident: "t", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.roc new file mode 100644 index 0000000000..be60d7ee37 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/crazy_pat_ann.expr.roc @@ -0,0 +1,4 @@ +((((0) +)# +))f:f +t diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double.expr.formatted.roc new file mode 100644 index 0000000000..d9323c5bf7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double.expr.formatted.roc @@ -0,0 +1 @@ +dbg dbg g g \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double.expr.result-ast new file mode 100644 index 0000000000..18725d92d9 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double.expr.result-ast @@ -0,0 +1,20 @@ +SpaceAfter( + Apply( + @0-3 Dbg, + [ + @4-7 Dbg, + @8-9 Var { + module_name: "", + ident: "g", + }, + @10-11 Var { + module_name: "", + ident: "g", + }, + ], + Space, + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double.expr.roc new file mode 100644 index 0000000000..2dabf8b716 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double.expr.roc @@ -0,0 +1 @@ +dbg dbg g g diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double_newline.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double_newline.expr.formatted.roc new file mode 100644 index 0000000000..29f8417298 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double_newline.expr.formatted.roc @@ -0,0 +1,4 @@ +dbg + dbg + a + g \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double_newline.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double_newline.expr.result-ast new file mode 100644 index 0000000000..df23ed33a1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double_newline.expr.result-ast @@ -0,0 +1,20 @@ +Apply( + @0-3 Dbg, + [ + @4-7 Dbg, + @9-10 SpaceBefore( + Var { + module_name: "", + ident: "a", + }, + [ + Newline, + ], + ), + @11-12 Var { + module_name: "", + ident: "g", + }, + ], + Space, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double_newline.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double_newline.expr.roc new file mode 100644 index 0000000000..6c04b8dfc7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_double_newline.expr.roc @@ -0,0 +1,2 @@ +dbg dbg + a g \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_extra_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_extra_parens.expr.formatted.roc new file mode 100644 index 0000000000..98a080d361 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_extra_parens.expr.formatted.roc @@ -0,0 +1,2 @@ +dbg d z +dd \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_extra_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_extra_parens.expr.result-ast new file mode 100644 index 0000000000..2a050b9212 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_extra_parens.expr.result-ast @@ -0,0 +1,53 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-11, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @0-3 RecordDestructure( + Collection { + items: [], + final_comments: [ + Newline, + ], + }, + ), + @4-11 Apply( + @4-7 Dbg, + [ + @8-9 Var { + module_name: "", + ident: "d", + }, + @10-11 Var { + module_name: "", + ident: "z", + }, + ], + Space, + ), + ), + ], + }, + @12-14 SpaceBefore( + Var { + module_name: "", + ident: "dd", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_extra_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_extra_parens.expr.roc new file mode 100644 index 0000000000..18eb8235a8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_extra_parens.expr.roc @@ -0,0 +1,3 @@ +{ +}=dbg d z +dd \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_newline_apply.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_newline_apply.expr.formatted.roc new file mode 100644 index 0000000000..944a69b877 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_newline_apply.expr.formatted.roc @@ -0,0 +1,4 @@ +dbg + + izzb + interfacesb \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_newline_apply.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_newline_apply.expr.result-ast new file mode 100644 index 0000000000..4f17def97a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_newline_apply.expr.result-ast @@ -0,0 +1,30 @@ +SpaceAfter( + Apply( + @0-3 Dbg, + [ + @6-10 SpaceBefore( + Var { + module_name: "", + ident: "izzb", + }, + [ + Newline, + Newline, + ], + ), + @13-24 SpaceBefore( + Var { + module_name: "", + ident: "interfacesb", + }, + [ + Newline, + ], + ), + ], + Space, + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_newline_apply.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_newline_apply.expr.roc new file mode 100644 index 0000000000..86addc18b8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_newline_apply.expr.roc @@ -0,0 +1,4 @@ +dbg + + izzb + interfacesb diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt.expr.formatted.roc index 9e53fc6a9a..8ee888eafb 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt.expr.formatted.roc @@ -1,3 +1,2 @@ dbg (1 == 1) - 4 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt.expr.result-ast index d6e409f5ed..28178e76b4 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt.expr.result-ast @@ -1,7 +1,7 @@ SpaceBefore( SpaceAfter( - DbgStmt( - @6-12 ParensAround( + DbgStmt { + first: @6-12 ParensAround( BinOps( [ ( @@ -16,7 +16,8 @@ SpaceBefore( ), ), ), - @15-16 SpaceBefore( + extra_args: [], + continuation: @15-16 SpaceBefore( Num( "4", ), @@ -25,7 +26,7 @@ SpaceBefore( Newline, ], ), - ), + }, [ Newline, ], diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_multiline.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_multiline.expr.formatted.roc index f6e349bd30..658e754cb4 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_multiline.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_multiline.expr.formatted.roc @@ -2,5 +2,4 @@ dbg ( 5, 666, ) - 4 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_multiline.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_multiline.expr.result-ast index 1592169153..759a03fec4 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_multiline.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_multiline.expr.result-ast @@ -1,6 +1,6 @@ SpaceAfter( - DbgStmt( - @4-16 Tuple( + DbgStmt { + first: @4-16 Tuple( [ @5-6 Num( "5", @@ -15,7 +15,8 @@ SpaceAfter( ), ], ), - @18-19 SpaceBefore( + extra_args: [], + continuation: @18-19 SpaceBefore( Num( "4", ), @@ -24,7 +25,7 @@ SpaceAfter( Newline, ], ), - ), + }, [ Newline, ], diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_two_exprs.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_two_exprs.expr.formatted.roc index dd0ca03778..1181edb3a2 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_two_exprs.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_two_exprs.expr.formatted.roc @@ -3,6 +3,5 @@ dbg q qt ) - g qt \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_two_exprs.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_two_exprs.expr.result-ast index 677c819ca1..9067980caa 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_two_exprs.expr.result-ast +++ b/crates/compiler/test_syntax/tests/snapshots/pass/dbg_stmt_two_exprs.expr.result-ast @@ -1,6 +1,6 @@ SpaceAfter( - DbgStmt( - @6-14 SpaceBefore( + DbgStmt { + first: @6-14 SpaceBefore( ParensAround( Apply( @6-7 Var { @@ -25,7 +25,8 @@ SpaceAfter( Newline, ], ), - @16-21 SpaceBefore( + extra_args: [], + continuation: @16-21 SpaceBefore( Apply( @16-17 Var { module_name: "", @@ -48,7 +49,7 @@ SpaceAfter( Newline, ], ), - ), + }, [ Newline, ], diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/def_multistring_apply.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/def_multistring_apply.expr.formatted.roc new file mode 100644 index 0000000000..6c24def9d1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/def_multistring_apply.expr.formatted.roc @@ -0,0 +1,5 @@ +e = + """ + """ + a +p \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/def_multistring_apply.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/def_multistring_apply.expr.result-ast new file mode 100644 index 0000000000..0e046a7718 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/def_multistring_apply.expr.result-ast @@ -0,0 +1,48 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-9, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @0-1 Identifier { + ident: "e", + }, + @2-9 Apply( + @2-8 Str( + Block( + [], + ), + ), + [ + @8-9 Var { + module_name: "", + ident: "a", + }, + ], + Space, + ), + ), + ], + }, + @10-11 SpaceBefore( + Var { + module_name: "", + ident: "p", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/def_multistring_apply.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/def_multistring_apply.expr.roc new file mode 100644 index 0000000000..45486291c7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/def_multistring_apply.expr.roc @@ -0,0 +1,2 @@ +e=""""""a +p \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/double_space_before.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/double_space_before.expr.formatted.roc new file mode 100644 index 0000000000..274fad495a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/double_space_before.expr.formatted.roc @@ -0,0 +1,4 @@ +1 : ( + M, +)w +ah \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/double_space_before.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/double_space_before.expr.result-ast new file mode 100644 index 0000000000..ab0701bf8d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/double_space_before.expr.result-ast @@ -0,0 +1,58 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-10, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-1 NumLiteral( + "1", + ), + @2-10 Tuple { + elems: [ + @6-7 SpaceBefore( + SpaceBefore( + Apply( + "", + "M", + [], + ), + [ + Newline, + ], + ), + [ + Newline, + ], + ), + ], + ext: Some( + @9-10 BoundVariable( + "w", + ), + ), + }, + ), + ], + }, + @11-13 SpaceBefore( + Var { + module_name: "", + ident: "ah", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/double_space_before.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/double_space_before.expr.roc new file mode 100644 index 0000000000..1998156097 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/double_space_before.expr.roc @@ -0,0 +1,4 @@ +1:( +( +M))w +ah \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assign_tag.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assign_tag.expr.formatted.roc new file mode 100644 index 0000000000..30e4fd072c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assign_tag.expr.formatted.roc @@ -0,0 +1,2 @@ +P +O \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assign_tag.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assign_tag.expr.result-ast new file mode 100644 index 0000000000..498c406c8a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assign_tag.expr.result-ast @@ -0,0 +1,41 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-6, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @0-2 RecordDestructure( + [], + ), + @5-6 SpaceBefore( + Tag( + "P", + ), + [ + Newline, + ], + ), + ), + ], + }, + @7-8 SpaceBefore( + Tag( + "O", + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assign_tag.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assign_tag.expr.roc new file mode 100644 index 0000000000..cb7e4f5494 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assign_tag.expr.roc @@ -0,0 +1,3 @@ +{}= + P +O \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assignment.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assignment.expr.formatted.roc new file mode 100644 index 0000000000..2b311ee88f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assignment.expr.formatted.roc @@ -0,0 +1,2 @@ +B +I \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assignment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assignment.expr.result-ast new file mode 100644 index 0000000000..22913295e4 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assignment.expr.result-ast @@ -0,0 +1,41 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-4, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @0-2 RecordDestructure( + [], + ), + @3-4 Tag( + "B", + ), + ), + ], + }, + @5-6 SpaceBefore( + Tag( + "I", + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assignment.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assignment.expr.roc new file mode 100644 index 0000000000..baee7b3f9f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_assignment.expr.roc @@ -0,0 +1,2 @@ +{}=B +I diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_dbg.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_dbg.expr.formatted.roc new file mode 100644 index 0000000000..463d8d140a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_dbg.expr.formatted.roc @@ -0,0 +1,2 @@ +dbg n +d \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_dbg.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_dbg.expr.result-ast new file mode 100644 index 0000000000..17a65bf30a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_dbg.expr.result-ast @@ -0,0 +1,54 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-10, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @0-3 SpaceAfter( + RecordDestructure( + Collection { + items: [], + final_comments: [ + Newline, + ], + }, + ), + [ + Newline, + ], + ), + @5-10 Apply( + @5-8 Dbg, + [ + @9-10 Var { + module_name: "", + ident: "n", + }, + ], + Space, + ), + ), + ], + }, + @11-12 SpaceBefore( + Var { + module_name: "", + ident: "d", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_dbg.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_dbg.expr.roc new file mode 100644 index 0000000000..33ec0420d1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_dbg.expr.roc @@ -0,0 +1,4 @@ +{ +} +=dbg n +d \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_newlines_doubleeq.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_newlines_doubleeq.expr.formatted.roc new file mode 100644 index 0000000000..37c71a1142 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_newlines_doubleeq.expr.formatted.roc @@ -0,0 +1,4 @@ +d +== +g +d \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_newlines_doubleeq.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_newlines_doubleeq.expr.result-ast new file mode 100644 index 0000000000..51cffd9d7a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_newlines_doubleeq.expr.result-ast @@ -0,0 +1,64 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-11, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @0-3 SpaceAfter( + RecordDestructure( + Collection { + items: [], + final_comments: [ + Newline, + ], + }, + ), + [ + Newline, + ], + ), + @5-11 BinOps( + [ + ( + @5-6 Var { + module_name: "", + ident: "d", + }, + @6-8 Equals, + ), + ], + @10-11 SpaceBefore( + Var { + module_name: "", + ident: "g", + }, + [ + Newline, + ], + ), + ), + ), + ], + }, + @12-13 SpaceBefore( + Var { + module_name: "", + ident: "d", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_newlines_doubleeq.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_newlines_doubleeq.expr.roc new file mode 100644 index 0000000000..c6205c776b --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_eq_newlines_doubleeq.expr.roc @@ -0,0 +1,5 @@ +{ +} +=d== + g +d \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_newline_assign.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_newline_assign.expr.formatted.roc new file mode 100644 index 0000000000..8df9830e9a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_newline_assign.expr.formatted.roc @@ -0,0 +1,2 @@ +{} +I \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_newline_assign.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_newline_assign.expr.result-ast new file mode 100644 index 0000000000..f8006f79bc --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_newline_assign.expr.result-ast @@ -0,0 +1,46 @@ +SpaceBefore( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @1-8, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @1-3 SpaceAfter( + RecordDestructure( + [], + ), + [ + Newline, + ], + ), + @6-8 Record( + [], + ), + ), + ], + }, + @9-10 SpaceBefore( + Tag( + "I", + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_newline_assign.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_newline_assign.expr.roc new file mode 100644 index 0000000000..582200fa59 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/empty_record_newline_assign.expr.roc @@ -0,0 +1,4 @@ + +{} +={} +I \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/f_not_not_f.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/f_not_not_f.expr.formatted.roc new file mode 100644 index 0000000000..b77c02f58c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/f_not_not_f.expr.formatted.roc @@ -0,0 +1,2 @@ +f +! !f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/f_not_not_f.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/f_not_not_f.expr.result-ast new file mode 100644 index 0000000000..79be5762ae --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/f_not_not_f.expr.result-ast @@ -0,0 +1,46 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-1, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-1 Var { + module_name: "", + ident: "f", + }, + ), + ], + }, + @2-6 SpaceBefore( + UnaryOp( + @4-6 SpaceBefore( + UnaryOp( + @5-6 Var { + module_name: "", + ident: "f", + }, + @4-5 Not, + ), + [ + Newline, + ], + ), + @2-3 Not, + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/f_not_not_f.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/f_not_not_f.expr.roc new file mode 100644 index 0000000000..5edd67c4a3 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/f_not_not_f.expr.roc @@ -0,0 +1,3 @@ +f +! +!f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/h_greater_comment_minus_div.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/h_greater_comment_minus_div.expr.formatted.roc new file mode 100644 index 0000000000..1111568307 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/h_greater_comment_minus_div.expr.formatted.roc @@ -0,0 +1,4 @@ +h +> # +(-h) +/ d \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/h_greater_comment_minus_div.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/h_greater_comment_minus_div.expr.result-ast new file mode 100644 index 0000000000..bc134bcfe6 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/h_greater_comment_minus_div.expr.result-ast @@ -0,0 +1,32 @@ +BinOps( + [ + ( + @0-1 Var { + module_name: "", + ident: "h", + }, + @1-2 GreaterThan, + ), + ( + @5-7 SpaceBefore( + UnaryOp( + @6-7 Var { + module_name: "", + ident: "h", + }, + @5-6 Negate, + ), + [ + LineComment( + "", + ), + ], + ), + @7-8 Slash, + ), + ], + @8-9 Var { + module_name: "", + ident: "d", + }, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/h_greater_comment_minus_div.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/h_greater_comment_minus_div.expr.roc new file mode 100644 index 0000000000..a3a626e9c9 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/h_greater_comment_minus_div.expr.roc @@ -0,0 +1,2 @@ +h># + -h/d \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/i_over_not_g.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/i_over_not_g.expr.formatted.roc new file mode 100644 index 0000000000..6d8ad6cbf7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/i_over_not_g.expr.formatted.roc @@ -0,0 +1,3 @@ +i +/ +!g \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/i_over_not_g.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/i_over_not_g.expr.result-ast new file mode 100644 index 0000000000..e9bcb3a334 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/i_over_not_g.expr.result-ast @@ -0,0 +1,28 @@ +BinOps( + [ + ( + @0-1 Var { + module_name: "", + ident: "i", + }, + @1-2 Slash, + ), + ], + @3-7 SpaceBefore( + UnaryOp( + @6-7 SpaceBefore( + Var { + module_name: "", + ident: "g", + }, + [ + Newline, + ], + ), + @3-4 Not, + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/i_over_not_g.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/i_over_not_g.expr.roc new file mode 100644 index 0000000000..7c65f0866f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/i_over_not_g.expr.roc @@ -0,0 +1,3 @@ +i/ +! + g \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/implements_newlines_comments.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/implements_newlines_comments.expr.formatted.roc new file mode 100644 index 0000000000..fa2ead60dc --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/implements_newlines_comments.expr.formatted.roc @@ -0,0 +1,5 @@ +M # + im implements + de : J + +s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/implements_newlines_comments.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/implements_newlines_comments.expr.result-ast new file mode 100644 index 0000000000..370f43f943 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/implements_newlines_comments.expr.result-ast @@ -0,0 +1,75 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(0), + ], + regions: [ + @0-25, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [ + Ability { + header: TypeHeader { + name: @0-1 "M", + vars: [ + @4-6 SpaceBefore( + Identifier { + ident: "im", + }, + [ + LineComment( + "", + ), + ], + ), + ], + }, + loc_implements: @9-19 SpaceBefore( + Implements, + [ + LineComment( + "", + ), + ], + ), + members: [ + AbilityMember { + name: @21-23 SpaceBefore( + "de", + [ + Newline, + ], + ), + typ: @24-25 Apply( + "", + "J", + [], + ), + }, + ], + }, + ], + value_defs: [], + }, + @29-30 SpaceBefore( + Var { + module_name: "", + ident: "s", + }, + [ + Newline, + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/implements_newlines_comments.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/implements_newlines_comments.expr.roc new file mode 100644 index 0000000000..6e4b5e9def --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/implements_newlines_comments.expr.roc @@ -0,0 +1,6 @@ +M# + im# + implements + de:J + +s diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/list_comma_newlines.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/list_comma_newlines.expr.formatted.roc new file mode 100644 index 0000000000..f46e375674 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/list_comma_newlines.expr.formatted.roc @@ -0,0 +1,3 @@ +[ + s, +] \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/list_comma_newlines.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/list_comma_newlines.expr.result-ast new file mode 100644 index 0000000000..84a68b4e5c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/list_comma_newlines.expr.result-ast @@ -0,0 +1,18 @@ +List( + Collection { + items: [ + @1-2 SpaceAfter( + Var { + module_name: "", + ident: "s", + }, + [ + Newline, + ], + ), + ], + final_comments: [ + Newline, + ], + }, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/list_comma_newlines.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/list_comma_newlines.expr.roc new file mode 100644 index 0000000000..1fe57b27da --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/list_comma_newlines.expr.roc @@ -0,0 +1,3 @@ +[s +, +] \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/list_comment_newline.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/list_comment_newline.expr.formatted.roc new file mode 100644 index 0000000000..5c29705e69 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/list_comment_newline.expr.formatted.roc @@ -0,0 +1,3 @@ +[ + L, # +] \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/list_comment_newline.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/list_comment_newline.expr.result-ast new file mode 100644 index 0000000000..02681aaaf4 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/list_comment_newline.expr.result-ast @@ -0,0 +1,20 @@ +List( + Collection { + items: [ + @1-2 SpaceAfter( + Tag( + "L", + ), + [ + LineComment( + "", + ), + ], + ), + ], + final_comments: [ + Newline, + Newline, + ], + }, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/list_comment_newline.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/list_comment_newline.expr.roc new file mode 100644 index 0000000000..3ac42307e8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/list_comment_newline.expr.roc @@ -0,0 +1,4 @@ +[L# +, + +] \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/list_lots_of_spaces.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/list_lots_of_spaces.expr.formatted.roc new file mode 100644 index 0000000000..eb17d6b55f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/list_lots_of_spaces.expr.formatted.roc @@ -0,0 +1,6 @@ +[ + J, + # + # + u, +] \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/list_lots_of_spaces.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/list_lots_of_spaces.expr.result-ast new file mode 100644 index 0000000000..7db93a7907 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/list_lots_of_spaces.expr.result-ast @@ -0,0 +1,28 @@ +List( + [ + @1-2 SpaceAfter( + Tag( + "J", + ), + [ + Newline, + LineComment( + "", + ), + ], + ), + @10-11 SpaceBefore( + Var { + module_name: "", + ident: "u", + }, + [ + Newline, + Newline, + LineComment( + "", + ), + ], + ), + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/list_lots_of_spaces.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/list_lots_of_spaces.expr.roc new file mode 100644 index 0000000000..18d2cd7a46 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/list_lots_of_spaces.expr.roc @@ -0,0 +1,6 @@ +[J +# +, + +# +u] \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/min_parens_number.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/min_parens_number.expr.result-ast new file mode 100644 index 0000000000..e952ea0970 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/min_parens_number.expr.result-ast @@ -0,0 +1,8 @@ +UnaryOp( + @2-3 ParensAround( + Num( + "8", + ), + ), + @0-1 Negate, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/min_parens_number.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/min_parens_number.expr.roc new file mode 100644 index 0000000000..051e20ea65 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/min_parens_number.expr.roc @@ -0,0 +1 @@ +-(8) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_block_string.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_block_string.expr.formatted.roc new file mode 100644 index 0000000000..7f16bc8b3f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_block_string.expr.formatted.roc @@ -0,0 +1,6 @@ +-( + -( + """ + """ + ) +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_block_string.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_block_string.expr.result-ast new file mode 100644 index 0000000000..2f6dd8d63b --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_block_string.expr.result-ast @@ -0,0 +1,11 @@ +UnaryOp( + @1-8 UnaryOp( + @2-8 Str( + Block( + [], + ), + ), + @1-2 Negate, + ), + @0-1 Negate, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_block_string.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_block_string.expr.roc new file mode 100644 index 0000000000..e7df0c439e --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_block_string.expr.roc @@ -0,0 +1 @@ +--"""""" \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_six.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_six.expr.formatted.roc new file mode 100644 index 0000000000..286f41fc73 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_six.expr.formatted.roc @@ -0,0 +1 @@ +-(-6) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_six.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_six.expr.result-ast new file mode 100644 index 0000000000..61947d1683 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_six.expr.result-ast @@ -0,0 +1,10 @@ +ParensAround( + UnaryOp( + @3-5 ParensAround( + Num( + "-6", + ), + ), + @1-2 Negate, + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_six.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_six.expr.roc new file mode 100644 index 0000000000..6aad0a1ec3 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_minus_six.expr.roc @@ -0,0 +1 @@ +(-(-6)) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus.expr.formatted.roc new file mode 100644 index 0000000000..265ba9c6f0 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus.expr.formatted.roc @@ -0,0 +1,3 @@ +s +- +(-{}) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus.expr.result-ast new file mode 100644 index 0000000000..2374aa5fb8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus.expr.result-ast @@ -0,0 +1,27 @@ +SpaceAfter( + BinOps( + [ + ( + @0-1 Var { + module_name: "", + ident: "s", + }, + @1-2 Minus, + ), + ], + @4-7 SpaceBefore( + UnaryOp( + @5-7 Record( + [], + ), + @4-5 Negate, + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus.expr.roc new file mode 100644 index 0000000000..07728e463c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus.expr.roc @@ -0,0 +1,2 @@ +s- + -{} diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus_minus.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus_minus.expr.formatted.roc new file mode 100644 index 0000000000..34a86f854a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus_minus.expr.formatted.roc @@ -0,0 +1,4 @@ +p +- +(-t) +- 1 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus_minus.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus_minus.expr.result-ast new file mode 100644 index 0000000000..54d7ec4c32 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus_minus.expr.result-ast @@ -0,0 +1,34 @@ +SpaceAfter( + BinOps( + [ + ( + @0-1 Var { + module_name: "", + ident: "p", + }, + @1-2 Minus, + ), + ( + @4-6 SpaceBefore( + UnaryOp( + @5-6 Var { + module_name: "", + ident: "t", + }, + @4-5 Negate, + ), + [ + Newline, + ], + ), + @6-7 Minus, + ), + ], + @7-8 Num( + "1", + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus_minus.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus_minus.expr.roc new file mode 100644 index 0000000000..88da804ec9 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_newline_minus_minus.expr.roc @@ -0,0 +1,2 @@ +p- + -t-1 diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_not_h.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_not_h.expr.formatted.roc new file mode 100644 index 0000000000..802ce66363 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_not_h.expr.formatted.roc @@ -0,0 +1 @@ +-(!h) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_not_h.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/minus_not_h.expr.result-ast new file mode 100644 index 0000000000..62bb6f9940 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_not_h.expr.result-ast @@ -0,0 +1,15 @@ +SpaceAfter( + UnaryOp( + @1-3 UnaryOp( + @2-3 Var { + module_name: "", + ident: "h", + }, + @1-2 Not, + ), + @0-1 Negate, + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/minus_not_h.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/minus_not_h.expr.roc new file mode 100644 index 0000000000..512f4b5e3d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/minus_not_h.expr.roc @@ -0,0 +1 @@ +-!h diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/mul_comment_neg.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/mul_comment_neg.expr.formatted.roc new file mode 100644 index 0000000000..a2213357fd --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/mul_comment_neg.expr.formatted.roc @@ -0,0 +1,3 @@ +n * f +# +-f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/mul_comment_neg.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/mul_comment_neg.expr.result-ast new file mode 100644 index 0000000000..3e77041044 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/mul_comment_neg.expr.result-ast @@ -0,0 +1,52 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-3, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-3 BinOps( + [ + ( + @0-1 Var { + module_name: "", + ident: "n", + }, + @1-2 Star, + ), + ], + @2-3 Var { + module_name: "", + ident: "f", + }, + ), + ), + ], + }, + @6-8 SpaceBefore( + UnaryOp( + @7-8 Var { + module_name: "", + ident: "f", + }, + @6-7 Negate, + ), + [ + Newline, + LineComment( + "", + ), + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/mul_comment_neg.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/mul_comment_neg.expr.roc new file mode 100644 index 0000000000..65e8d4c491 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/mul_comment_neg.expr.roc @@ -0,0 +1,3 @@ +n*f +# +-f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multilin_str_body.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/multilin_str_body.expr.formatted.roc new file mode 100644 index 0000000000..b4b2ccfbaf --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multilin_str_body.expr.formatted.roc @@ -0,0 +1,5 @@ +a = + """ + "f + """ +f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multilin_str_body.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/multilin_str_body.expr.result-ast new file mode 100644 index 0000000000..6bfb9cb363 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multilin_str_body.expr.result-ast @@ -0,0 +1,44 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-10, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @0-1 Identifier { + ident: "a", + }, + @2-10 Str( + PlainLine( + "\"f", + ), + ), + ), + ], + }, + @11-12 SpaceBefore( + Var { + module_name: "", + ident: "f", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multilin_str_body.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/multilin_str_body.expr.roc new file mode 100644 index 0000000000..384b5c1da6 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multilin_str_body.expr.roc @@ -0,0 +1,2 @@ +a=""""f""" +f diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.formatted.roc new file mode 100644 index 0000000000..0235158840 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.formatted.roc @@ -0,0 +1,3 @@ +(MT q) = g + q +dbgT \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.result-ast new file mode 100644 index 0000000000..9d250fce06 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.result-ast @@ -0,0 +1,74 @@ +SpaceBefore( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @1-12, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @1-6 SpaceAfter( + Apply( + @1-3 Tag( + "MT", + ), + [ + @5-6 SpaceBefore( + Identifier { + ident: "q", + }, + [ + Newline, + ], + ), + ], + ), + [ + Newline, + ], + ), + @8-12 Apply( + @8-9 Var { + module_name: "", + ident: "g", + }, + [ + @11-12 SpaceBefore( + Var { + module_name: "", + ident: "q", + }, + [ + Newline, + ], + ), + ], + Space, + ), + ), + ], + }, + @13-17 SpaceBefore( + Var { + module_name: "", + ident: "dbgT", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.roc new file mode 100644 index 0000000000..3400d3c86e --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_apply_equals_multiline_apply.expr.roc @@ -0,0 +1,6 @@ + +MT + q +=g + q +dbgT \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_backpassing.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_backpassing.expr.formatted.roc new file mode 100644 index 0000000000..6dadcdd8f8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_backpassing.expr.formatted.roc @@ -0,0 +1,4 @@ +d +t # + <- b +-f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_backpassing.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_backpassing.expr.result-ast new file mode 100644 index 0000000000..79a074d616 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_backpassing.expr.result-ast @@ -0,0 +1,61 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-1, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-1 Var { + module_name: "", + ident: "d", + }, + ), + ], + }, + @2-12 SpaceBefore( + Backpassing( + [ + @2-3 SpaceAfter( + Identifier { + ident: "t", + }, + [ + LineComment( + "", + ), + ], + ), + ], + @8-9 Var { + module_name: "", + ident: "b", + }, + @10-12 SpaceBefore( + UnaryOp( + @11-12 Var { + module_name: "", + ident: "f", + }, + @10-11 Negate, + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/multiline_backpassing.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_backpassing.expr.roc new file mode 100644 index 0000000000..f0354d4a60 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/multiline_backpassing.expr.roc @@ -0,0 +1,4 @@ +d +t # +<-b +-f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.formatted.roc new file mode 100644 index 0000000000..408d473392 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.formatted.roc @@ -0,0 +1,7 @@ +-( + 0 + ( + 1 + d + ) +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.result-ast new file mode 100644 index 0000000000..3dadf656c9 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.result-ast @@ -0,0 +1,49 @@ +UnaryOp( + @2-8 ParensAround( + Apply( + @2-3 Num( + "0", + ), + [ + @4-7 ParensAround( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @4-5, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @4-5 Num( + "1", + ), + ), + ], + }, + @6-7 SpaceBefore( + Var { + module_name: "", + ident: "d", + }, + [ + Newline, + ], + ), + ), + ), + ], + Space, + ), + ), + @0-1 Negate, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.roc new file mode 100644 index 0000000000..e6c3dfbba4 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/neg_nested_parens.expr.roc @@ -0,0 +1,2 @@ +-(0(1 +d)) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/neg_newline_four.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/neg_newline_four.expr.formatted.roc new file mode 100644 index 0000000000..b902fc6dbd --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/neg_newline_four.expr.formatted.roc @@ -0,0 +1,2 @@ +-( + 4) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/neg_newline_four.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/neg_newline_four.expr.result-ast new file mode 100644 index 0000000000..0140426636 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/neg_newline_four.expr.result-ast @@ -0,0 +1,13 @@ +UnaryOp( + @3-4 ParensAround( + SpaceBefore( + Num( + "4", + ), + [ + Newline, + ], + ), + ), + @0-1 Negate, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/neg_newline_four.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/neg_newline_four.expr.roc new file mode 100644 index 0000000000..c1a5001c46 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/neg_newline_four.expr.roc @@ -0,0 +1,2 @@ +-( +4) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/negate_apply_parens_comment.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/negate_apply_parens_comment.expr.formatted.roc new file mode 100644 index 0000000000..089d7de192 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/negate_apply_parens_comment.expr.formatted.roc @@ -0,0 +1,7 @@ +-( + ( + 4 + 4 + ) + 4 +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/negate_apply_parens_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/negate_apply_parens_comment.expr.result-ast new file mode 100644 index 0000000000..a6817351a7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/negate_apply_parens_comment.expr.result-ast @@ -0,0 +1,53 @@ +SpaceAfter( + UnaryOp( + @2-8 ParensAround( + Apply( + @3-6 ParensAround( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @3-4, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @3-4 Num( + "4", + ), + ), + ], + }, + @5-6 SpaceBefore( + Num( + "4", + ), + [ + Newline, + ], + ), + ), + ), + [ + @7-8 Num( + "4", + ), + ], + Space, + ), + ), + @0-1 Negate, + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/negate_apply_parens_comment.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/negate_apply_parens_comment.expr.roc new file mode 100644 index 0000000000..5869720303 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/negate_apply_parens_comment.expr.roc @@ -0,0 +1,2 @@ +-((4 +4)4) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/negate_multiline_string.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/negate_multiline_string.expr.formatted.roc index d73b102c78..901e029b28 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/negate_multiline_string.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/negate_multiline_string.expr.formatted.roc @@ -1,3 +1,4 @@ -( """ - """) \ No newline at end of file + """ +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/negate_multiline_string_with_quote.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/negate_multiline_string_with_quote.expr.formatted.roc index 363eae8f45..64a439f1d7 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/negate_multiline_string_with_quote.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/negate_multiline_string_with_quote.expr.formatted.roc @@ -1,4 +1,5 @@ -( """ "< - """) \ No newline at end of file + """ +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/negative_single_quote.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/negative_single_quote.expr.result-ast new file mode 100644 index 0000000000..b36e700e5f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/negative_single_quote.expr.result-ast @@ -0,0 +1,6 @@ +UnaryOp( + @1-4 SingleQuote( + "i", + ), + @0-1 Negate, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/negative_single_quote.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/negative_single_quote.expr.roc new file mode 100644 index 0000000000..9f516eaab1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/negative_single_quote.expr.roc @@ -0,0 +1 @@ +-'i' \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.formatted.roc new file mode 100644 index 0000000000..3443b960a2 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.formatted.roc @@ -0,0 +1,4 @@ +\I [[ + O # + , i]] + -> i \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.result-ast new file mode 100644 index 0000000000..725e207ec2 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.result-ast @@ -0,0 +1,41 @@ +Closure( + [ + @1-12 Apply( + @1-2 Tag( + "I", + ), + [ + @2-12 List( + [ + @3-11 List( + [ + @5-6 SpaceBefore( + SpaceAfter( + Tag( + "O", + ), + [ + LineComment( + "", + ), + ], + ), + [ + Newline, + ], + ), + @9-10 Identifier { + ident: "i", + }, + ], + ), + ], + ), + ], + ), + ], + @14-15 Var { + module_name: "", + ident: "i", + }, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.roc new file mode 100644 index 0000000000..cc1fbccc98 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/nested_list_comment_in_closure_arg.expr.roc @@ -0,0 +1,3 @@ +\I[[ +O# +,i]]->i \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_type_alias_application.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_type_alias_application.expr.formatted.roc index 08831cf13a..ac9bdc513e 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_type_alias_application.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/newline_in_type_alias_application.expr.formatted.roc @@ -1,3 +1,3 @@ A : A - A + A p \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_double_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/not_double_parens.expr.formatted.roc new file mode 100644 index 0000000000..68ec352918 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_double_parens.expr.formatted.roc @@ -0,0 +1,4 @@ +!( + + E +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_double_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/not_double_parens.expr.result-ast new file mode 100644 index 0000000000..86cfcb6190 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_double_parens.expr.result-ast @@ -0,0 +1,25 @@ +UnaryOp( + @3-7 SpaceBefore( + ParensAround( + SpaceAfter( + ParensAround( + SpaceBefore( + Tag( + "E", + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], + ), + @0-1 Not, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_double_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/not_double_parens.expr.roc new file mode 100644 index 0000000000..95bb5e2382 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_double_parens.expr.roc @@ -0,0 +1,4 @@ +! +(( +E) +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_multiline_string.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/not_multiline_string.expr.formatted.roc index f85e7a3632..e0b44fade7 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/not_multiline_string.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_multiline_string.expr.formatted.roc @@ -1,3 +1,3 @@ ! -""" -""" \ No newline at end of file + """ + """ \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_record_updater.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/not_record_updater.expr.formatted.roc new file mode 100644 index 0000000000..203bf2b670 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_record_updater.expr.formatted.roc @@ -0,0 +1,2 @@ +e +! &s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_record_updater.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/not_record_updater.expr.result-ast new file mode 100644 index 0000000000..e192985baa --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_record_updater.expr.result-ast @@ -0,0 +1,42 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-1, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-1 Var { + module_name: "", + ident: "e", + }, + ), + ], + }, + @2-6 SpaceBefore( + UnaryOp( + @4-6 SpaceBefore( + RecordUpdater( + "s", + ), + [ + Newline, + ], + ), + @2-3 Not, + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_record_updater.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/not_record_updater.expr.roc new file mode 100644 index 0000000000..e163ca730d --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_record_updater.expr.roc @@ -0,0 +1,3 @@ +e +! +&s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_tag.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/not_tag.expr.formatted.roc new file mode 100644 index 0000000000..e36765f76f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_tag.expr.formatted.roc @@ -0,0 +1,4 @@ +!( + C + 2 +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_tag.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/not_tag.expr.result-ast new file mode 100644 index 0000000000..fb899bca82 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_tag.expr.result-ast @@ -0,0 +1,38 @@ +UnaryOp( + @2-5 ParensAround( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @2-3, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @2-3 Tag( + "C", + ), + ), + ], + }, + @4-5 SpaceBefore( + Num( + "2", + ), + [ + Newline, + ], + ), + ), + ), + @0-1 Not, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/not_tag.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/not_tag.expr.roc new file mode 100644 index 0000000000..d8b78c77be --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/not_tag.expr.roc @@ -0,0 +1,2 @@ +!(C +2) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opaque_comment_after_head.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_comment_after_head.expr.formatted.roc new file mode 100644 index 0000000000..d81e71d7c4 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_comment_after_head.expr.formatted.roc @@ -0,0 +1,3 @@ +A # + p := a +A \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opaque_comment_after_head.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_comment_after_head.expr.result-ast new file mode 100644 index 0000000000..a86d1badd4 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_comment_after_head.expr.result-ast @@ -0,0 +1,49 @@ +Defs( + Defs { + tags: [ + EitherIndex(0), + ], + regions: [ + @0-8, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [ + Opaque { + header: TypeHeader { + name: @0-1 "A", + vars: [ + @4-5 SpaceBefore( + Identifier { + ident: "p", + }, + [ + LineComment( + "", + ), + ], + ), + ], + }, + typ: @7-8 BoundVariable( + "a", + ), + derived: None, + }, + ], + value_defs: [], + }, + @9-10 SpaceBefore( + Tag( + "A", + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opaque_comment_after_head.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_comment_after_head.expr.roc new file mode 100644 index 0000000000..56ff88ecaa --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opaque_comment_after_head.expr.roc @@ -0,0 +1,3 @@ +A# + p:=a +A \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_pat.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_pat.expr.formatted.roc new file mode 100644 index 0000000000..45bbf90e78 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_pat.expr.formatted.roc @@ -0,0 +1,2 @@ +{ i ? Y } = p +Q \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_pat.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_pat.expr.result-ast new file mode 100644 index 0000000000..d90d2afacf --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_pat.expr.result-ast @@ -0,0 +1,54 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-9, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Body( + @0-7 RecordDestructure( + [ + @1-6 SpaceAfter( + OptionalField( + "i", + @5-6 SpaceBefore( + Tag( + "Y", + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], + ), + ], + ), + @8-9 Var { + module_name: "", + ident: "p", + }, + ), + ], + }, + @10-11 SpaceBefore( + Tag( + "Q", + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_pat.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_pat.expr.roc new file mode 100644 index 0000000000..c72bcce94e --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_pat.expr.roc @@ -0,0 +1,4 @@ +{i +? +Y}=p +Q \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_ty.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_ty.expr.formatted.roc new file mode 100644 index 0000000000..058df007df --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_ty.expr.formatted.roc @@ -0,0 +1,5 @@ +0 : { + i + ? d, +} +O \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_ty.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_ty.expr.result-ast new file mode 100644 index 0000000000..f032e52f42 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_ty.expr.result-ast @@ -0,0 +1,47 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-8, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-1 NumLiteral( + "0", + ), + @2-8 Record { + fields: [ + @3-7 OptionalValue( + @3-4 "i", + [ + Newline, + ], + @6-7 BoundVariable( + "d", + ), + ), + ], + ext: None, + }, + ), + ], + }, + @9-10 SpaceBefore( + Tag( + "O", + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_ty.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_ty.expr.roc new file mode 100644 index 0000000000..35c6cc377c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/opt_field_newline_in_ty.expr.roc @@ -0,0 +1,3 @@ +0:{i +?d} +O \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/p_return_f_minus_f.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/p_return_f_minus_f.expr.formatted.roc new file mode 100644 index 0000000000..f7f0c753dd --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/p_return_f_minus_f.expr.formatted.roc @@ -0,0 +1,5 @@ +p +return + # + f + -f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/p_return_f_minus_f.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/p_return_f_minus_f.expr.result-ast new file mode 100644 index 0000000000..63b6510ac0 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/p_return_f_minus_f.expr.result-ast @@ -0,0 +1,74 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-1, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-1 Var { + module_name: "", + ident: "p", + }, + ), + ], + }, + Return( + @2-16 SpaceBefore( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @11-12, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @11-12 Var { + module_name: "", + ident: "f", + }, + ), + ], + }, + @14-16 SpaceBefore( + UnaryOp( + @15-16 Var { + module_name: "", + ident: "f", + }, + @14-15 Negate, + ), + [ + Newline, + ], + ), + ), + [ + LineComment( + "", + ), + ], + ), + None, + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/p_return_f_minus_f.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/p_return_f_minus_f.expr.roc new file mode 100644 index 0000000000..0bffb05fe1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/p_return_f_minus_f.expr.roc @@ -0,0 +1,4 @@ +p +return# + f + -f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_newline.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_newline.expr.formatted.roc new file mode 100644 index 0000000000..f535926d4b --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_newline.expr.formatted.roc @@ -0,0 +1,5 @@ +( + f + N +) +N # \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_newline.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_newline.expr.result-ast new file mode 100644 index 0000000000..a22a76b0e1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_newline.expr.result-ast @@ -0,0 +1,73 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-5, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-5 ParensAround( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @1-2, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @1-2 Var { + module_name: "", + ident: "f", + }, + ), + ], + }, + @3-4 SpaceBefore( + Tag( + "N", + ), + [ + Newline, + ], + ), + ), + ), + ), + ], + }, + @6-7 SpaceBefore( + Tag( + "N", + ), + [ + Newline, + ], + ), + ), + [ + LineComment( + "", + ), + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_newline.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_newline.expr.roc new file mode 100644 index 0000000000..b6a9d52730 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_newline.expr.roc @@ -0,0 +1,3 @@ +(f +N) +N# \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_not_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_not_parens.expr.formatted.roc new file mode 100644 index 0000000000..63f20ff571 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_not_parens.expr.formatted.roc @@ -0,0 +1,4 @@ +!( + 4 +) + 4 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_not_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_not_parens.expr.result-ast new file mode 100644 index 0000000000..fccc65783b --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_not_parens.expr.result-ast @@ -0,0 +1,23 @@ +ParensAround( + Apply( + @1-6 UnaryOp( + @3-4 ParensAround( + SpaceAfter( + Num( + "4", + ), + [ + Newline, + ], + ), + ), + @1-2 Not, + ), + [ + @6-7 Num( + "4", + ), + ], + Space, + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_not_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_not_parens.expr.roc new file mode 100644 index 0000000000..db232007b8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_apply_not_parens.expr.roc @@ -0,0 +1,2 @@ +(!(4 +)4) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_in_ty_annotation.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_in_ty_annotation.expr.formatted.roc new file mode 100644 index 0000000000..f22e854ae8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_in_ty_annotation.expr.formatted.roc @@ -0,0 +1,3 @@ +Zx e # + f : i +s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_in_ty_annotation.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_in_ty_annotation.expr.result-ast new file mode 100644 index 0000000000..22d9dfea46 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_in_ty_annotation.expr.result-ast @@ -0,0 +1,52 @@ +Defs( + Defs { + tags: [ + EitherIndex(0), + ], + regions: [ + @0-10, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [ + Alias { + header: TypeHeader { + name: @0-2 "Zx", + vars: [ + @3-4 SpaceAfter( + Identifier { + ident: "e", + }, + [ + LineComment( + "", + ), + ], + ), + @7-8 Identifier { + ident: "f", + }, + ], + }, + ann: @9-10 BoundVariable( + "i", + ), + }, + ], + value_defs: [], + }, + @11-12 SpaceBefore( + Var { + module_name: "", + ident: "s", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_in_ty_annotation.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_in_ty_annotation.expr.roc new file mode 100644 index 0000000000..3fa885ed16 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_in_ty_annotation.expr.roc @@ -0,0 +1,3 @@ +Zx(e# +)f:i +s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_tuple.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_tuple.expr.formatted.roc new file mode 100644 index 0000000000..4b8e2b9c86 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_tuple.expr.formatted.roc @@ -0,0 +1,4 @@ +( + 0, # + L, +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_tuple.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_tuple.expr.result-ast new file mode 100644 index 0000000000..d50ace0ee4 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_tuple.expr.result-ast @@ -0,0 +1,24 @@ +SpaceAfter( + Tuple( + [ + @1-6 ParensAround( + SpaceAfter( + Num( + "0", + ), + [ + LineComment( + "", + ), + ], + ), + ), + @7-8 Tag( + "L", + ), + ], + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_tuple.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_tuple.expr.roc new file mode 100644 index 0000000000..083897e2cb --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_comment_tuple.expr.roc @@ -0,0 +1,2 @@ +((0# +),L) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_empty_record_apply.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_empty_record_apply.expr.formatted.roc new file mode 100644 index 0000000000..100e3999bf --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_empty_record_apply.expr.formatted.roc @@ -0,0 +1,5 @@ +( + { + } +) { +} \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_empty_record_apply.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/parens_empty_record_apply.expr.result-ast new file mode 100644 index 0000000000..05cf96a953 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_empty_record_apply.expr.result-ast @@ -0,0 +1,23 @@ +Apply( + @1-4 ParensAround( + Record( + Collection { + items: [], + final_comments: [ + Newline, + ], + }, + ), + ), + [ + @5-8 Record( + Collection { + items: [], + final_comments: [ + Newline, + ], + }, + ), + ], + Space, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_empty_record_apply.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_empty_record_apply.expr.roc new file mode 100644 index 0000000000..ffb571fcb2 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_empty_record_apply.expr.roc @@ -0,0 +1,3 @@ +({ +}){ +} \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_func_apply_type.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_func_apply_type.expr.formatted.roc new file mode 100644 index 0000000000..ca390c94a0 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_func_apply_type.expr.formatted.roc @@ -0,0 +1,2 @@ +si : (e)(e -> A) +A \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_func_apply_type.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/parens_func_apply_type.expr.result-ast new file mode 100644 index 0000000000..e19e71987b --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_func_apply_type.expr.result-ast @@ -0,0 +1,55 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-12, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-2 Identifier { + ident: "si", + }, + @3-12 Tuple { + elems: [ + @4-5 BoundVariable( + "e", + ), + ], + ext: Some( + @7-11 Function( + [ + @7-8 BoundVariable( + "e", + ), + ], + Pure, + @10-11 Apply( + "", + "A", + [], + ), + ), + ), + }, + ), + ], + }, + @13-14 SpaceBefore( + Tag( + "A", + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_func_apply_type.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_func_apply_type.expr.roc new file mode 100644 index 0000000000..dfc5b39b95 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_func_apply_type.expr.roc @@ -0,0 +1,2 @@ +si:(e)(e->A) +A \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_record_updater.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_record_updater.expr.formatted.roc new file mode 100644 index 0000000000..ceecaf52b2 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_record_updater.expr.formatted.roc @@ -0,0 +1,2 @@ +T +&n \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_record_updater.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/parens_record_updater.expr.result-ast new file mode 100644 index 0000000000..f90ffb156f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_record_updater.expr.result-ast @@ -0,0 +1,38 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-1, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-1 Tag( + "T", + ), + ), + ], + }, + @2-4 SpaceBefore( + RecordUpdater( + "n", + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/parens_record_updater.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/parens_record_updater.expr.roc new file mode 100644 index 0000000000..a0ccdc36c1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/parens_record_updater.expr.roc @@ -0,0 +1,2 @@ +T +&n diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.formatted.roc new file mode 100644 index 0000000000..a03fb36ab8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.formatted.roc @@ -0,0 +1,3 @@ +1 (i, p # + ) : f +n \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.result-ast new file mode 100644 index 0000000000..4f5c4a2d6f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.result-ast @@ -0,0 +1,58 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-10, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-1 Apply( + @0-1 NumLiteral( + "1", + ), + [ + @1-8 Tuple( + [ + @2-3 Identifier { + ident: "i", + }, + @4-5 SpaceAfter( + Identifier { + ident: "p", + }, + [ + LineComment( + "", + ), + ], + ), + ], + ), + ], + ), + @9-10 BoundVariable( + "f", + ), + ), + ], + }, + @11-12 SpaceBefore( + Var { + module_name: "", + ident: "n", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.roc new file mode 100644 index 0000000000..13364e8176 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_comma_newlines.expr.roc @@ -0,0 +1,3 @@ +1(i,p# +):f +n \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.formatted.roc new file mode 100644 index 0000000000..e3ef37924f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.formatted.roc @@ -0,0 +1,3 @@ +s { t # + } : s +p # \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.result-ast new file mode 100644 index 0000000000..b503d9e744 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.result-ast @@ -0,0 +1,62 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-8, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-1 Apply( + @0-1 Identifier { + ident: "s", + }, + [ + @1-6 RecordDestructure( + [ + @2-5 SpaceAfter( + Identifier { + ident: "t", + }, + [ + LineComment( + "", + ), + ], + ), + ], + ), + ], + ), + @7-8 BoundVariable( + "s", + ), + ), + ], + }, + @9-10 SpaceBefore( + Var { + module_name: "", + ident: "p", + }, + [ + Newline, + ], + ), + ), + [ + LineComment( + "", + ), + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.roc new file mode 100644 index 0000000000..4f9389463a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/pattern_record_apply_comment.expr.roc @@ -0,0 +1,3 @@ +s{t# +}:s +p# \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/pizza_question.moduledefs.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/pizza_question.moduledefs.formatted.roc deleted file mode 100644 index e561b11c43..0000000000 --- a/crates/compiler/test_syntax/tests/snapshots/pass/pizza_question.moduledefs.formatted.roc +++ /dev/null @@ -1,7 +0,0 @@ -main = - parseArgs? {} - |> List.dropFirst 1 - |> List.mapTry? Str.toU8 - |> List.sum - |> \total -> "Sum of numbers: $(Num.toStr total)" - |> Str.toUpper diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/record_update_comment_before_ampersand.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/record_update_comment_before_ampersand.expr.formatted.roc new file mode 100644 index 0000000000..6017448e78 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/record_update_comment_before_ampersand.expr.formatted.roc @@ -0,0 +1,2 @@ +{ i # + & } \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/record_update_comment_before_ampersand.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/record_update_comment_before_ampersand.expr.result-ast new file mode 100644 index 0000000000..52b92736a7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/record_update_comment_before_ampersand.expr.result-ast @@ -0,0 +1,14 @@ +RecordUpdate { + update: @1-2 SpaceAfter( + Var { + module_name: "", + ident: "i", + }, + [ + LineComment( + "", + ), + ], + ), + fields: [], +} diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/record_update_comment_before_ampersand.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/record_update_comment_before_ampersand.expr.roc new file mode 100644 index 0000000000..596c0f6a0f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/record_update_comment_before_ampersand.expr.roc @@ -0,0 +1,2 @@ +{i# +&} \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/record_updater_closure_weirdness.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/record_updater_closure_weirdness.expr.formatted.roc new file mode 100644 index 0000000000..bd008ae9df --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/record_updater_closure_weirdness.expr.formatted.roc @@ -0,0 +1,2 @@ +&rm? \L2 -> t ++ c \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/record_updater_closure_weirdness.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/record_updater_closure_weirdness.expr.result-ast new file mode 100644 index 0000000000..fd690e5d55 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/record_updater_closure_weirdness.expr.result-ast @@ -0,0 +1,43 @@ +SpaceAfter( + BinOps( + [ + ( + @0-10 SpaceAfter( + Apply( + @0-3 TrySuffix { + target: Result, + expr: RecordUpdater( + "rm", + ), + }, + [ + @4-10 Closure( + [ + @5-7 Tag( + "L2", + ), + ], + @9-10 Var { + module_name: "", + ident: "t", + }, + ), + ], + Space, + ), + [ + Newline, + ], + ), + @11-12 Plus, + ), + ], + @12-13 Var { + module_name: "", + ident: "c", + }, + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/record_updater_closure_weirdness.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/record_updater_closure_weirdness.expr.roc new file mode 100644 index 0000000000..83373cae38 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/record_updater_closure_weirdness.expr.roc @@ -0,0 +1,2 @@ +&rm?\L2->t ++c diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_apply_newline.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_apply_newline.expr.formatted.roc new file mode 100644 index 0000000000..0628067bd7 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_apply_newline.expr.formatted.roc @@ -0,0 +1,3 @@ +return + n + r # \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_apply_newline.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/return_apply_newline.expr.result-ast new file mode 100644 index 0000000000..95ce213096 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_apply_newline.expr.result-ast @@ -0,0 +1,50 @@ +SpaceAfter( + Return( + @0-12 SpaceBefore( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @8-9, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @8-9 Var { + module_name: "", + ident: "n", + }, + ), + ], + }, + @11-12 SpaceBefore( + Var { + module_name: "", + ident: "r", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], + ), + None, + ), + [ + LineComment( + "", + ), + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_apply_newline.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_apply_newline.expr.roc new file mode 100644 index 0000000000..aaf336016f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_apply_newline.expr.roc @@ -0,0 +1,3 @@ +return + n + r# \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_field_access_in_parens.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_field_access_in_parens.expr.formatted.roc new file mode 100644 index 0000000000..b1d5f5edbf --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_field_access_in_parens.expr.formatted.roc @@ -0,0 +1,4 @@ +( + return .o +) +ss \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_field_access_in_parens.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/return_field_access_in_parens.expr.result-ast new file mode 100644 index 0000000000..6070019652 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_field_access_in_parens.expr.result-ast @@ -0,0 +1,41 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-10, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-10 ParensAround( + Return( + @1-9 AccessorFunction( + RecordField( + "o", + ), + ), + None, + ), + ), + ), + ], + }, + @11-13 SpaceBefore( + Var { + module_name: "", + ident: "ss", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_field_access_in_parens.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_field_access_in_parens.expr.roc new file mode 100644 index 0000000000..91874a3e7e --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_field_access_in_parens.expr.roc @@ -0,0 +1,2 @@ +(return.o) +ss \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_in_apply_func.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_in_apply_func.expr.formatted.roc new file mode 100644 index 0000000000..d41225b26f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_in_apply_func.expr.formatted.roc @@ -0,0 +1,3 @@ +( + return -3e) + g \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_in_apply_func.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/return_in_apply_func.expr.result-ast new file mode 100644 index 0000000000..56773d649e --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_in_apply_func.expr.result-ast @@ -0,0 +1,22 @@ +Apply( + @2-11 ParensAround( + SpaceBefore( + Return( + @2-11 Num( + "-3e", + ), + None, + ), + [ + Newline, + ], + ), + ), + [ + @12-13 Var { + module_name: "", + ident: "g", + }, + ], + Space, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_in_apply_func.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_in_apply_func.expr.roc new file mode 100644 index 0000000000..3651820e6c --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_in_apply_func.expr.roc @@ -0,0 +1,2 @@ +( +return-3e)g \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_minus_one.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_minus_one.expr.formatted.roc new file mode 100644 index 0000000000..a3fe56af70 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_minus_one.expr.formatted.roc @@ -0,0 +1,2 @@ +return -r +1 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_minus_one.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/return_minus_one.expr.result-ast new file mode 100644 index 0000000000..4571082e1f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_minus_one.expr.result-ast @@ -0,0 +1,19 @@ +Return( + @0-8 UnaryOp( + @7-8 Var { + module_name: "", + ident: "r", + }, + @6-7 Negate, + ), + Some( + @9-10 SpaceBefore( + Num( + "1", + ), + [ + Newline, + ], + ), + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_minus_one.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_minus_one.expr.roc new file mode 100644 index 0000000000..cf05d7bdba --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_minus_one.expr.roc @@ -0,0 +1,2 @@ +return-r +1 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_with_after.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_with_after.expr.formatted.roc new file mode 100644 index 0000000000..c8c01309f1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_with_after.expr.formatted.roc @@ -0,0 +1,3 @@ +return -1 # +X +s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_with_after.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/return_with_after.expr.result-ast new file mode 100644 index 0000000000..a9d9b8d9a5 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_with_after.expr.result-ast @@ -0,0 +1,45 @@ +Return( + @0-8 Num( + "-1", + ), + Some( + @10-13 Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @10-11, + ], + space_before: [ + Slice { start: 0, length: 1 }, + ], + space_after: [ + Slice { start: 1, length: 0 }, + ], + spaces: [ + LineComment( + "", + ), + ], + type_defs: [], + value_defs: [ + Stmt( + @10-11 Tag( + "X", + ), + ), + ], + }, + @12-13 SpaceBefore( + Var { + module_name: "", + ident: "s", + }, + [ + Newline, + ], + ), + ), + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/return_with_after.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/return_with_after.expr.roc new file mode 100644 index 0000000000..715e746489 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/return_with_after.expr.roc @@ -0,0 +1,3 @@ +return-1# +X +s \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/space_before_parens_space_after.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/space_before_parens_space_after.expr.formatted.roc new file mode 100644 index 0000000000..8cbeb2061a --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/space_before_parens_space_after.expr.formatted.roc @@ -0,0 +1,2 @@ +i +4 # ( \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/space_before_parens_space_after.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/space_before_parens_space_after.expr.result-ast new file mode 100644 index 0000000000..7b4fd983f2 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/space_before_parens_space_after.expr.result-ast @@ -0,0 +1,48 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-1, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-1 Var { + module_name: "", + ident: "i", + }, + ), + ], + }, + @2-6 SpaceBefore( + ParensAround( + SpaceAfter( + Num( + "4", + ), + [ + Newline, + ], + ), + ), + [ + Newline, + ], + ), + ), + [ + LineComment( + "(", + ), + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/space_before_parens_space_after.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/space_before_parens_space_after.expr.roc new file mode 100644 index 0000000000..a9c1ff5bb1 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/space_before_parens_space_after.expr.roc @@ -0,0 +1,3 @@ +i +(4 +)#( \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/stmt_parens_minus.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/stmt_parens_minus.expr.formatted.roc new file mode 100644 index 0000000000..e7c60aba0b --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/stmt_parens_minus.expr.formatted.roc @@ -0,0 +1,2 @@ +i +-2 \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/stmt_parens_minus.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/stmt_parens_minus.expr.result-ast new file mode 100644 index 0000000000..8bcd85263e --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/stmt_parens_minus.expr.result-ast @@ -0,0 +1,36 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-1, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @0-1 Var { + module_name: "", + ident: "i", + }, + ), + ], + }, + @2-6 SpaceBefore( + ParensAround( + Num( + "-2", + ), + ), + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/stmt_parens_minus.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/stmt_parens_minus.expr.roc new file mode 100644 index 0000000000..f5ee907786 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/stmt_parens_minus.expr.roc @@ -0,0 +1,2 @@ +i +(-2) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/suffixed_question_one_def.full.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/suffixed_question_one_def.full.formatted.roc index e0bc1818e9..5f72ff1e05 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/suffixed_question_one_def.full.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/suffixed_question_one_def.full.formatted.roc @@ -10,8 +10,8 @@ main = # what about this? "Bar" - |> B.y? - { config: "config" } + |> B.y? + { config: "config" } C.z "Bar" diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/suffixed_question_optional_last.full.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/suffixed_question_optional_last.full.formatted.roc index 65fc305940..1bbbe4f36c 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/suffixed_question_optional_last.full.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/suffixed_question_optional_last.full.formatted.roc @@ -4,6 +4,6 @@ app [main] { main = "jq --version" - |> Cmd.new - |> Cmd.status - |> Result.mapErr? UnableToCheckJQVersion + |> Cmd.new + |> Cmd.status + |> Result.mapErr? UnableToCheckJQVersion diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.formatted.roc new file mode 100644 index 0000000000..edc201ec4f --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.formatted.roc @@ -0,0 +1,2 @@ +1 (0 0) f : f +i \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.result-ast new file mode 100644 index 0000000000..0b21682f02 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.result-ast @@ -0,0 +1,64 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-13, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-1 Apply( + @0-1 NumLiteral( + "1", + ), + [ + @2-9 Apply( + @3-4 NumLiteral( + "0", + ), + [ + @5-6 SpaceAfter( + NumLiteral( + "0", + ), + [ + Newline, + ], + ), + ], + ), + @10-11 Identifier { + ident: "f", + }, + ], + ), + @12-13 BoundVariable( + "f", + ), + ), + ], + }, + @14-15 SpaceBefore( + Var { + module_name: "", + ident: "i", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.roc new file mode 100644 index 0000000000..d09cf698f8 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/triple_paren_pat_ann.expr.roc @@ -0,0 +1,3 @@ +1((0(0 +)))f:f +i diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/try_subtract.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/try_subtract.expr.formatted.roc new file mode 100644 index 0000000000..2ad4dbbc49 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/try_subtract.expr.formatted.roc @@ -0,0 +1 @@ +try - w \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/try_subtract.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/try_subtract.expr.result-ast new file mode 100644 index 0000000000..735b74edf9 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/try_subtract.expr.result-ast @@ -0,0 +1,12 @@ +BinOps( + [ + ( + @0-3 Try, + @3-4 Minus, + ), + ], + @4-5 Var { + module_name: "", + ident: "w", + }, +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/try_subtract.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/try_subtract.expr.roc new file mode 100644 index 0000000000..898a5045ec --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/try_subtract.expr.roc @@ -0,0 +1 @@ +try-w \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tuple_apply_parens_comment.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_apply_parens_comment.expr.formatted.roc new file mode 100644 index 0000000000..fd384fb581 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_apply_parens_comment.expr.formatted.roc @@ -0,0 +1,8 @@ +( + ( + L + L + ) + L, + L, +) # \ \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tuple_apply_parens_comment.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_apply_parens_comment.expr.result-ast new file mode 100644 index 0000000000..9d139768aa --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_apply_parens_comment.expr.result-ast @@ -0,0 +1,57 @@ +SpaceAfter( + Tuple( + [ + @1-7 Apply( + @2-5 ParensAround( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @2-3, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @2-3 Tag( + "L", + ), + ), + ], + }, + @4-5 SpaceBefore( + Tag( + "L", + ), + [ + Newline, + ], + ), + ), + ), + [ + @6-7 Tag( + "L", + ), + ], + Space, + ), + @8-9 Tag( + "L", + ), + ], + ), + [ + LineComment( + "\\", + ), + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tuple_apply_parens_comment.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_apply_parens_comment.expr.roc new file mode 100644 index 0000000000..9561d4b8f6 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_apply_parens_comment.expr.roc @@ -0,0 +1,2 @@ +((L +L)L,L)#\ diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tuple_function_annotation.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_function_annotation.expr.formatted.roc new file mode 100644 index 0000000000..87338cba51 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_function_annotation.expr.formatted.roc @@ -0,0 +1,7 @@ +1P : ( + I, + s, + Mw + -> r, +)l +asl \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tuple_function_annotation.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_function_annotation.expr.result-ast new file mode 100644 index 0000000000..a3e27dd316 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_function_annotation.expr.result-ast @@ -0,0 +1,74 @@ +Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-17, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Annotation( + @0-2 SpaceAfter( + NumLiteral( + "1P", + ), + [ + Newline, + ], + ), + @4-17 Tuple { + elems: [ + @5-15 Function( + [ + @5-6 Apply( + "", + "I", + [], + ), + @7-8 SpaceAfter( + BoundVariable( + "s", + ), + [ + Newline, + ], + ), + @10-12 Apply( + "", + "Mw", + [], + ), + ], + Pure, + @14-15 BoundVariable( + "r", + ), + ), + ], + ext: Some( + @16-17 BoundVariable( + "l", + ), + ), + }, + ), + ], + }, + @18-21 SpaceBefore( + Var { + module_name: "", + ident: "asl", + }, + [ + Newline, + ], + ), +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tuple_function_annotation.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_function_annotation.expr.roc new file mode 100644 index 0000000000..2ff6085810 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tuple_function_annotation.expr.roc @@ -0,0 +1,4 @@ +1P +:(I,s +,Mw->r)l +asl \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tuples_parens_comments.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/tuples_parens_comments.expr.formatted.roc new file mode 100644 index 0000000000..7dd0035f74 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tuples_parens_comments.expr.formatted.roc @@ -0,0 +1,8 @@ +( + i, # + # + ( + EsE + ui + ), +) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tuples_parens_comments.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/tuples_parens_comments.expr.result-ast new file mode 100644 index 0000000000..aec88cefc4 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tuples_parens_comments.expr.result-ast @@ -0,0 +1,62 @@ +Tuple( + [ + @1-2 Var { + module_name: "", + ident: "i", + }, + @6-19 SpaceBefore( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @6-16, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + Stmt( + @6-16 ParensAround( + SpaceBefore( + ParensAround( + Tag( + "EsE", + ), + ), + [ + Newline, + LineComment( + "", + ), + ], + ), + ), + ), + ], + }, + @17-19 SpaceBefore( + Var { + module_name: "", + ident: "ui", + }, + [ + Newline, + ], + ), + ), + [ + LineComment( + "", + ), + Newline, + ], + ), + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/tuples_parens_comments.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/tuples_parens_comments.expr.roc new file mode 100644 index 0000000000..1f29ebd963 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/tuples_parens_comments.expr.roc @@ -0,0 +1,6 @@ +(i,# + +( +# +(EsE)) +ui) \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/type_tuple_where_annotation.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/type_tuple_where_annotation.expr.formatted.roc new file mode 100644 index 0000000000..80106010b5 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/type_tuple_where_annotation.expr.formatted.roc @@ -0,0 +1,3 @@ +nextWhileLess : List Bucket, k, U8 -> (U64, U32) where k implements Hash & Eq +nextWhileLess = \buckets, key, shifts -> foo +nextWhileLess \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/type_tuple_where_annotation.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/type_tuple_where_annotation.expr.result-ast new file mode 100644 index 0000000000..4fd636e8b5 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/type_tuple_where_annotation.expr.result-ast @@ -0,0 +1,120 @@ +SpaceAfter( + Defs( + Defs { + tags: [ + EitherIndex(2147483648), + ], + regions: [ + @0-122, + ], + space_before: [ + Slice { start: 0, length: 0 }, + ], + space_after: [ + Slice { start: 0, length: 0 }, + ], + spaces: [], + type_defs: [], + value_defs: [ + AnnotatedBody { + ann_pattern: @0-13 Identifier { + ident: "nextWhileLess", + }, + ann_type: @16-77 Where( + @16-48 Function( + [ + @16-27 Apply( + "", + "List", + [ + @21-27 Apply( + "", + "Bucket", + [], + ), + ], + ), + @29-30 BoundVariable( + "k", + ), + @32-34 Apply( + "", + "U8", + [], + ), + ], + Pure, + @38-48 Tuple { + elems: [ + @39-42 Apply( + "", + "U64", + [], + ), + @44-47 Apply( + "", + "U32", + [], + ), + ], + ext: None, + }, + ), + [ + @55-77 ImplementsClause { + var: @55-56 "k", + abilities: [ + @68-72 Apply( + "", + "Hash", + [], + ), + @75-77 Apply( + "", + "Eq", + [], + ), + ], + }, + ], + ), + lines_between: [ + Newline, + ], + body_pattern: @78-91 Identifier { + ident: "nextWhileLess", + }, + body_expr: @94-122 Closure( + [ + @95-102 Identifier { + ident: "buckets", + }, + @104-107 Identifier { + ident: "key", + }, + @109-115 Identifier { + ident: "shifts", + }, + ], + @119-122 Var { + module_name: "", + ident: "foo", + }, + ), + }, + ], + }, + @123-136 SpaceBefore( + Var { + module_name: "", + ident: "nextWhileLess", + }, + [ + Newline, + ], + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/type_tuple_where_annotation.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/type_tuple_where_annotation.expr.roc new file mode 100644 index 0000000000..638787e775 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/type_tuple_where_annotation.expr.roc @@ -0,0 +1,3 @@ +nextWhileLess : List Bucket, k, U8 -> (U64, U32) where k implements Hash & Eq +nextWhileLess = \buckets, key, shifts -> foo +nextWhileLess diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/when_in_binops.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/when_in_binops.expr.formatted.roc new file mode 100644 index 0000000000..1605846682 --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/when_in_binops.expr.formatted.roc @@ -0,0 +1,9 @@ +di +< s +< ( + when + b + is + 7 -> 7e +) + zl \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/when_in_binops.expr.result-ast b/crates/compiler/test_syntax/tests/snapshots/pass/when_in_binops.expr.result-ast new file mode 100644 index 0000000000..f6903073cb --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/when_in_binops.expr.result-ast @@ -0,0 +1,61 @@ +SpaceAfter( + BinOps( + [ + ( + @0-2 Var { + module_name: "", + ident: "di", + }, + @2-3 LessThan, + ), + ( + @3-4 Var { + module_name: "", + ident: "s", + }, + @4-5 LessThan, + ), + ], + @5-25 Apply( + @5-21 When( + @10-11 SpaceAfter( + Var { + module_name: "", + ident: "b", + }, + [ + Newline, + ], + ), + [ + WhenBranch { + patterns: [ + @16-17 NumLiteral( + "7", + ), + ], + value: @19-21 Num( + "7e", + ), + guard: None, + }, + ], + ), + [ + @23-25 SpaceBefore( + Var { + module_name: "", + ident: "zl", + }, + [ + Newline, + ], + ), + ], + Space, + ), + ), + [ + Newline, + ], +) diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/when_in_binops.expr.roc b/crates/compiler/test_syntax/tests/snapshots/pass/when_in_binops.expr.roc new file mode 100644 index 0000000000..30fe0013fa --- /dev/null +++ b/crates/compiler/test_syntax/tests/snapshots/pass/when_in_binops.expr.roc @@ -0,0 +1,3 @@ +di7e + zl diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_multiple_bound_abilities.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_multiple_bound_abilities.expr.formatted.roc index 15ab48af35..889a36e239 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_multiple_bound_abilities.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_multiple_bound_abilities.expr.formatted.roc @@ -1,5 +1,6 @@ f : a -> b where a implements Hash & Eq, b implements Eq & Hash & Display -f : a -> b where a implements Hash & Eq, b implements Hash & Display & Eq +f : + a -> b where a implements Hash & Eq, b implements Hash & Display & Eq f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.formatted.roc index 9076cc336a..c1c240a7f7 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_multiple_has_across_newlines.expr.formatted.roc @@ -1,3 +1,4 @@ -f : a -> (b -> c) where a implements Hash, b implements Eq, c implements Ord +f : + a -> (b -> c) where a implements Hash, b implements Eq, c implements Ord f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_on_newline.expr.formatted.roc b/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_on_newline.expr.formatted.roc index 1b14b8c6b4..fb6a3b0303 100644 --- a/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_on_newline.expr.formatted.roc +++ b/crates/compiler/test_syntax/tests/snapshots/pass/where_clause_on_newline.expr.formatted.roc @@ -1,3 +1,4 @@ -f : a -> U64 where a implements Hash +f : + a -> U64 where a implements Hash f \ No newline at end of file diff --git a/crates/compiler/test_syntax/tests/test_fmt.rs b/crates/compiler/test_syntax/tests/test_fmt.rs index ef2d046832..89bb5a1ebd 100644 --- a/crates/compiler/test_syntax/tests/test_fmt.rs +++ b/crates/compiler/test_syntax/tests/test_fmt.rs @@ -2283,15 +2283,25 @@ mod test_fmt { " )); - expr_formats_same(indoc!( - r" - f : - { + expr_formats_to( + indoc!( + r" + f : + { + } + + f + " + ), + indoc!( + r" + f : { } - f - " - )); + f + " + ), + ); } #[test] @@ -4731,8 +4741,6 @@ mod test_fmt { expr_formats_same(indoc!( r" blah : - Str, - # comment (Str -> Str) -> Str @@ -5489,25 +5497,15 @@ mod test_fmt { " )); - expr_formats_to( - indoc!( - r" + expr_formats_same(indoc!( + r" A := U8 implements [Eq, Hash] 0 " - ), - indoc!( - r" - A := U8 - implements [Eq, Hash] - - 0 - " - ), - ); + )); expr_formats_to( indoc!( diff --git a/crates/compiler/test_syntax/tests/test_snapshots.rs b/crates/compiler/test_syntax/tests/test_snapshots.rs index ee05de117b..15eb1f24ec 100644 --- a/crates/compiler/test_syntax/tests/test_snapshots.rs +++ b/crates/compiler/test_syntax/tests/test_snapshots.rs @@ -222,6 +222,7 @@ mod test_snapshots { fail/module_params_with_missing_arrow.header, fail/module_with_unfinished_params.header, fail/multi_no_end.expr, + fail/nested_tuples_annotation_terrible_perf.expr, fail/newline_before_operator_with_defs.expr, fail/opaque_type_def_with_newline.expr, fail/pattern_binds_keyword.expr, @@ -276,27 +277,54 @@ mod test_snapshots { pass/ability_two_in_a_row.expr, pass/add_var_with_spaces.expr, pass/add_with_spaces.expr, + pass/alias_ann_in_parens.expr, + pass/alias_comment_after_head.expr, + pass/alias_parens_comment.expr, + pass/alias_parens_comment_indent.expr, + pass/all_the_bangs.expr, pass/ann_closed_union.expr, pass/ann_effectful_fn.expr, pass/ann_open_union.expr, + pass/ann_parens_comments.expr, + pass/ann_record_pat_with_comment.expr, + pass/ann_tag_union_newline_comment.expr, + pass/annotate_tuple_func.expr, + pass/annotated_empty_record_destructure.expr, pass/annotated_record_destructure.expr, pass/annotated_tag_destructure.expr, pass/annotated_tuple_destructure.expr, + pass/annotation_apply_newlines.expr, + pass/annotation_comment_before_colon.expr, + pass/annotation_tuple_comment.expr, + pass/annotation_tuple_newline.expr, + pass/annotation_tuple_parens_newlines.expr, + pass/applies_in_binop.expr, + pass/apply_binop_switch.expr, + pass/apply_closure_pizza.expr, pass/apply_parenthetical_tag_args.expr, + pass/apply_record_ann.expr, pass/apply_tag.expr, pass/apply_three_args.expr, pass/apply_two_args.expr, pass/apply_unary_negation.expr, pass/apply_unary_not.expr, pass/arg_pattern_as.expr, + pass/backpassing_bananza.expr, + pass/bang_newline_double_accessor.expr, pass/basic_apply.expr, pass/basic_docs.expr, pass/basic_field.expr, pass/basic_tag.expr, pass/basic_tuple.expr, pass/basic_var.expr, + pass/binop_apply_complex.expr, + pass/binop_assign_defs_nested.expr, + pass/block_string_ann.expr, + pass/body_block_string_apply_string.expr, + pass/body_with_unneeded_parens.expr, pass/call_bang.expr, pass/call_bang_no_space.expr, + pass/closure_in_apply_in_binop.expr, pass/closure_in_binop_with_spaces.expr, pass/closure_with_underscores.expr, pass/comma_prefixed_indented_record.expr, @@ -307,18 +335,34 @@ mod test_snapshots { pass/comment_before_colon_def.expr, pass/comment_before_equals_def.expr, pass/comment_before_op.expr, + pass/comment_before_pat_in_parens.expr, + pass/comment_in_backpassing_args.expr, + pass/comment_in_closure_pat.expr, + pass/comment_in_closure_pat_apply.expr, + pass/comment_indent_in_parens.expr, pass/comment_inside_empty_list.expr, pass/comment_with_non_ascii.expr, + pass/compare_apply_record.expr, pass/control_characters_in_scalar.expr, pass/crash.expr, + pass/crazy_annotation_left.expr, + pass/crazy_annotation_left2.expr, + pass/crazy_backpassing_parens.expr, + pass/crazy_pat_ann.expr, pass/dbg.expr, + pass/dbg_double.expr, + pass/dbg_double_newline.expr, + pass/dbg_extra_parens.expr, + pass/dbg_newline_apply.expr, pass/dbg_stmt.expr, pass/dbg_stmt_multiline.expr, pass/dbg_stmt_two_exprs.expr, pass/def_bang.expr, + pass/def_multistring_apply.expr, pass/defs_suffixed_middle_extra_indents.moduledefs, pass/destructure_tag_assignment.expr, pass/docs.expr, + pass/double_space_before.expr, pass/effectful_closure_statements.expr, pass/empty_app_header.header, pass/empty_hosted_header.header, @@ -327,6 +371,11 @@ mod test_snapshots { pass/empty_package_header.header, pass/empty_platform_header.header, pass/empty_record.expr, + pass/empty_record_assign_tag.expr, + pass/empty_record_assignment.expr, + pass/empty_record_eq_dbg.expr, + pass/empty_record_eq_newlines_doubleeq.expr, + pass/empty_record_newline_assign.expr, pass/empty_record_update.expr, pass/empty_string.expr, pass/equals.expr, @@ -336,6 +385,7 @@ mod test_snapshots { pass/expect_single_line.expr, pass/extra_newline.expr, pass/extra_newline_in_parens.expr, + pass/f_not_not_f.expr, pass/float_with_underscores.expr, pass/fn_with_record_arg.expr, pass/full_app_header.header, @@ -343,9 +393,12 @@ mod test_snapshots { pass/function_effect_types.header, pass/function_with_tuple_ext_type.expr, pass/function_with_tuple_type.expr, + pass/h_greater_comment_minus_div.expr, pass/highest_float.expr, pass/highest_int.expr, + pass/i_over_not_g.expr, pass/if_def.expr, + pass/implements_newlines_comments.expr, pass/import.moduledefs, pass/import_from_package.moduledefs, pass/import_with_alias.moduledefs, @@ -363,12 +416,21 @@ mod test_snapshots { pass/list_closing_indent_not_enough.expr, pass/list_closing_same_indent_no_trailing_comma.expr, pass/list_closing_same_indent_with_trailing_comma.expr, + pass/list_comma_newlines.expr, + pass/list_comment_newline.expr, + pass/list_lots_of_spaces.expr, pass/list_minus_newlines.expr, pass/list_pattern_weird_indent.expr, pass/list_patterns.expr, pass/lowest_float.expr, pass/lowest_int.expr, + pass/min_parens_number.expr, pass/minimal_app_header.header, + pass/minus_minus_block_string.expr, + pass/minus_minus_six.expr, + pass/minus_newline_minus.expr, + pass/minus_newline_minus_minus.expr, + pass/minus_not_h.expr, pass/minus_twelve_minus_five.expr, pass/mixed_docs.expr, pass/module_def_newline.moduledefs, @@ -378,10 +440,14 @@ mod test_snapshots { pass/module_with_optional_param.header, pass/module_with_params.header, pass/module_with_params_and_multiline_exposes.header, + pass/mul_comment_neg.expr, pass/multi_backpassing.expr, pass/multi_backpassing_in_def.moduledefs, pass/multi_backpassing_with_apply.expr, pass/multi_char_string.expr, + pass/multilin_str_body.expr, + pass/multiline_apply_equals_multiline_apply.expr, + pass/multiline_backpassing.expr, pass/multiline_binop_when_with_comments.expr, pass/multiline_str_in_pat.expr, pass/multiline_string.expr, @@ -392,13 +458,18 @@ mod test_snapshots { pass/multiple_fields.expr, pass/multiple_operators.expr, pass/neg_inf_float.expr, + pass/neg_nested_parens.expr, + pass/neg_newline_four.expr, + pass/negate_apply_parens_comment.expr, pass/negate_multiline_string.expr, pass/negate_multiline_string_with_quote.expr, pass/negative_float.expr, pass/negative_in_apply_def.expr, pass/negative_int.expr, + pass/negative_single_quote.expr, pass/nested_def_annotation.moduledefs, pass/nested_if.expr, + pass/nested_list_comment_in_closure_arg.expr, pass/newline_after_equals.expr, // Regression test for https://github.com/roc-lang/roc/issues/51 pass/newline_after_mul.expr, pass/newline_after_paren.expr, @@ -414,7 +485,10 @@ mod test_snapshots { pass/nonempty_hosted_header.header, pass/nonempty_package_header.header, pass/nonempty_platform_header.header, + pass/not_double_parens.expr, pass/not_multiline_string.expr, + pass/not_record_updater.expr, + pass/not_tag.expr, pass/number_literal_suffixes.expr, pass/old_app_header.full, pass/old_interface_header.header, @@ -424,6 +498,7 @@ mod test_snapshots { pass/one_minus_two.expr, pass/one_plus_two.expr, pass/one_spaced_def.expr, + pass/opaque_comment_after_head.expr, pass/opaque_destructure_first_item_in_body.expr, pass/opaque_has_abilities.expr, pass/opaque_reference_expr.expr, @@ -433,12 +508,22 @@ mod test_snapshots { pass/opaque_simple.moduledefs, pass/opaque_with_type_arguments.moduledefs, pass/ops_with_newlines.expr, + pass/opt_field_newline_in_pat.expr, + pass/opt_field_newline_in_ty.expr, pass/outdented_app_with_record.expr, pass/outdented_colon_in_record.expr, pass/outdented_list.expr, pass/outdented_record.expr, + pass/p_return_f_minus_f.expr, pass/packed_singleton_list.expr, + pass/parens_apply_newline.expr, + pass/parens_apply_not_parens.expr, + pass/parens_comment_in_ty_annotation.expr, + pass/parens_comment_tuple.expr, + pass/parens_empty_record_apply.expr, + pass/parens_func_apply_type.expr, pass/parens_in_type_def_apply.expr, + pass/parens_record_updater.expr, pass/parenthesized_type_def.expr, pass/parenthesized_type_def_space_before.expr, pass/parenthetical_apply.expr, @@ -450,6 +535,8 @@ mod test_snapshots { pass/pattern_as.expr, pass/pattern_as_list_rest.expr, pass/pattern_as_spaces.expr, + pass/pattern_comma_newlines.expr, + pass/pattern_record_apply_comment.expr, pass/pattern_with_space_in_parens.expr, // https://github.com/roc-lang/roc/issues/929 pass/pizza_dbg.expr, pass/pizza_question.moduledefs, @@ -470,23 +557,32 @@ mod test_snapshots { pass/record_literal_field_bang.expr, pass/record_type_with_function.expr, pass/record_update.expr, + pass/record_update_comment_before_ampersand.expr, + pass/record_updater_closure_weirdness.expr, pass/record_updater_literal_apply.expr, pass/record_updater_var_apply.expr, pass/record_with_if.expr, pass/requires_type.header, + pass/return_apply_newline.expr, + pass/return_field_access_in_parens.expr, + pass/return_in_apply_func.expr, pass/return_in_if.expr, pass/return_in_static_def.expr, pass/return_in_when.expr, + pass/return_minus_one.expr, pass/return_multiline.expr, pass/return_only_statement.expr, + pass/return_with_after.expr, pass/separate_defs.moduledefs, pass/single_arg_closure.expr, pass/single_underscore_closure.expr, pass/space_before_colon.full, + pass/space_before_parens_space_after.expr, pass/space_only_after_minus.expr, pass/spaced_singleton_list.expr, pass/spaces_inside_empty_list.expr, pass/standalone_module_defs.moduledefs, + pass/stmt_parens_minus.expr, pass/str_block_multiple_newlines.expr, pass/string_without_escape.expr, pass/sub_var_with_spaces.expr, @@ -501,16 +597,21 @@ mod test_snapshots { pass/tag_pattern.expr, pass/ten_times_eleven.expr, pass/three_arg_closure.expr, + pass/triple_paren_pat_ann.expr, pass/try_blank_in_list.expr, pass/try_function_after_pipe.expr, pass/try_pipe_suffix.expr, pass/try_plain_prefix.expr, + pass/try_subtract.expr, pass/tuple_access_after_ident.expr, pass/tuple_access_after_record.expr, pass/tuple_accessor_function.expr, + pass/tuple_apply_parens_comment.expr, pass/tuple_destructure_bang.expr, + pass/tuple_function_annotation.expr, pass/tuple_type.expr, pass/tuple_type_ext.expr, + pass/tuples_parens_comments.expr, pass/two_arg_closure.expr, pass/two_backpassing.expr, pass/two_branch_when.expr, @@ -518,6 +619,7 @@ mod test_snapshots { pass/type_decl_with_underscore.expr, pass/type_signature_def.expr, pass/type_signature_function_def.expr, + pass/type_tuple_where_annotation.expr, pass/unary_negation.expr, pass/unary_negation_access.expr, // Regression test for https://github.com/roc-lang/roc/issues/509 pass/unary_negation_arg.expr, @@ -535,6 +637,7 @@ mod test_snapshots { pass/var_when.expr, pass/when_if_guard.expr, pass/when_in_assignment.expr, + pass/when_in_binops.expr, pass/when_in_function.expr, pass/when_in_function_python_style_indent.expr, pass/when_in_parens.expr, diff --git a/crates/language_server/src/analysis/tokens.rs b/crates/language_server/src/analysis/tokens.rs index 96ad8000db..1d9bc2fff4 100644 --- a/crates/language_server/src/analysis/tokens.rs +++ b/crates/language_server/src/analysis/tokens.rs @@ -687,8 +687,13 @@ impl IterTokens for Loc> { .chain(e2.iter_tokens(arena)) .collect_in(arena), Expr::Dbg => onetoken(Token::Keyword, region, arena), - Expr::DbgStmt(e1, e2) => (e1.iter_tokens(arena).into_iter()) - .chain(e2.iter_tokens(arena)) + Expr::DbgStmt { + first, + extra_args, + continuation, + } => (first.iter_tokens(arena).into_iter()) + .chain(extra_args.iter_tokens(arena)) + .chain(continuation.iter_tokens(arena)) .collect_in(arena), Expr::LowLevelDbg(_, e1, e2) => (e1.iter_tokens(arena).into_iter()) .chain(e2.iter_tokens(arena)) diff --git a/crates/reporting/src/error/parse.rs b/crates/reporting/src/error/parse.rs index 5e34152408..62a36dda73 100644 --- a/crates/reporting/src/error/parse.rs +++ b/crates/reporting/src/error/parse.rs @@ -1512,7 +1512,6 @@ fn to_dbg_or_expect_report<'a>( to_space_report(alloc, lines, filename, err, *pos) } - roc_parse::parser::EExpect::DbgArity(_) => todo!(), roc_parse::parser::EExpect::Dbg(_) => unreachable!("another branch would be taken"), roc_parse::parser::EExpect::Expect(_) => unreachable!("another branch would be taken"),