mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
Merge branch 'main' into inline-imports
This commit is contained in:
commit
d5a38a26db
667 changed files with 22300 additions and 14562 deletions
|
@ -12,5 +12,6 @@ roc_collections = { path = "../collections" }
|
|||
roc_module = { path = "../module" }
|
||||
roc_parse = { path = "../parse" }
|
||||
roc_region = { path = "../region" }
|
||||
roc_error_macros = { path = "../../error_macros" }
|
||||
|
||||
bumpalo.workspace = true
|
||||
|
|
|
@ -376,10 +376,11 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
Dbg { condition, .. } => condition.is_multiline(),
|
||||
ModuleImport(module_import) => module_import.is_multiline(),
|
||||
IngestedFileImport(ingested_file_import) => ingested_file_import.is_multiline(),
|
||||
Stmt(loc_expr) => loc_expr.is_multiline(),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, _parens: Parens, newlines: Newlines, indent: u16) {
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
use roc_parse::ast::ValueDef::*;
|
||||
match self {
|
||||
Annotation(loc_pattern, loc_annotation) => {
|
||||
|
@ -420,6 +421,7 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
}
|
||||
ModuleImport(module_import) => module_import.format(buf, indent),
|
||||
IngestedFileImport(ingested_file_import) => ingested_file_import.format(buf, indent),
|
||||
Stmt(loc_expr) => loc_expr.format_with_options(buf, parens, newlines, indent),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -539,9 +541,19 @@ pub fn fmt_defs(buf: &mut Buf, defs: &Defs, indent: u16) {
|
|||
}
|
||||
|
||||
pub fn fmt_body<'a>(buf: &mut Buf, pattern: &'a Pattern<'a>, body: &'a Expr<'a>, indent: u16) {
|
||||
pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent);
|
||||
buf.indent(indent);
|
||||
buf.push_str(" =");
|
||||
// Check if this is an assignment into the unit value
|
||||
let is_unit_assignment = if let Pattern::RecordDestructure(collection) = pattern {
|
||||
collection.is_empty()
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
// Don't format the `{} =` for defs with this pattern
|
||||
if !is_unit_assignment {
|
||||
pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent);
|
||||
buf.indent(indent);
|
||||
buf.push_str(" =");
|
||||
}
|
||||
|
||||
if body.is_multiline() {
|
||||
match body {
|
||||
|
|
|
@ -9,8 +9,8 @@ use crate::spaces::{
|
|||
use crate::Buf;
|
||||
use roc_module::called_via::{self, BinOp};
|
||||
use roc_parse::ast::{
|
||||
AssignedField, Base, Collection, CommentOrNewline, Expr, ExtractSpaces, Pattern,
|
||||
RecordBuilderField, WhenBranch,
|
||||
is_loc_expr_suffixed, AssignedField, Base, Collection, CommentOrNewline, Expr, ExtractSpaces,
|
||||
Pattern, RecordBuilderField, WhenBranch,
|
||||
};
|
||||
use roc_parse::ast::{StrLiteral, StrSegment};
|
||||
use roc_parse::ident::Accessor;
|
||||
|
@ -31,6 +31,8 @@ impl<'a> Formattable for Expr<'a> {
|
|||
true
|
||||
}
|
||||
|
||||
MalformedSuffixed(loc_expr) => loc_expr.is_multiline(),
|
||||
|
||||
// These expressions never have newlines
|
||||
Float(..)
|
||||
| Num(..)
|
||||
|
@ -46,6 +48,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
| Tag(_)
|
||||
| OpaqueRef(_)
|
||||
| IngestedFile(_, _)
|
||||
| EmptyDefsFinal
|
||||
| Crash => false,
|
||||
|
||||
// These expressions always have newlines
|
||||
|
@ -167,7 +170,11 @@ impl<'a> Formattable for Expr<'a> {
|
|||
Str(literal) => {
|
||||
fmt_str_literal(buf, *literal, indent);
|
||||
}
|
||||
Var { module_name, ident } => {
|
||||
Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
} => {
|
||||
buf.indent(indent);
|
||||
if !module_name.is_empty() {
|
||||
buf.push_str(module_name);
|
||||
|
@ -175,6 +182,11 @@ impl<'a> Formattable for Expr<'a> {
|
|||
}
|
||||
|
||||
buf.push_str(ident);
|
||||
|
||||
let count: u8 = *suffixed;
|
||||
for _ in 0..count {
|
||||
buf.push('!');
|
||||
}
|
||||
}
|
||||
Underscore(name) => {
|
||||
buf.indent(indent);
|
||||
|
@ -416,6 +428,9 @@ impl<'a> Formattable for Expr<'a> {
|
|||
indent,
|
||||
);
|
||||
}
|
||||
EmptyDefsFinal => {
|
||||
// no need to print anything
|
||||
}
|
||||
_ => {
|
||||
buf.ensure_ends_with_newline();
|
||||
buf.indent(indent);
|
||||
|
@ -432,6 +447,9 @@ impl<'a> Formattable for Expr<'a> {
|
|||
buf.push(')');
|
||||
}
|
||||
}
|
||||
EmptyDefsFinal => {
|
||||
// no need to print anything
|
||||
}
|
||||
Expect(condition, continuation) => {
|
||||
fmt_expect(buf, condition, continuation, self.is_multiline(), indent);
|
||||
}
|
||||
|
@ -494,19 +512,69 @@ impl<'a> Formattable for Expr<'a> {
|
|||
}
|
||||
}
|
||||
RecordAccess(expr, key) => {
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
// Check for any `!` suffixes and format these at the end of expression
|
||||
let (expr_to_format, suffix_count) = if let Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
} = expr
|
||||
{
|
||||
(
|
||||
Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed: 0,
|
||||
},
|
||||
suffixed,
|
||||
)
|
||||
} else {
|
||||
(**expr, &0u8)
|
||||
};
|
||||
|
||||
expr_to_format.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
buf.push('.');
|
||||
buf.push_str(key);
|
||||
|
||||
for _ in 0..*suffix_count {
|
||||
buf.push('!');
|
||||
}
|
||||
}
|
||||
TupleAccess(expr, key) => {
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
// Check for any `!` suffixes and format these at the end of expression
|
||||
let (expr_to_format, suffix_count) = if let Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
} = expr
|
||||
{
|
||||
(
|
||||
Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed: 0,
|
||||
},
|
||||
suffixed,
|
||||
)
|
||||
} else {
|
||||
(**expr, &0u8)
|
||||
};
|
||||
|
||||
expr_to_format.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
buf.push('.');
|
||||
buf.push_str(key);
|
||||
|
||||
for _ in 0..*suffix_count {
|
||||
buf.push('!');
|
||||
}
|
||||
}
|
||||
MalformedIdent(str, _) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(str)
|
||||
}
|
||||
MalformedSuffixed(loc_expr) => {
|
||||
buf.indent(indent);
|
||||
loc_expr.format_with_options(buf, parens, newlines, indent);
|
||||
}
|
||||
MalformedClosure => {}
|
||||
PrecedenceConflict { .. } => {}
|
||||
MultipleRecordBuilders { .. } => {}
|
||||
|
@ -612,18 +680,7 @@ fn format_str_segment(seg: &StrSegment, buf: &mut Buf, indent: u16) {
|
|||
buf.push('\\');
|
||||
buf.push(escaped.to_parsed_char());
|
||||
}
|
||||
DeprecatedInterpolated(loc_expr) => {
|
||||
buf.push_str("\\(");
|
||||
// e.g. (name) in "Hi, $(name)!"
|
||||
loc_expr.value.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded, // We already printed parens!
|
||||
Newlines::No, // Interpolations can never have newlines
|
||||
indent,
|
||||
);
|
||||
buf.push(')');
|
||||
}
|
||||
Interpolated(loc_expr) => {
|
||||
DeprecatedInterpolated(loc_expr) | Interpolated(loc_expr) => {
|
||||
buf.push_str("$(");
|
||||
// e.g. (name) in "Hi, $(name)!"
|
||||
loc_expr.value.format_with_options(
|
||||
|
@ -732,14 +789,32 @@ fn fmt_binops<'a>(
|
|||
|| loc_right_side.value.is_multiline()
|
||||
|| lefts.iter().any(|(expr, _)| expr.value.is_multiline());
|
||||
|
||||
let is_any_lefts_suffixed = lefts.iter().any(|(left, _)| is_loc_expr_suffixed(left));
|
||||
let is_right_suffixed = is_loc_expr_suffixed(loc_right_side);
|
||||
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, indent);
|
||||
loc_left_side.format_with_options(buf, Parens::InOperator, Newlines::No, adjusted_indent);
|
||||
|
||||
if is_first {
|
||||
// indent the remaining lines, but only if the expression is suffixed.
|
||||
is_first = false;
|
||||
adjusted_indent = indent + 4;
|
||||
}
|
||||
|
||||
if is_multiline {
|
||||
buf.ensure_ends_with_newline();
|
||||
buf.indent(indent);
|
||||
buf.indent(adjusted_indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
@ -749,7 +824,7 @@ fn fmt_binops<'a>(
|
|||
buf.spaces(1);
|
||||
}
|
||||
|
||||
loc_right_side.format_with_options(buf, Parens::InOperator, Newlines::Yes, indent);
|
||||
loc_right_side.format_with_options(buf, Parens::InOperator, Newlines::Yes, adjusted_indent);
|
||||
}
|
||||
|
||||
fn format_spaces(buf: &mut Buf, spaces: &[CommentOrNewline], newlines: Newlines, indent: u16) {
|
||||
|
|
|
@ -41,8 +41,12 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
fn is_multiline(&self) -> bool {
|
||||
// Theory: a pattern should only be multiline when it contains a comment
|
||||
match self {
|
||||
Pattern::SpaceBefore(_, spaces) | Pattern::SpaceAfter(_, spaces) => {
|
||||
debug_assert!(!spaces.is_empty());
|
||||
Pattern::SpaceBefore(pattern, spaces) | Pattern::SpaceAfter(pattern, spaces) => {
|
||||
debug_assert!(
|
||||
!spaces.is_empty(),
|
||||
"spaces is empty in pattern {:#?}",
|
||||
pattern
|
||||
);
|
||||
|
||||
spaces.iter().any(|s| s.is_comment())
|
||||
}
|
||||
|
@ -60,7 +64,7 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
}
|
||||
},
|
||||
|
||||
Pattern::Identifier(_)
|
||||
Pattern::Identifier { .. }
|
||||
| Pattern::Tag(_)
|
||||
| Pattern::OpaqueRef(_)
|
||||
| Pattern::Apply(_, _)
|
||||
|
@ -84,9 +88,16 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
use self::Pattern::*;
|
||||
|
||||
match self {
|
||||
Identifier(string) => {
|
||||
Identifier {
|
||||
ident: string,
|
||||
suffixed,
|
||||
} => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string)
|
||||
buf.push_str(string);
|
||||
|
||||
for _ in 0..*suffixed {
|
||||
buf.push('!');
|
||||
}
|
||||
}
|
||||
Tag(name) | OpaqueRef(name) => {
|
||||
buf.indent(indent);
|
||||
|
@ -266,13 +277,21 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
QualifiedIdentifier { module_name, ident } => {
|
||||
QualifiedIdentifier {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
} => {
|
||||
buf.indent(indent);
|
||||
if !module_name.is_empty() {
|
||||
buf.push_str(module_name);
|
||||
buf.push('.');
|
||||
}
|
||||
|
||||
for _ in 0..*suffixed {
|
||||
buf.push('!');
|
||||
}
|
||||
|
||||
buf.push_str(ident);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,7 +155,9 @@ fn fmt_comment(buf: &mut Buf, comment: &str) {
|
|||
}
|
||||
|
||||
buf.push('#');
|
||||
if !comment.starts_with(' ') {
|
||||
// Add a space between the starting `#` and the rest of the comment,
|
||||
// unless there already is a space or the comment is of the form `#### something`.
|
||||
if !comment.starts_with(' ') && !comment.starts_with('#') {
|
||||
buf.spaces(1);
|
||||
}
|
||||
buf.push_str(comment.trim_end());
|
||||
|
@ -207,7 +209,7 @@ fn fmt_docs(buf: &mut Buf, docs: &str) {
|
|||
/// * Removing comments
|
||||
/// * Removing parens in Exprs
|
||||
///
|
||||
/// Long term, we actuall want this transform to preserve comments (so we can assert they're maintained by formatting)
|
||||
/// Long term, we actually want this transform to preserve comments (so we can assert they're maintained by formatting)
|
||||
/// - but there are currently several bugs where they're _not_ preserved.
|
||||
/// TODO: ensure formatting retains comments
|
||||
pub trait RemoveSpaces<'a> {
|
||||
|
@ -570,6 +572,7 @@ impl<'a> RemoveSpaces<'a> for ValueDef<'a> {
|
|||
IngestedFileImport(ingested_file_import) => {
|
||||
IngestedFileImport(ingested_file_import.remove_spaces(arena))
|
||||
}
|
||||
Stmt(loc_expr) => Stmt(arena.alloc(loc_expr.remove_spaces(arena))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -719,6 +722,7 @@ impl<'a> RemoveSpaces<'a> for StrSegment<'a> {
|
|||
impl<'a> RemoveSpaces<'a> for Expr<'a> {
|
||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||
match *self {
|
||||
Expr::EmptyDefsFinal => Expr::EmptyDefsFinal,
|
||||
Expr::Float(a) => Expr::Float(a),
|
||||
Expr::Num(a) => Expr::Num(a),
|
||||
Expr::NonBase10Int {
|
||||
|
@ -743,7 +747,15 @@ impl<'a> RemoveSpaces<'a> for Expr<'a> {
|
|||
Expr::Record(a) => Expr::Record(a.remove_spaces(arena)),
|
||||
Expr::RecordBuilder(a) => Expr::RecordBuilder(a.remove_spaces(arena)),
|
||||
Expr::Tuple(a) => Expr::Tuple(a.remove_spaces(arena)),
|
||||
Expr::Var { module_name, ident } => Expr::Var { module_name, ident },
|
||||
Expr::Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
} => Expr::Var {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
},
|
||||
Expr::Underscore(a) => Expr::Underscore(a),
|
||||
Expr::Tag(a) => Expr::Tag(a),
|
||||
Expr::OpaqueRef(a) => Expr::OpaqueRef(a),
|
||||
|
@ -806,6 +818,7 @@ impl<'a> RemoveSpaces<'a> for Expr<'a> {
|
|||
}
|
||||
Expr::MalformedIdent(a, b) => Expr::MalformedIdent(a, remove_spaces_bad_ident(b)),
|
||||
Expr::MalformedClosure => Expr::MalformedClosure,
|
||||
Expr::MalformedSuffixed(a) => Expr::MalformedSuffixed(a),
|
||||
Expr::PrecedenceConflict(a) => Expr::PrecedenceConflict(a),
|
||||
Expr::MultipleRecordBuilders(a) => Expr::MultipleRecordBuilders(a),
|
||||
Expr::UnappliedRecordBuilder(a) => Expr::UnappliedRecordBuilder(a),
|
||||
|
@ -842,7 +855,7 @@ fn remove_spaces_bad_ident(ident: BadIdent) -> BadIdent {
|
|||
impl<'a> RemoveSpaces<'a> for Pattern<'a> {
|
||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||
match *self {
|
||||
Pattern::Identifier(a) => Pattern::Identifier(a),
|
||||
Pattern::Identifier { ident, suffixed } => Pattern::Identifier { ident, suffixed },
|
||||
Pattern::Tag(a) => Pattern::Tag(a),
|
||||
Pattern::OpaqueRef(a) => Pattern::OpaqueRef(a),
|
||||
Pattern::Apply(a, b) => Pattern::Apply(
|
||||
|
@ -875,9 +888,15 @@ impl<'a> RemoveSpaces<'a> for Pattern<'a> {
|
|||
Pattern::Underscore(a) => Pattern::Underscore(a),
|
||||
Pattern::Malformed(a) => Pattern::Malformed(a),
|
||||
Pattern::MalformedIdent(a, b) => Pattern::MalformedIdent(a, remove_spaces_bad_ident(b)),
|
||||
Pattern::QualifiedIdentifier { module_name, ident } => {
|
||||
Pattern::QualifiedIdentifier { module_name, ident }
|
||||
}
|
||||
Pattern::QualifiedIdentifier {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
} => Pattern::QualifiedIdentifier {
|
||||
module_name,
|
||||
ident,
|
||||
suffixed,
|
||||
},
|
||||
Pattern::SpaceBefore(a, _) => a.remove_spaces(arena),
|
||||
Pattern::SpaceAfter(a, _) => a.remove_spaces(arena),
|
||||
Pattern::SingleQuote(a) => Pattern::SingleQuote(a),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue