mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
Parsing support for snake_case identifiers
In this initial commit, I have done the following: - Added unit tests to roc_parse's ident.rs file to cover at least the simplest Ident enum cases (Tag, OpaqueRef, and simple Access) - Added '_' as a valid "rest" character in both uppercase and lowercase identifier parts - Updated the test_syntax snapshots appropriately There is still a lot left to do here. Such as: - Do we want to allow multiple '_'s to parse successfully? - Handle qualified access - Handle accessor functions - Handle record update functions - Remove the UnderscoreInMiddle case from BadIdent - Write unit tests for Malformed Idents I am not a "Rustacean" by any means, but have been through the Book in years past. Any feedback on the way I wrote the tests or any other part of the implementation would be very appreciated.
This commit is contained in:
parent
d7825428df
commit
a2083cec30
31 changed files with 1214 additions and 460 deletions
|
@ -4,6 +4,7 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use bumpalo::Bump;
|
||||
use roc_error_macros::{internal_error, user_error};
|
||||
use roc_fmt::annotation::MigrationFlags;
|
||||
use roc_fmt::def::fmt_defs;
|
||||
use roc_fmt::header::fmt_header;
|
||||
use roc_fmt::Buf;
|
||||
|
@ -63,14 +64,18 @@ fn is_roc_file(path: &Path) -> bool {
|
|||
matches!(path.extension().and_then(OsStr::to_str), Some("roc"))
|
||||
}
|
||||
|
||||
pub fn format_files(files: std::vec::Vec<PathBuf>, mode: FormatMode) -> Result<(), String> {
|
||||
pub fn format_files(
|
||||
files: std::vec::Vec<PathBuf>,
|
||||
mode: FormatMode,
|
||||
flags: &MigrationFlags,
|
||||
) -> Result<(), String> {
|
||||
let arena = Bump::new();
|
||||
let mut files_to_reformat = Vec::new(); // to track which files failed `roc format --check`
|
||||
|
||||
for file in flatten_directories(files) {
|
||||
let src = std::fs::read_to_string(&file).unwrap();
|
||||
|
||||
match format_src(&arena, &src) {
|
||||
match format_src(&arena, &src, flags) {
|
||||
Ok(buf) => {
|
||||
match mode {
|
||||
FormatMode::CheckOnly => {
|
||||
|
@ -183,12 +188,16 @@ pub enum FormatProblem {
|
|||
},
|
||||
}
|
||||
|
||||
pub fn format_src(arena: &Bump, src: &str) -> Result<String, FormatProblem> {
|
||||
pub fn format_src(
|
||||
arena: &Bump,
|
||||
src: &str,
|
||||
flags: &MigrationFlags,
|
||||
) -> Result<String, FormatProblem> {
|
||||
let ast = arena.alloc(parse_all(arena, src).unwrap_or_else(|e| {
|
||||
user_error!("Unexpected parse failure when parsing this formatting:\n\n{:?}\n\nParse error was:\n\n{:?}\n\n", src, e)
|
||||
}));
|
||||
let mut buf = Buf::new_in(arena);
|
||||
fmt_all(&mut buf, ast);
|
||||
fmt_all(&mut buf, ast, flags);
|
||||
|
||||
let reparsed_ast = match arena.alloc(parse_all(arena, buf.as_str())) {
|
||||
Ok(ast) => ast,
|
||||
|
@ -208,7 +217,9 @@ pub fn format_src(arena: &Bump, src: &str) -> Result<String, FormatProblem> {
|
|||
// the PartialEq implementation is returning `false` even when the Debug-formatted impl is exactly the same.
|
||||
// I don't have the patience to debug this right now, so let's leave it for another day...
|
||||
// TODO: fix PartialEq impl on ast types
|
||||
if format!("{ast_normalized:?}") != format!("{reparsed_ast_normalized:?}") {
|
||||
if !flags.at_least_one_active()
|
||||
&& format!("{ast_normalized:?}") != format!("{reparsed_ast_normalized:?}")
|
||||
{
|
||||
return Err(FormatProblem::ReformattingChangedAst {
|
||||
formatted_src: buf.as_str().to_string(),
|
||||
ast_before: format!("{ast_normalized:#?}\n"),
|
||||
|
@ -219,7 +230,7 @@ pub fn format_src(arena: &Bump, src: &str) -> Result<String, FormatProblem> {
|
|||
// Now verify that the resultant formatting is _stable_ - i.e. that it doesn't change again if re-formatted
|
||||
let mut reformatted_buf = Buf::new_in(arena);
|
||||
|
||||
fmt_all(&mut reformatted_buf, reparsed_ast);
|
||||
fmt_all(&mut reformatted_buf, reparsed_ast, flags);
|
||||
|
||||
if buf.as_str() != reformatted_buf.as_str() {
|
||||
return Err(FormatProblem::ReformattingUnstable {
|
||||
|
@ -248,10 +259,10 @@ fn parse_all<'a>(arena: &'a Bump, src: &'a str) -> Result<FullAst<'a>, SyntaxErr
|
|||
})
|
||||
}
|
||||
|
||||
fn fmt_all<'a>(buf: &mut Buf<'a>, ast: &'a FullAst) {
|
||||
fmt_header(buf, &ast.header);
|
||||
fn fmt_all<'a>(buf: &mut Buf<'a>, ast: &'a FullAst, flags: &MigrationFlags) {
|
||||
fmt_header(buf, &ast.header, flags);
|
||||
|
||||
fmt_defs(buf, &ast.defs, 0);
|
||||
fmt_defs(buf, &ast.defs, flags, 0);
|
||||
|
||||
buf.fmt_end_of_file();
|
||||
}
|
||||
|
@ -298,8 +309,9 @@ main =
|
|||
fn test_single_file_needs_reformatting() {
|
||||
let dir = tempdir().unwrap();
|
||||
let file_path = setup_test_file(dir.path(), "test1.roc", UNFORMATTED_ROC);
|
||||
let flags = MigrationFlags::new(false);
|
||||
|
||||
let result = format_files(vec![file_path.clone()], FormatMode::CheckOnly);
|
||||
let result = format_files(vec![file_path.clone()], FormatMode::CheckOnly, &flags);
|
||||
assert!(result.is_err());
|
||||
assert_eq!(
|
||||
result.unwrap_err(),
|
||||
|
@ -317,8 +329,9 @@ main =
|
|||
let dir = tempdir().unwrap();
|
||||
let file1 = setup_test_file(dir.path(), "test1.roc", UNFORMATTED_ROC);
|
||||
let file2 = setup_test_file(dir.path(), "test2.roc", UNFORMATTED_ROC);
|
||||
let flags = MigrationFlags::new(false);
|
||||
|
||||
let result = format_files(vec![file1, file2], FormatMode::CheckOnly);
|
||||
let result = format_files(vec![file1, file2], FormatMode::CheckOnly, &flags);
|
||||
assert!(result.is_err());
|
||||
let error_message = result.unwrap_err();
|
||||
assert!(error_message.contains("test1.roc") && error_message.contains("test2.roc"));
|
||||
|
@ -330,8 +343,9 @@ main =
|
|||
fn test_no_files_need_reformatting() {
|
||||
let dir = tempdir().unwrap();
|
||||
let file_path = setup_test_file(dir.path(), "formatted.roc", FORMATTED_ROC);
|
||||
let flags = MigrationFlags::new(false);
|
||||
|
||||
let result = format_files(vec![file_path], FormatMode::CheckOnly);
|
||||
let result = format_files(vec![file_path], FormatMode::CheckOnly, &flags);
|
||||
assert!(result.is_ok());
|
||||
|
||||
cleanup_temp_dir(dir);
|
||||
|
@ -343,10 +357,12 @@ main =
|
|||
let file_formatted = setup_test_file(dir.path(), "formatted.roc", FORMATTED_ROC);
|
||||
let file1_unformated = setup_test_file(dir.path(), "test1.roc", UNFORMATTED_ROC);
|
||||
let file2_unformated = setup_test_file(dir.path(), "test2.roc", UNFORMATTED_ROC);
|
||||
let flags = MigrationFlags::new(false);
|
||||
|
||||
let result = format_files(
|
||||
vec![file_formatted, file1_unformated, file2_unformated],
|
||||
FormatMode::CheckOnly,
|
||||
&flags,
|
||||
);
|
||||
assert!(result.is_err());
|
||||
let error_message = result.unwrap_err();
|
||||
|
|
|
@ -89,6 +89,7 @@ pub const ARGS_FOR_APP: &str = "ARGS_FOR_APP";
|
|||
pub const FLAG_PP_HOST: &str = "host";
|
||||
pub const FLAG_PP_PLATFORM: &str = "platform";
|
||||
pub const FLAG_PP_DYLIB: &str = "lib";
|
||||
pub const FLAG_MIGRATE: &str = "migrate";
|
||||
|
||||
pub const VERSION: &str = env!("ROC_VERSION");
|
||||
const DEFAULT_GENERATED_DOCS_DIR: &str = "generated-docs";
|
||||
|
@ -344,6 +345,13 @@ pub fn build_app() -> Command {
|
|||
.action(ArgAction::SetTrue)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(FLAG_MIGRATE)
|
||||
.long(FLAG_MIGRATE)
|
||||
.help("Will fixup syntax to match the latest preferred style. This can cause changes to variable names and more.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(FLAG_STDIN)
|
||||
.long(FLAG_STDIN)
|
||||
|
|
|
@ -5,12 +5,14 @@ use roc_build::program::{check_file, CodeGenBackend};
|
|||
use roc_cli::{
|
||||
build_app, format_files, format_src, test, BuildConfig, FormatMode, CMD_BUILD, CMD_CHECK,
|
||||
CMD_DEV, CMD_DOCS, CMD_FORMAT, CMD_GLUE, CMD_PREPROCESS_HOST, CMD_REPL, CMD_RUN, CMD_TEST,
|
||||
CMD_VERSION, DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_LIB, FLAG_MAIN, FLAG_NO_COLOR,
|
||||
FLAG_NO_HEADER, FLAG_NO_LINK, FLAG_OUTPUT, FLAG_PP_DYLIB, FLAG_PP_HOST, FLAG_PP_PLATFORM,
|
||||
FLAG_STDIN, FLAG_STDOUT, FLAG_TARGET, FLAG_TIME, GLUE_DIR, GLUE_SPEC, ROC_FILE, VERSION,
|
||||
CMD_VERSION, DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_LIB, FLAG_MAIN, FLAG_MIGRATE,
|
||||
FLAG_NO_COLOR, FLAG_NO_HEADER, FLAG_NO_LINK, FLAG_OUTPUT, FLAG_PP_DYLIB, FLAG_PP_HOST,
|
||||
FLAG_PP_PLATFORM, FLAG_STDIN, FLAG_STDOUT, FLAG_TARGET, FLAG_TIME, GLUE_DIR, GLUE_SPEC,
|
||||
ROC_FILE, VERSION,
|
||||
};
|
||||
use roc_docs::generate_docs_html;
|
||||
use roc_error_macros::user_error;
|
||||
use roc_fmt::annotation::MigrationFlags;
|
||||
use roc_gen_dev::AssemblyBackendMode;
|
||||
use roc_gen_llvm::llvm::build::LlvmBackendMode;
|
||||
use roc_load::{LoadingProblem, Threading};
|
||||
|
@ -310,6 +312,7 @@ fn main() -> io::Result<()> {
|
|||
Some((CMD_FORMAT, matches)) => {
|
||||
let from_stdin = matches.get_flag(FLAG_STDIN);
|
||||
let to_stdout = matches.get_flag(FLAG_STDOUT);
|
||||
let migrate = matches.get_flag(FLAG_MIGRATE);
|
||||
let format_mode = if to_stdout {
|
||||
FormatMode::WriteToStdout
|
||||
} else {
|
||||
|
@ -318,6 +321,7 @@ fn main() -> io::Result<()> {
|
|||
false => FormatMode::WriteToFile,
|
||||
}
|
||||
};
|
||||
let flags = MigrationFlags::new(migrate);
|
||||
|
||||
if from_stdin && matches!(format_mode, FormatMode::WriteToFile) {
|
||||
eprintln!("When using the --stdin flag, either the --check or the --stdout flag must also be specified. (Otherwise, it's unclear what filename to write to!)");
|
||||
|
@ -370,7 +374,7 @@ fn main() -> io::Result<()> {
|
|||
std::process::exit(1);
|
||||
});
|
||||
|
||||
match format_src(&arena, src) {
|
||||
match format_src(&arena, src, &flags) {
|
||||
Ok(formatted_src) => {
|
||||
match format_mode {
|
||||
FormatMode::CheckOnly => {
|
||||
|
@ -402,7 +406,7 @@ fn main() -> io::Result<()> {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
match format_files(roc_files, format_mode) {
|
||||
match format_files(roc_files, format_mode, &flags) {
|
||||
Ok(()) => 0,
|
||||
Err(message) => {
|
||||
eprintln!("{message}");
|
||||
|
|
|
@ -273,6 +273,14 @@ pub fn canonicalize_def_header_pattern<'a>(
|
|||
region,
|
||||
) {
|
||||
Ok((symbol, shadowing_ability_member)) => {
|
||||
if name.contains("__") {
|
||||
env.problem(Problem::RuntimeError(RuntimeError::MalformedPattern(
|
||||
MalformedPatternProblem::BadIdent(
|
||||
roc_parse::ident::BadIdent::TooManyUnderscores(region.start()),
|
||||
),
|
||||
region,
|
||||
)));
|
||||
}
|
||||
let can_pattern = match shadowing_ability_member {
|
||||
// A fresh identifier.
|
||||
None => {
|
||||
|
|
|
@ -67,13 +67,34 @@ impl Newlines {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct MigrationFlags {
|
||||
pub(crate) snakify: bool,
|
||||
}
|
||||
|
||||
impl MigrationFlags {
|
||||
pub fn new(snakify: bool) -> Self {
|
||||
MigrationFlags { snakify }
|
||||
}
|
||||
|
||||
pub fn at_least_one_active(&self) -> bool {
|
||||
self.snakify
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Formattable {
|
||||
fn is_multiline(&self) -> bool;
|
||||
|
||||
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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
);
|
||||
|
||||
fn format(&self, buf: &mut Buf, indent: u16) {
|
||||
self.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
fn format(&self, buf: &mut Buf, flags: &MigrationFlags, indent: u16) {
|
||||
self.format_with_options(buf, Parens::NotNeeded, Newlines::No, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,12 +107,19 @@ where
|
|||
(*self).is_multiline()
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
(*self).format_with_options(buf, parens, newlines, indent)
|
||||
fn format_with_options(
|
||||
&self,
|
||||
buf: &mut Buf,
|
||||
parens: Parens,
|
||||
newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
(*self).format_with_options(buf, parens, newlines, flags, indent)
|
||||
}
|
||||
|
||||
fn format(&self, buf: &mut Buf, indent: u16) {
|
||||
(*self).format(buf, indent)
|
||||
fn format(&self, buf: &mut Buf, flags: &MigrationFlags, indent: u16) {
|
||||
(*self).format(buf, flags, indent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,13 +141,20 @@ where
|
|||
self.value.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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
self.value
|
||||
.format_with_options(buf, parens, newlines, indent)
|
||||
.format_with_options(buf, parens, newlines, flags, indent)
|
||||
}
|
||||
|
||||
fn format(&self, buf: &mut Buf, indent: u16) {
|
||||
self.value.format(buf, indent)
|
||||
fn format(&self, buf: &mut Buf, flags: &MigrationFlags, indent: u16) {
|
||||
self.value.format(buf, flags, indent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,6 +168,7 @@ impl<'a> Formattable for UppercaseIdent<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
_flags: &MigrationFlags,
|
||||
_indent: u16,
|
||||
) {
|
||||
buf.push_str((*self).into())
|
||||
|
@ -195,14 +231,22 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, newlines: Newlines, indent: u16) {
|
||||
fmt_ty_ann(self, buf, indent, parens, newlines, false);
|
||||
fn format_with_options(
|
||||
&self,
|
||||
buf: &mut Buf,
|
||||
parens: Parens,
|
||||
newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_ty_ann(self, buf, flags, indent, parens, newlines, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_ty_ann(
|
||||
me: &TypeAnnotation<'_>,
|
||||
buf: &mut Buf<'_>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
parens: Parens,
|
||||
newlines: Newlines,
|
||||
|
@ -248,6 +292,7 @@ fn fmt_ty_ann(
|
|||
fmt_ty_ann(
|
||||
&argument.value,
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Parens::InFunctionType,
|
||||
Newlines::Yes,
|
||||
|
@ -270,7 +315,7 @@ fn fmt_ty_ann(
|
|||
buf.spaces(1);
|
||||
|
||||
ret.value
|
||||
.format_with_options(buf, Parens::InFunctionType, Newlines::No, indent);
|
||||
.format_with_options(buf, Parens::InFunctionType, Newlines::No, flags, indent);
|
||||
|
||||
if needs_parens {
|
||||
buf.push(')')
|
||||
|
@ -312,12 +357,17 @@ fn fmt_ty_ann(
|
|||
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);
|
||||
arg.item.format_with_options(
|
||||
buf,
|
||||
Parens::InApply,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
arg_indent,
|
||||
);
|
||||
fmt_spaces(buf, arg.after.iter(), arg_indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
arg.format_with_options(buf, Parens::InApply, Newlines::No, arg_indent);
|
||||
arg.format_with_options(buf, Parens::InApply, Newlines::No, flags, arg_indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,24 +389,24 @@ fn fmt_ty_ann(
|
|||
}
|
||||
|
||||
TypeAnnotation::TagUnion { tags, ext } => {
|
||||
fmt_collection(buf, indent, Braces::Square, *tags, newlines);
|
||||
fmt_ext(ext, buf, indent);
|
||||
fmt_collection(buf, flags, indent, Braces::Square, *tags, newlines);
|
||||
fmt_ext(ext, buf, flags, indent);
|
||||
}
|
||||
|
||||
TypeAnnotation::Tuple { elems: fields, ext } => {
|
||||
fmt_ty_collection(buf, indent, Braces::Round, *fields, newlines);
|
||||
fmt_ext(ext, buf, indent);
|
||||
fmt_ty_collection(buf, flags, indent, Braces::Round, *fields, newlines);
|
||||
fmt_ext(ext, buf, flags, indent);
|
||||
}
|
||||
|
||||
TypeAnnotation::Record { fields, ext } => {
|
||||
fmt_collection(buf, indent, Braces::Curly, *fields, newlines);
|
||||
fmt_ext(ext, buf, indent);
|
||||
fmt_collection(buf, flags, indent, Braces::Curly, *fields, newlines);
|
||||
fmt_ext(ext, buf, flags, indent);
|
||||
}
|
||||
|
||||
TypeAnnotation::As(lhs, _spaces, TypeHeader { name, vars }) => {
|
||||
// TODO use _spaces?
|
||||
lhs.value
|
||||
.format_with_options(buf, Parens::InFunctionType, Newlines::No, indent);
|
||||
.format_with_options(buf, Parens::InFunctionType, Newlines::No, flags, indent);
|
||||
buf.spaces(1);
|
||||
buf.push_str("as");
|
||||
buf.spaces(1);
|
||||
|
@ -364,12 +414,12 @@ fn fmt_ty_ann(
|
|||
for var in *vars {
|
||||
buf.spaces(1);
|
||||
var.value
|
||||
.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
.format_with_options(buf, Parens::NotNeeded, Newlines::No, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
TypeAnnotation::Where(annot, implements_clauses) => {
|
||||
annot.format_with_options(buf, parens, newlines, indent);
|
||||
annot.format_with_options(buf, parens, newlines, flags, indent);
|
||||
if implements_clauses
|
||||
.iter()
|
||||
.any(|implements| implements.is_multiline())
|
||||
|
@ -386,7 +436,7 @@ fn fmt_ty_ann(
|
|||
","
|
||||
});
|
||||
buf.spaces(1);
|
||||
has.format_with_options(buf, parens, newlines, indent);
|
||||
has.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
}
|
||||
TypeAnnotation::Malformed(raw) => {
|
||||
|
@ -423,6 +473,7 @@ fn lower<'a, 'b: 'a>(
|
|||
|
||||
fn fmt_ty_collection(
|
||||
buf: &mut Buf<'_>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
braces: Braces,
|
||||
items: Collection<'_, Loc<TypeAnnotation<'_>>>,
|
||||
|
@ -459,10 +510,15 @@ fn fmt_ty_collection(
|
|||
let new_items =
|
||||
Collection::with_items_and_comments(arena, new_items.into_bump_slice(), final_comments);
|
||||
|
||||
fmt_collection(buf, indent, braces, new_items, newlines)
|
||||
fmt_collection(buf, flags, indent, braces, new_items, newlines)
|
||||
}
|
||||
|
||||
fn fmt_ext(ext: &Option<&Loc<TypeAnnotation<'_>>>, buf: &mut Buf<'_>, indent: u16) {
|
||||
fn fmt_ext(
|
||||
ext: &Option<&Loc<TypeAnnotation<'_>>>,
|
||||
buf: &mut Buf<'_>,
|
||||
flags: &MigrationFlags,
|
||||
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);
|
||||
|
@ -470,11 +526,11 @@ fn fmt_ext(ext: &Option<&Loc<TypeAnnotation<'_>>>, buf: &mut Buf<'_>, indent: u1
|
|||
// 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);
|
||||
loc_ext_ann.value.format(buf, flags, indent + INDENT);
|
||||
buf.indent(indent);
|
||||
buf.push(')');
|
||||
} else {
|
||||
loc_ext_ann.value.format(buf, indent + INDENT);
|
||||
loc_ext_ann.value.format(buf, flags, indent + INDENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -530,9 +586,16 @@ impl<'a> Formattable for AssignedField<'a, TypeAnnotation<'a>> {
|
|||
is_multiline_assigned_field_help(self)
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
// we abuse the `Newlines` type to decide between multiline or single-line layout
|
||||
format_assigned_field_help(self, buf, indent, 1, newlines == Newlines::Yes);
|
||||
format_assigned_field_help(self, buf, flags, indent, 1, newlines == Newlines::Yes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -541,9 +604,16 @@ impl<'a> Formattable for AssignedField<'a, Expr<'a>> {
|
|||
is_multiline_assigned_field_help(self)
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
// we abuse the `Newlines` type to decide between multiline or single-line layout
|
||||
format_assigned_field_help(self, buf, indent, 0, newlines == Newlines::Yes);
|
||||
format_assigned_field_help(self, buf, flags, indent, 0, newlines == Newlines::Yes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,6 +632,7 @@ fn is_multiline_assigned_field_help<T: Formattable>(afield: &AssignedField<'_, T
|
|||
fn format_assigned_field_help<T>(
|
||||
zelf: &AssignedField<T>,
|
||||
buf: &mut Buf,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
separator_spaces: usize,
|
||||
is_multiline: bool,
|
||||
|
@ -587,7 +658,7 @@ fn format_assigned_field_help<T>(
|
|||
buf.indent(indent);
|
||||
buf.push(':');
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
ann.value.format(buf, flags, indent);
|
||||
}
|
||||
OptionalValue(name, spaces, ann) => {
|
||||
if is_multiline {
|
||||
|
@ -605,7 +676,7 @@ fn format_assigned_field_help<T>(
|
|||
buf.indent(indent);
|
||||
buf.push('?');
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
ann.value.format(buf, flags, indent);
|
||||
}
|
||||
IgnoredValue(name, spaces, ann) => {
|
||||
if is_multiline {
|
||||
|
@ -623,7 +694,7 @@ fn format_assigned_field_help<T>(
|
|||
buf.spaces(separator_spaces);
|
||||
buf.push(':');
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
ann.value.format(buf, flags, indent);
|
||||
}
|
||||
LabelOnly(name) => {
|
||||
if is_multiline {
|
||||
|
@ -635,10 +706,24 @@ fn format_assigned_field_help<T>(
|
|||
}
|
||||
AssignedField::SpaceBefore(sub_field, spaces) => {
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
format_assigned_field_help(sub_field, buf, indent, separator_spaces, is_multiline);
|
||||
format_assigned_field_help(
|
||||
sub_field,
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
separator_spaces,
|
||||
is_multiline,
|
||||
);
|
||||
}
|
||||
AssignedField::SpaceAfter(sub_field, spaces) => {
|
||||
format_assigned_field_help(sub_field, buf, indent, separator_spaces, is_multiline);
|
||||
format_assigned_field_help(
|
||||
sub_field,
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
separator_spaces,
|
||||
is_multiline,
|
||||
);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
}
|
||||
|
@ -659,6 +744,7 @@ impl<'a> Formattable for Tag<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let is_multiline = self.is_multiline();
|
||||
|
@ -676,13 +762,14 @@ impl<'a> Formattable for Tag<'a> {
|
|||
buf,
|
||||
Parens::InApply,
|
||||
Newlines::No,
|
||||
flags,
|
||||
arg_indent,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
for arg in *args {
|
||||
buf.spaces(1);
|
||||
arg.format_with_options(buf, Parens::InApply, Newlines::No, indent);
|
||||
arg.format_with_options(buf, Parens::InApply, Newlines::No, flags, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -697,7 +784,14 @@ impl<'a> Formattable for ImplementsClause<'a> {
|
|||
false
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.push_str(self.var.value.extract_spaces().item);
|
||||
buf.spaces(1);
|
||||
buf.push_str(roc_parse::keyword::IMPLEMENTS);
|
||||
|
@ -709,7 +803,7 @@ impl<'a> Formattable for ImplementsClause<'a> {
|
|||
buf.push('&');
|
||||
buf.spaces(1);
|
||||
}
|
||||
ab.format_with_options(buf, parens, newlines, indent);
|
||||
ab.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -722,23 +816,30 @@ impl<'a> Formattable for AbilityImpls<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
match self {
|
||||
AbilityImpls::AbilityImpls(impls) => {
|
||||
if newlines == Newlines::Yes {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
}
|
||||
fmt_collection(buf, indent, Braces::Curly, *impls, Newlines::No);
|
||||
fmt_collection(buf, flags, indent, Braces::Curly, *impls, Newlines::No);
|
||||
}
|
||||
AbilityImpls::SpaceBefore(impls, spaces) => {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
impls.format_with_options(buf, parens, Newlines::No, indent);
|
||||
impls.format_with_options(buf, parens, Newlines::No, flags, indent);
|
||||
}
|
||||
AbilityImpls::SpaceAfter(impls, spaces) => {
|
||||
impls.format_with_options(buf, parens, newlines, indent);
|
||||
impls.format_with_options(buf, parens, newlines, flags, indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
}
|
||||
|
@ -755,27 +856,34 @@ impl<'a> Formattable for ImplementsAbility<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
match self {
|
||||
ImplementsAbility::ImplementsAbility { ability, impls } => {
|
||||
if newlines == Newlines::Yes {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
}
|
||||
ability.format_with_options(buf, parens, newlines, indent);
|
||||
ability.format_with_options(buf, parens, newlines, flags, indent);
|
||||
if let Some(impls) = impls {
|
||||
buf.spaces(1);
|
||||
impls.format_with_options(buf, parens, newlines, indent);
|
||||
impls.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
}
|
||||
ImplementsAbility::SpaceBefore(ab, spaces) => {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
ab.format_with_options(buf, parens, Newlines::No, indent)
|
||||
ab.format_with_options(buf, parens, Newlines::No, flags, indent)
|
||||
}
|
||||
ImplementsAbility::SpaceAfter(ab, spaces) => {
|
||||
ab.format_with_options(buf, parens, newlines, indent);
|
||||
ab.format_with_options(buf, parens, newlines, flags, indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
}
|
||||
|
@ -792,7 +900,14 @@ impl<'a> Formattable for ImplementsAbilities<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
match self {
|
||||
ImplementsAbilities::Implements(has_abilities) => {
|
||||
if newlines == Newlines::Yes {
|
||||
|
@ -801,16 +916,23 @@ impl<'a> Formattable for ImplementsAbilities<'a> {
|
|||
}
|
||||
buf.push_str(roc_parse::keyword::IMPLEMENTS);
|
||||
buf.spaces(1);
|
||||
fmt_collection(buf, indent, Braces::Square, *has_abilities, Newlines::No);
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Square,
|
||||
*has_abilities,
|
||||
Newlines::No,
|
||||
);
|
||||
}
|
||||
ImplementsAbilities::SpaceBefore(has_abilities, spaces) => {
|
||||
buf.newline();
|
||||
buf.indent(indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
has_abilities.format_with_options(buf, parens, Newlines::No, indent)
|
||||
has_abilities.format_with_options(buf, parens, Newlines::No, flags, indent)
|
||||
}
|
||||
ImplementsAbilities::SpaceAfter(has_abilities, spaces) => {
|
||||
has_abilities.format_with_options(buf, parens, newlines, indent);
|
||||
has_abilities.format_with_options(buf, parens, newlines, flags, indent);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
}
|
||||
}
|
||||
|
@ -934,7 +1056,14 @@ impl<'a> Formattable for Node<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
match self {
|
||||
Node::DelimitedSequence(braces, lefts, right) => {
|
||||
buf.indent(indent);
|
||||
|
@ -945,7 +1074,7 @@ impl<'a> Formattable for Node<'a> {
|
|||
fmt_spaces(buf, sp.iter(), indent);
|
||||
}
|
||||
|
||||
l.format_with_options(buf, parens, newlines, indent);
|
||||
l.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
|
||||
if !right.is_empty() {
|
||||
|
@ -956,7 +1085,7 @@ impl<'a> Formattable for Node<'a> {
|
|||
buf.push(braces.end());
|
||||
}
|
||||
Node::TypeAnnotation(type_annotation) => {
|
||||
type_annotation.format_with_options(buf, parens, newlines, indent);
|
||||
type_annotation.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1093,10 +1222,12 @@ impl<'a, V: Formattable> Formattable for NodeSpaces<'a, V> {
|
|||
buf: &mut Buf,
|
||||
parens: crate::annotation::Parens,
|
||||
newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_spaces(buf, self.before.iter(), indent);
|
||||
self.item.format_with_options(buf, parens, newlines, indent);
|
||||
self.item
|
||||
.format_with_options(buf, parens, newlines, flags, indent);
|
||||
fmt_spaces(buf, self.after.iter(), indent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ impl Braces {
|
|||
|
||||
pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable + std::fmt::Debug>(
|
||||
buf: &mut Buf<'buf>,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
braces: Braces,
|
||||
items: Collection<'a, T>,
|
||||
|
@ -109,7 +110,7 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable + std::fmt::D
|
|||
}
|
||||
|
||||
buf.indent(item_indent);
|
||||
item.item.format(buf, item_indent);
|
||||
item.item.format(buf, flags, item_indent);
|
||||
|
||||
buf.indent(item_indent);
|
||||
buf.push(',');
|
||||
|
@ -152,7 +153,7 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable + std::fmt::D
|
|||
buf.spaces(1);
|
||||
}
|
||||
|
||||
item.format(buf, indent);
|
||||
item.format(buf, flags, indent);
|
||||
if iter.peek().is_some() {
|
||||
buf.push(',');
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::annotation::{
|
||||
ann_lift_spaces, ann_lift_spaces_after, is_collection_multiline, ty_is_outdentable,
|
||||
Formattable, Newlines, Parens,
|
||||
Formattable, MigrationFlags, Newlines, Parens,
|
||||
};
|
||||
use crate::collection::{fmt_collection, Braces};
|
||||
use crate::expr::{
|
||||
|
@ -37,6 +37,7 @@ impl<'a> Formattable for Defs<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let mut prev_spaces = true;
|
||||
|
@ -58,8 +59,8 @@ impl<'a> Formattable for Defs<'a> {
|
|||
}
|
||||
|
||||
match def.item {
|
||||
Ok(type_def) => type_def.format(buf, indent),
|
||||
Err(value_def) => value_def.format(buf, indent),
|
||||
Ok(type_def) => type_def.format(buf, flags, indent),
|
||||
Err(value_def) => value_def.format(buf, flags, indent),
|
||||
}
|
||||
|
||||
fmt_spaces(buf, spaces_after.iter(), indent);
|
||||
|
@ -413,12 +414,19 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
use roc_parse::ast::TypeDef::*;
|
||||
|
||||
match self {
|
||||
Alias { header, ann } => {
|
||||
header.format(buf, indent);
|
||||
header.format(buf, flags, indent);
|
||||
|
||||
buf.indent(indent);
|
||||
buf.push_str(" :");
|
||||
|
@ -432,7 +440,7 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
indent + INDENT
|
||||
};
|
||||
fmt_comments_only(buf, ann.before.iter(), NewlineAt::Bottom, inner_indent);
|
||||
ann.item.format(buf, inner_indent);
|
||||
ann.item.format(buf, flags, inner_indent);
|
||||
fmt_spaces(buf, ann.after.iter(), indent);
|
||||
}
|
||||
Opaque {
|
||||
|
@ -453,7 +461,7 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
|
||||
let make_multiline = ann.is_multiline() || has_abilities_multiline;
|
||||
|
||||
fmt_general_def(header, buf, indent, ":=", &ann.value, newlines);
|
||||
fmt_general_def(header, buf, flags, indent, ":=", &ann.value, newlines);
|
||||
|
||||
if let Some(has_abilities) = has_abilities {
|
||||
buf.spaces(1);
|
||||
|
@ -462,6 +470,7 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::from_bool(make_multiline),
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
}
|
||||
|
@ -471,7 +480,7 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
loc_implements: _,
|
||||
members,
|
||||
} => {
|
||||
header.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
header.format_with_options(buf, Parens::NotNeeded, Newlines::No, flags, indent);
|
||||
buf.spaces(1);
|
||||
buf.push_str(roc_parse::keyword::IMPLEMENTS);
|
||||
|
||||
|
@ -482,6 +491,7 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::No,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
} else {
|
||||
|
@ -490,6 +500,7 @@ impl<'a> Formattable for TypeDef<'a> {
|
|||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
}
|
||||
|
@ -509,6 +520,7 @@ impl<'a> Formattable for TypeHeader<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.indent(indent);
|
||||
|
@ -551,7 +563,7 @@ impl<'a> Formattable for TypeHeader<'a> {
|
|||
buf.push_str("(");
|
||||
}
|
||||
|
||||
fmt_pattern(buf, &var.item, vars_indent, Parens::NotNeeded);
|
||||
fmt_pattern(buf, &var.item, flags, vars_indent, Parens::NotNeeded);
|
||||
|
||||
buf.indent(vars_indent);
|
||||
|
||||
|
@ -599,6 +611,7 @@ impl<'a> Formattable for ModuleImport<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let Self {
|
||||
|
@ -624,13 +637,20 @@ impl<'a> Formattable for ModuleImport<'a> {
|
|||
|
||||
fmt_default_spaces(buf, before_name, indent);
|
||||
|
||||
name.format(buf, indent);
|
||||
params.format(buf, indent);
|
||||
alias.format(buf, indent);
|
||||
name.format(buf, flags, indent);
|
||||
params.format(buf, flags, indent);
|
||||
alias.format(buf, flags, indent);
|
||||
|
||||
if let Some(exposed) = exposed {
|
||||
exposed.keyword.format(buf, indent);
|
||||
fmt_collection(buf, indent, Braces::Square, exposed.item, Newlines::No);
|
||||
exposed.keyword.format(buf, flags, indent);
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Square,
|
||||
exposed.item,
|
||||
Newlines::No,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -642,11 +662,18 @@ impl<'a> Formattable for ModuleImportParams<'a> {
|
|||
!before.is_empty() || is_collection_multiline(¶ms.value)
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let ModuleImportParams { before, params } = self;
|
||||
|
||||
fmt_default_spaces(buf, before, indent);
|
||||
fmt_collection(buf, indent, Braces::Curly, params.value, newlines);
|
||||
fmt_collection(buf, flags, indent, Braces::Curly, params.value, newlines);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -666,6 +693,7 @@ impl<'a> Formattable for IngestedFileImport<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let Self {
|
||||
|
@ -681,12 +709,12 @@ impl<'a> Formattable for IngestedFileImport<'a> {
|
|||
let indent = indent + INDENT;
|
||||
|
||||
fmt_default_spaces(buf, before_path, indent);
|
||||
fmt_str_literal(buf, path.value, indent);
|
||||
fmt_str_literal(buf, path.value, flags, indent);
|
||||
|
||||
name.keyword.format(buf, indent);
|
||||
name.keyword.format(buf, flags, indent);
|
||||
buf.push_str(name.item.value);
|
||||
|
||||
annotation.format(buf, indent);
|
||||
annotation.format(buf, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -701,6 +729,7 @@ impl<'a> Formattable for ImportedModuleName<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.indent(indent);
|
||||
|
@ -710,7 +739,7 @@ impl<'a> Formattable for ImportedModuleName<'a> {
|
|||
buf.push_str(".");
|
||||
}
|
||||
|
||||
self.name.format(buf, indent);
|
||||
self.name.format(buf, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,6 +754,7 @@ impl<'a> Formattable for ImportAlias<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
_flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.indent(indent);
|
||||
|
@ -742,6 +772,7 @@ impl Formattable for ImportAsKeyword {
|
|||
buf: &mut Buf<'_>,
|
||||
_parens: crate::annotation::Parens,
|
||||
_newlines: Newlines,
|
||||
_flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.indent(indent);
|
||||
|
@ -759,6 +790,7 @@ impl Formattable for ImportExposingKeyword {
|
|||
buf: &mut Buf<'_>,
|
||||
_parens: crate::annotation::Parens,
|
||||
_newlines: Newlines,
|
||||
_flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.indent(indent);
|
||||
|
@ -780,6 +812,7 @@ impl<'a> Formattable for IngestedFileAnnotation<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let Self {
|
||||
|
@ -790,7 +823,7 @@ impl<'a> Formattable for IngestedFileAnnotation<'a> {
|
|||
fmt_default_spaces(buf, before_colon, indent);
|
||||
buf.push_str(":");
|
||||
buf.spaces(1);
|
||||
annotation.format(buf, indent);
|
||||
annotation.format(buf, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,13 +846,21 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
use roc_parse::ast::ValueDef::*;
|
||||
match self {
|
||||
Annotation(loc_pattern, loc_annotation) => {
|
||||
fmt_general_def(
|
||||
loc_pattern,
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
":",
|
||||
&loc_annotation.value,
|
||||
|
@ -827,10 +868,21 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
);
|
||||
}
|
||||
Body(loc_pattern, loc_expr) => {
|
||||
fmt_body(buf, true, &loc_pattern.value, &loc_expr.value, indent);
|
||||
fmt_body(
|
||||
buf,
|
||||
true,
|
||||
&loc_pattern.value,
|
||||
&loc_expr.value,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
}
|
||||
Dbg { condition, .. } => {
|
||||
fmt_dbg_in_def(buf, condition, self.is_multiline(), flags, indent)
|
||||
}
|
||||
Expect { condition, .. } => {
|
||||
fmt_expect(buf, condition, self.is_multiline(), flags, indent)
|
||||
}
|
||||
Dbg { condition, .. } => fmt_dbg_in_def(buf, condition, self.is_multiline(), indent),
|
||||
Expect { condition, .. } => fmt_expect(buf, condition, self.is_multiline(), indent),
|
||||
AnnotatedBody {
|
||||
ann_pattern,
|
||||
ann_type,
|
||||
|
@ -838,16 +890,33 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
body_pattern,
|
||||
body_expr,
|
||||
} => {
|
||||
fmt_general_def(ann_pattern, buf, indent, ":", &ann_type.value, newlines);
|
||||
fmt_general_def(
|
||||
ann_pattern,
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
":",
|
||||
&ann_type.value,
|
||||
newlines,
|
||||
);
|
||||
|
||||
fmt_annotated_body_comment(buf, indent, lines_between);
|
||||
|
||||
buf.newline();
|
||||
fmt_body(buf, false, &body_pattern.value, &body_expr.value, indent);
|
||||
fmt_body(
|
||||
buf,
|
||||
false,
|
||||
&body_pattern.value,
|
||||
&body_expr.value,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
}
|
||||
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),
|
||||
ModuleImport(module_import) => module_import.format(buf, flags, indent),
|
||||
IngestedFileImport(ingested_file_import) => {
|
||||
ingested_file_import.format(buf, flags, indent)
|
||||
}
|
||||
Stmt(loc_expr) => loc_expr.format_with_options(buf, parens, newlines, flags, indent),
|
||||
StmtAfterExpr => internal_error!("shouldn't exist before can"),
|
||||
}
|
||||
}
|
||||
|
@ -856,12 +925,13 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
fn fmt_general_def<L: Formattable>(
|
||||
lhs: L,
|
||||
buf: &mut Buf,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
sep: &str,
|
||||
rhs: &TypeAnnotation,
|
||||
newlines: Newlines,
|
||||
) {
|
||||
lhs.format(buf, indent);
|
||||
lhs.format(buf, flags, indent);
|
||||
buf.indent(indent);
|
||||
|
||||
if rhs.is_multiline() {
|
||||
|
@ -872,9 +942,13 @@ fn fmt_general_def<L: Formattable>(
|
|||
let rhs_lifted = ann_lift_spaces(buf.text.bump(), rhs);
|
||||
|
||||
if ty_is_outdentable(&rhs_lifted.item) && rhs_lifted.before.iter().all(|s| s.is_newline()) {
|
||||
rhs_lifted
|
||||
.item
|
||||
.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
rhs_lifted.item.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::No,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
} else {
|
||||
buf.ensure_ends_with_newline();
|
||||
fmt_comments_only(
|
||||
|
@ -883,30 +957,46 @@ fn fmt_general_def<L: Formattable>(
|
|||
NewlineAt::Bottom,
|
||||
indent + INDENT,
|
||||
);
|
||||
rhs_lifted
|
||||
.item
|
||||
.format_with_options(buf, Parens::NotNeeded, newlines, indent + INDENT);
|
||||
rhs_lifted.item.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
newlines,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
}
|
||||
fmt_comments_only(buf, rhs_lifted.after.iter(), NewlineAt::Bottom, indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
buf.push_str(sep);
|
||||
buf.spaces(1);
|
||||
rhs.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
rhs.format_with_options(buf, Parens::NotNeeded, Newlines::No, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_dbg_in_def<'a>(buf: &mut Buf, condition: &'a Loc<Expr<'a>>, _: bool, indent: u16) {
|
||||
fn fmt_dbg_in_def<'a>(
|
||||
buf: &mut Buf,
|
||||
condition: &'a Loc<Expr<'a>>,
|
||||
_: bool,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.ensure_ends_with_newline();
|
||||
buf.indent(indent);
|
||||
buf.push_str("dbg");
|
||||
|
||||
buf.spaces(1);
|
||||
|
||||
condition.format(buf, indent);
|
||||
condition.format(buf, flags, indent);
|
||||
}
|
||||
|
||||
fn fmt_expect<'a>(buf: &mut Buf, condition: &'a Loc<Expr<'a>>, is_multiline: bool, indent: u16) {
|
||||
fn fmt_expect<'a>(
|
||||
buf: &mut Buf,
|
||||
condition: &'a Loc<Expr<'a>>,
|
||||
is_multiline: bool,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.ensure_ends_with_newline();
|
||||
buf.indent(indent);
|
||||
buf.push_str("expect");
|
||||
|
@ -919,19 +1009,34 @@ fn fmt_expect<'a>(buf: &mut Buf, condition: &'a Loc<Expr<'a>>, is_multiline: boo
|
|||
indent
|
||||
};
|
||||
|
||||
condition.format(buf, return_indent);
|
||||
condition.format(buf, flags, return_indent);
|
||||
}
|
||||
|
||||
pub fn fmt_value_def(buf: &mut Buf, def: &roc_parse::ast::ValueDef, indent: u16) {
|
||||
def.format(buf, indent);
|
||||
pub fn fmt_value_def(
|
||||
buf: &mut Buf,
|
||||
def: &roc_parse::ast::ValueDef,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
def.format(buf, flags, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_type_def(buf: &mut Buf, def: &roc_parse::ast::TypeDef, indent: u16) {
|
||||
def.format(buf, indent);
|
||||
pub fn fmt_type_def(
|
||||
buf: &mut Buf,
|
||||
def: &roc_parse::ast::TypeDef,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
def.format(buf, flags, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_defs(buf: &mut Buf, defs: &Defs, indent: u16) {
|
||||
defs.format(buf, indent);
|
||||
pub fn fmt_defs(
|
||||
buf: &mut Buf,
|
||||
defs: &Defs,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
defs.format(buf, flags, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_annotated_body_comment<'a>(
|
||||
|
@ -982,6 +1087,7 @@ pub fn fmt_body<'a>(
|
|||
allow_simplify_empty_record_destructure: bool,
|
||||
pattern: &'a Pattern<'a>,
|
||||
body: &'a Expr<'a>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let pattern_extracted = pattern.extract_spaces();
|
||||
|
@ -998,10 +1104,10 @@ pub fn fmt_body<'a>(
|
|||
|
||||
// Don't format the `{} =` for defs with this pattern
|
||||
if is_unit_assignment {
|
||||
return body.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
|
||||
return body.format_with_options(buf, Parens::NotNeeded, Newlines::No, flags, indent);
|
||||
}
|
||||
|
||||
pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent);
|
||||
pattern.format_with_options(buf, Parens::InApply, Newlines::No, flags, indent);
|
||||
buf.indent(indent);
|
||||
buf.push_str(" =");
|
||||
|
||||
|
@ -1020,15 +1126,28 @@ pub fn fmt_body<'a>(
|
|||
|
||||
if is_unit_assignment {
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent);
|
||||
sub_def.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
sub_def.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
} else if should_outdent {
|
||||
buf.spaces(1);
|
||||
sub_def.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
sub_def.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
} else {
|
||||
body.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
}
|
||||
|
@ -1041,7 +1160,13 @@ pub fn fmt_body<'a>(
|
|||
..,
|
||||
) => {
|
||||
buf.spaces(1);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
body.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
}
|
||||
Expr::Str(s) => {
|
||||
if is_str_multiline(&s) {
|
||||
|
@ -1049,15 +1174,33 @@ pub fn fmt_body<'a>(
|
|||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
body.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
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);
|
||||
body.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
}
|
||||
Expr::When(..) => {
|
||||
buf.ensure_ends_with_newline();
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
body.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
}
|
||||
Expr::Defs(..) | Expr::BinOps(_, _) | Expr::Backpassing(..) => {
|
||||
// Binop chains always get a newline. Otherwise you can have things like:
|
||||
|
@ -1073,7 +1216,13 @@ pub fn fmt_body<'a>(
|
|||
//
|
||||
// This makes it clear what the binop is applying to!
|
||||
buf.newline();
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
body.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
}
|
||||
Expr::ParensAround(&Expr::SpaceBefore(sub_def, _)) => {
|
||||
let needs_indent = !sub_expr_requests_parens(sub_def);
|
||||
|
@ -1083,16 +1232,16 @@ pub fn fmt_body<'a>(
|
|||
indent
|
||||
};
|
||||
buf.spaces(1);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, flags, indent);
|
||||
}
|
||||
_ => {
|
||||
buf.spaces(1);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, flags, indent);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1118,6 +1267,7 @@ impl<'a> Formattable for AbilityMember<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let Spaces { before, item, .. } = self.name.value.extract_spaces();
|
||||
|
@ -1128,6 +1278,6 @@ impl<'a> Formattable for AbilityMember<'a> {
|
|||
buf.spaces(1);
|
||||
buf.push(':');
|
||||
buf.spaces(1);
|
||||
self.typ.value.format(buf, indent + INDENT);
|
||||
self.typ.value.format(buf, flags, indent + INDENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::annotation::{except_last, is_collection_multiline, Formattable, Newlines, Parens};
|
||||
use crate::annotation::{
|
||||
except_last, is_collection_multiline, Formattable, MigrationFlags, Newlines, Parens,
|
||||
};
|
||||
use crate::collection::{fmt_collection, Braces};
|
||||
use crate::def::{fmt_defs, valdef_lift_spaces_before};
|
||||
use crate::pattern::{fmt_pattern, pattern_lift_spaces, starts_with_inline_comment};
|
||||
|
@ -28,7 +30,14 @@ impl<'a> Formattable for Expr<'a> {
|
|||
expr_is_multiline(self, false)
|
||||
}
|
||||
|
||||
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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
use self::Expr::*;
|
||||
|
||||
let me = expr_lift_spaces(parens, buf.text.bump(), self);
|
||||
|
@ -41,13 +50,13 @@ impl<'a> Formattable for Expr<'a> {
|
|||
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);
|
||||
sub_expr.format_with_options(buf, Parens::NotNeeded, newlines, flags, indent);
|
||||
} else {
|
||||
fmt_parens(sub_expr, buf, indent);
|
||||
fmt_parens(sub_expr, buf, flags, indent);
|
||||
}
|
||||
}
|
||||
Str(literal) => {
|
||||
fmt_str_literal(buf, *literal, indent);
|
||||
fmt_str_literal(buf, *literal, flags, indent);
|
||||
}
|
||||
Var { module_name, ident } => {
|
||||
buf.indent(indent);
|
||||
|
@ -75,9 +84,9 @@ impl<'a> Formattable for Expr<'a> {
|
|||
let apply_needs_parens = parens == Parens::InApply;
|
||||
|
||||
if apply_needs_parens && !loc_args.is_empty() {
|
||||
fmt_parens(self, buf, indent);
|
||||
fmt_parens(self, buf, flags, indent);
|
||||
} else {
|
||||
fmt_apply(loc_expr, loc_args, indent, buf);
|
||||
fmt_apply(loc_expr, loc_args, flags, indent, buf);
|
||||
}
|
||||
}
|
||||
&Num(string) => {
|
||||
|
@ -120,6 +129,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
buf,
|
||||
None,
|
||||
*fields,
|
||||
flags,
|
||||
indent,
|
||||
format_assigned_field_multiline,
|
||||
assigned_field_to_space_before,
|
||||
|
@ -130,6 +140,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
buf,
|
||||
Some(RecordPrefix::Update(update)),
|
||||
*fields,
|
||||
flags,
|
||||
indent,
|
||||
format_assigned_field_multiline,
|
||||
assigned_field_to_space_before,
|
||||
|
@ -140,28 +151,29 @@ impl<'a> Formattable for Expr<'a> {
|
|||
buf,
|
||||
Some(RecordPrefix::Mapper(mapper)),
|
||||
*fields,
|
||||
flags,
|
||||
indent,
|
||||
format_assigned_field_multiline,
|
||||
assigned_field_to_space_before,
|
||||
);
|
||||
}
|
||||
Closure(loc_patterns, loc_ret) => {
|
||||
fmt_closure(buf, loc_patterns, loc_ret, indent);
|
||||
fmt_closure(buf, loc_patterns, loc_ret, flags, indent);
|
||||
}
|
||||
Backpassing(loc_patterns, loc_body, loc_ret) => {
|
||||
fmt_backpassing(buf, loc_patterns, loc_body, loc_ret, indent);
|
||||
fmt_backpassing(buf, loc_patterns, loc_body, loc_ret, flags, indent);
|
||||
}
|
||||
Defs(defs, ret) => {
|
||||
let defs_needs_parens = parens == Parens::InOperator || parens == Parens::InApply;
|
||||
|
||||
if defs_needs_parens {
|
||||
fmt_parens(self, buf, indent)
|
||||
fmt_parens(self, buf, flags, 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());
|
||||
|
||||
fmt_defs(buf, defs, indent);
|
||||
fmt_defs(buf, defs, flags, indent);
|
||||
|
||||
match &ret.value {
|
||||
SpaceBefore(sub_expr, spaces) => {
|
||||
|
@ -174,6 +186,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
}
|
||||
|
@ -182,7 +195,13 @@ impl<'a> Formattable for Expr<'a> {
|
|||
buf.indent(indent);
|
||||
// Even if there were no defs, which theoretically should never happen,
|
||||
// still print the return value.
|
||||
ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
ret.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,13 +215,21 @@ impl<'a> Formattable for Expr<'a> {
|
|||
extra_args,
|
||||
continuation,
|
||||
} => {
|
||||
fmt_dbg_stmt(buf, first, extra_args, continuation, parens, indent);
|
||||
fmt_dbg_stmt(buf, first, extra_args, continuation, parens, flags, indent);
|
||||
}
|
||||
LowLevelDbg(_, _, _) => unreachable!(
|
||||
"LowLevelDbg should only exist after desugaring, not during formatting"
|
||||
),
|
||||
Return(return_value, after_return) => {
|
||||
fmt_return(buf, return_value, after_return, parens, newlines, indent);
|
||||
fmt_return(
|
||||
buf,
|
||||
return_value,
|
||||
after_return,
|
||||
parens,
|
||||
newlines,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
}
|
||||
If {
|
||||
if_thens: branches,
|
||||
|
@ -215,13 +242,18 @@ impl<'a> Formattable for Expr<'a> {
|
|||
final_else,
|
||||
self.is_multiline(),
|
||||
*indented_else,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
}
|
||||
When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, 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),
|
||||
When(loc_condition, branches) => fmt_when(buf, loc_condition, branches, flags, indent),
|
||||
Tuple(items) => {
|
||||
fmt_expr_collection(buf, flags, indent, Braces::Round, *items, Newlines::No)
|
||||
}
|
||||
List(items) => {
|
||||
fmt_expr_collection(buf, flags, indent, Braces::Square, *items, Newlines::No)
|
||||
}
|
||||
BinOps(lefts, right) => fmt_binops(buf, lefts, right, flags, indent),
|
||||
UnaryOp(sub_expr, unary_op) => {
|
||||
buf.indent(indent);
|
||||
match &unary_op.value {
|
||||
|
@ -255,7 +287,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
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.
|
||||
fmt_parens(&sub_expr.value, buf, indent);
|
||||
fmt_parens(&sub_expr.value, buf, flags, indent);
|
||||
} else {
|
||||
if matches!(unary_op.value, called_via::UnaryOp::Not)
|
||||
&& requires_space_after_unary(&lifted.item)
|
||||
|
@ -281,9 +313,13 @@ impl<'a> Formattable for Expr<'a> {
|
|||
if !before_all_newlines {
|
||||
format_spaces(buf, lifted.before, newlines, inner_indent);
|
||||
}
|
||||
lifted
|
||||
.item
|
||||
.format_with_options(buf, inner_parens, newlines, inner_indent);
|
||||
lifted.item.format_with_options(
|
||||
buf,
|
||||
inner_parens,
|
||||
newlines,
|
||||
flags,
|
||||
inner_indent,
|
||||
);
|
||||
format_spaces(buf, lifted.after, newlines, inner_indent);
|
||||
}
|
||||
}
|
||||
|
@ -301,17 +337,17 @@ impl<'a> Formattable for Expr<'a> {
|
|||
buf.push_str(key);
|
||||
}
|
||||
RecordAccess(expr, key) => {
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, flags, indent);
|
||||
buf.push('.');
|
||||
buf.push_str(key);
|
||||
}
|
||||
TupleAccess(expr, key) => {
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, flags, indent);
|
||||
buf.push('.');
|
||||
buf.push_str(key);
|
||||
}
|
||||
TrySuffix { expr, target } => {
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
expr.format_with_options(buf, Parens::InApply, Newlines::Yes, flags, indent);
|
||||
match target {
|
||||
TryTarget::Task => buf.push('!'),
|
||||
TryTarget::Result => buf.push('?'),
|
||||
|
@ -323,7 +359,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
}
|
||||
MalformedSuffixed(loc_expr) => {
|
||||
buf.indent(indent);
|
||||
loc_expr.format_with_options(buf, parens, newlines, indent);
|
||||
loc_expr.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
PrecedenceConflict { .. } => {}
|
||||
EmptyRecordBuilder { .. } => {}
|
||||
|
@ -465,6 +501,7 @@ fn lower<'a, 'b: 'a>(arena: &'b Bump, lifted: Spaces<'b, Expr<'b>>) -> Expr<'b>
|
|||
|
||||
fn fmt_expr_collection(
|
||||
buf: &mut Buf<'_>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
braces: Braces,
|
||||
items: Collection<'_, &Loc<Expr<'_>>>,
|
||||
|
@ -488,7 +525,7 @@ fn fmt_expr_collection(
|
|||
let new_items =
|
||||
Collection::with_items_and_comments(arena, new_items.into_bump_slice(), final_comments);
|
||||
|
||||
fmt_collection(buf, indent, braces, new_items, newlines)
|
||||
fmt_collection(buf, flags, indent, braces, new_items, newlines)
|
||||
}
|
||||
|
||||
fn requires_space_after_unary(item: &Expr<'_>) -> bool {
|
||||
|
@ -513,6 +550,7 @@ fn requires_space_after_unary(item: &Expr<'_>) -> bool {
|
|||
fn fmt_apply(
|
||||
loc_expr: &Loc<Expr<'_>>,
|
||||
loc_args: &[&Loc<Expr<'_>>],
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
buf: &mut Buf<'_>,
|
||||
) {
|
||||
|
@ -568,9 +606,9 @@ fn fmt_apply(
|
|||
|| expr_needs_parens_in_apply(&loc_expr.value);
|
||||
|
||||
if expr_needs_parens {
|
||||
fmt_parens(&loc_expr.value, buf, indent);
|
||||
fmt_parens(&loc_expr.value, buf, flags, indent);
|
||||
} else {
|
||||
loc_expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
|
||||
loc_expr.format_with_options(buf, Parens::InApply, Newlines::Yes, flags, indent);
|
||||
}
|
||||
|
||||
for loc_arg in loc_args.iter() {
|
||||
|
@ -583,17 +621,17 @@ fn fmt_apply(
|
|||
|
||||
let arg = loc_arg.extract_spaces();
|
||||
arg.item
|
||||
.format_with_options(buf, Parens::InApply, Newlines::Yes, arg_indent);
|
||||
.format_with_options(buf, Parens::InApply, Newlines::Yes, flags, 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);
|
||||
.format_with_options(buf, Parens::InApply, Newlines::Yes, flags, 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);
|
||||
loc_arg.format_with_options(buf, Parens::InApply, Newlines::Yes, flags, arg_indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -625,7 +663,7 @@ fn expr_ends_in_closure(expr: &Expr<'_>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn fmt_parens(sub_expr: &Expr<'_>, buf: &mut Buf<'_>, indent: u16) {
|
||||
fn fmt_parens(sub_expr: &Expr<'_>, buf: &mut Buf<'_>, flags: &MigrationFlags, indent: u16) {
|
||||
let should_add_newlines = match sub_expr {
|
||||
Expr::Closure(..) | Expr::SpaceBefore(..) | Expr::SpaceAfter(Expr::Closure(..), ..) => {
|
||||
false
|
||||
|
@ -648,7 +686,7 @@ fn fmt_parens(sub_expr: &Expr<'_>, buf: &mut Buf<'_>, indent: u16) {
|
|||
indent
|
||||
};
|
||||
|
||||
sub_expr.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, next_indent);
|
||||
sub_expr.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, flags, next_indent);
|
||||
|
||||
if !matches!(sub_expr, Expr::SpaceAfter(..)) && should_add_newlines {
|
||||
buf.newline();
|
||||
|
@ -741,7 +779,7 @@ fn fmt_str_body(body: &str, buf: &mut Buf) {
|
|||
}
|
||||
}
|
||||
|
||||
fn format_str_segment(seg: &StrSegment, buf: &mut Buf, indent: u16) {
|
||||
fn format_str_segment(seg: &StrSegment, buf: &mut Buf, flags: &MigrationFlags, indent: u16) {
|
||||
use StrSegment::*;
|
||||
|
||||
match seg {
|
||||
|
@ -772,6 +810,7 @@ fn format_str_segment(seg: &StrSegment, buf: &mut Buf, indent: u16) {
|
|||
buf,
|
||||
Parens::NotNeeded, // We already printed parens!
|
||||
Newlines::No, // Interpolations can never have newlines
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
buf.push(')');
|
||||
|
@ -800,7 +839,7 @@ fn push_op(buf: &mut Buf, op: BinOp) {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fmt_str_literal(buf: &mut Buf, literal: StrLiteral, indent: u16) {
|
||||
pub fn fmt_str_literal(buf: &mut Buf, literal: StrLiteral, flags: &MigrationFlags, indent: u16) {
|
||||
use roc_parse::ast::StrLiteral::*;
|
||||
|
||||
match literal {
|
||||
|
@ -829,7 +868,7 @@ pub fn fmt_str_literal(buf: &mut Buf, literal: StrLiteral, indent: u16) {
|
|||
buf.indent(indent);
|
||||
buf.push('"');
|
||||
for seg in segments.iter() {
|
||||
format_str_segment(seg, buf, 0)
|
||||
format_str_segment(seg, buf, flags, 0)
|
||||
}
|
||||
buf.push('"');
|
||||
}
|
||||
|
@ -845,7 +884,7 @@ pub fn fmt_str_literal(buf: &mut Buf, literal: StrLiteral, indent: u16) {
|
|||
// only add indent if the line isn't empty
|
||||
if *seg != StrSegment::Plaintext("\n") {
|
||||
buf.indent(indent);
|
||||
format_str_segment(seg, buf, indent);
|
||||
format_str_segment(seg, buf, flags, indent);
|
||||
} else {
|
||||
buf.push_newline_literal();
|
||||
}
|
||||
|
@ -1044,6 +1083,7 @@ fn fmt_binops<'a>(
|
|||
buf: &mut Buf,
|
||||
lefts: &'a [(Loc<Expr<'a>>, Loc<BinOp>)],
|
||||
loc_right_side: &'a Loc<Expr<'a>>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let is_multiline = loc_right_side.value.is_multiline()
|
||||
|
@ -1060,12 +1100,13 @@ fn fmt_binops<'a>(
|
|||
|| starts_with_unary_minus(lifted_left_side.item);
|
||||
|
||||
if need_parens {
|
||||
fmt_parens(&lifted_left_side.item, buf, indent);
|
||||
fmt_parens(&lifted_left_side.item, buf, flags, indent);
|
||||
} else {
|
||||
lifted_left_side.item.format_with_options(
|
||||
buf,
|
||||
Parens::InOperator,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
}
|
||||
|
@ -1092,11 +1133,15 @@ fn fmt_binops<'a>(
|
|||
|| starts_with_unary_minus(lifted_right_side.item);
|
||||
|
||||
if need_parens {
|
||||
fmt_parens(&lifted_right_side.item, buf, indent);
|
||||
fmt_parens(&lifted_right_side.item, buf, flags, indent);
|
||||
} else {
|
||||
lifted_right_side
|
||||
.item
|
||||
.format_with_options(buf, Parens::InOperator, Newlines::Yes, indent);
|
||||
lifted_right_side.item.format_with_options(
|
||||
buf,
|
||||
Parens::InOperator,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
}
|
||||
|
||||
format_spaces(buf, lifted_right_side.after, Newlines::Yes, indent);
|
||||
|
@ -1153,6 +1198,7 @@ fn fmt_when<'a>(
|
|||
buf: &mut Buf,
|
||||
loc_condition: &'a Loc<Expr<'a>>,
|
||||
branches: &[&'a WhenBranch<'a>],
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let is_multiline_condition = loc_condition.is_multiline();
|
||||
|
@ -1184,7 +1230,7 @@ fn fmt_when<'a>(
|
|||
NewlineAt::None
|
||||
};
|
||||
|
||||
expr_above.format(buf, condition_indent);
|
||||
expr_above.format(buf, flags, condition_indent);
|
||||
fmt_comments_only(
|
||||
buf,
|
||||
spaces_below_expr.iter(),
|
||||
|
@ -1194,20 +1240,20 @@ fn fmt_when<'a>(
|
|||
buf.newline();
|
||||
}
|
||||
_ => {
|
||||
expr_below.format(buf, condition_indent);
|
||||
expr_below.format(buf, flags, condition_indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
buf.newline();
|
||||
loc_condition.format(buf, condition_indent);
|
||||
loc_condition.format(buf, flags, condition_indent);
|
||||
buf.newline();
|
||||
}
|
||||
}
|
||||
buf.indent(indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
loc_condition.format(buf, indent);
|
||||
loc_condition.format(buf, flags, indent);
|
||||
buf.spaces(1);
|
||||
}
|
||||
buf.push_str("is");
|
||||
|
@ -1256,7 +1302,7 @@ fn fmt_when<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fmt_pattern(buf, sub_pattern, indent + INDENT, Parens::NotNeeded);
|
||||
fmt_pattern(buf, sub_pattern, flags, indent + INDENT, Parens::NotNeeded);
|
||||
}
|
||||
other => {
|
||||
if branch_index > 0 {
|
||||
|
@ -1268,7 +1314,7 @@ fn fmt_when<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fmt_pattern(buf, other, indent + INDENT, Parens::NotNeeded);
|
||||
fmt_pattern(buf, other, flags, indent + INDENT, Parens::NotNeeded);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1282,14 +1328,26 @@ fn fmt_when<'a>(
|
|||
|
||||
buf.spaces(1);
|
||||
|
||||
fmt_pattern(buf, &pattern.value, indent + INDENT, Parens::NotNeeded);
|
||||
fmt_pattern(
|
||||
buf,
|
||||
&pattern.value,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
Parens::NotNeeded,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(guard_expr) = &branch.guard {
|
||||
buf.push_str(" if");
|
||||
buf.spaces(1);
|
||||
guard_expr.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
|
||||
guard_expr.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent + INDENT,
|
||||
);
|
||||
}
|
||||
|
||||
buf.push_str(" ->");
|
||||
|
@ -1308,6 +1366,7 @@ fn fmt_when<'a>(
|
|||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent + 2 * INDENT,
|
||||
);
|
||||
}
|
||||
|
@ -1322,6 +1381,7 @@ fn fmt_when<'a>(
|
|||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent + 2 * INDENT,
|
||||
);
|
||||
}
|
||||
|
@ -1337,6 +1397,7 @@ fn fmt_dbg_stmt<'a>(
|
|||
extra_args: &'a [&'a Loc<Expr<'a>>],
|
||||
continuation: &'a Loc<Expr<'a>>,
|
||||
parens: Parens,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
let mut args = Vec::with_capacity_in(extra_args.len() + 1, buf.text.bump());
|
||||
|
@ -1348,12 +1409,12 @@ fn fmt_dbg_stmt<'a>(
|
|||
args.into_bump_slice(),
|
||||
called_via::CalledVia::Space,
|
||||
)
|
||||
.format_with_options(buf, parens, Newlines::Yes, indent);
|
||||
.format_with_options(buf, parens, Newlines::Yes, flags, indent);
|
||||
|
||||
// Always put a newline after the `dbg` line(s)
|
||||
buf.ensure_ends_with_newline();
|
||||
|
||||
continuation.format(buf, indent);
|
||||
continuation.format(buf, flags, indent);
|
||||
}
|
||||
|
||||
fn fmt_return<'a>(
|
||||
|
@ -1362,6 +1423,7 @@ fn fmt_return<'a>(
|
|||
after_return: &Option<&'a Loc<Expr<'a>>>,
|
||||
parens: Parens,
|
||||
newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.ensure_ends_with_newline();
|
||||
|
@ -1380,7 +1442,7 @@ fn fmt_return<'a>(
|
|||
indent
|
||||
};
|
||||
|
||||
return_value.format_with_options(buf, parens, Newlines::No, return_indent);
|
||||
return_value.format_with_options(buf, parens, Newlines::No, flags, return_indent);
|
||||
|
||||
if let Some(after_return) = after_return {
|
||||
let lifted = expr_lift_spaces(Parens::NotNeeded, buf.text.bump(), &after_return.value);
|
||||
|
@ -1391,7 +1453,7 @@ fn fmt_return<'a>(
|
|||
}
|
||||
lifted
|
||||
.item
|
||||
.format_with_options(buf, parens, newlines, indent);
|
||||
.format_with_options(buf, parens, newlines, flags, indent);
|
||||
fmt_spaces(buf, lifted.after.iter(), indent);
|
||||
} else if parens != Parens::NotNeeded {
|
||||
buf.ensure_ends_with_newline();
|
||||
|
@ -1404,6 +1466,7 @@ fn fmt_if<'a>(
|
|||
final_else: &'a Loc<Expr<'a>>,
|
||||
is_multiline: bool,
|
||||
indented_else: bool,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
// let is_multiline_then = loc_then.is_multiline();
|
||||
|
@ -1442,7 +1505,7 @@ fn fmt_if<'a>(
|
|||
|
||||
match &expr_below {
|
||||
Expr::SpaceAfter(expr_above, spaces_after_expr) => {
|
||||
expr_above.format(buf, return_indent);
|
||||
expr_above.format(buf, flags, return_indent);
|
||||
|
||||
// If any of the spaces is a newline, add a newline at the top.
|
||||
// Otherwise leave it as just a comment.
|
||||
|
@ -1465,28 +1528,28 @@ fn fmt_if<'a>(
|
|||
}
|
||||
|
||||
_ => {
|
||||
expr_below.format(buf, return_indent);
|
||||
expr_below.format(buf, flags, return_indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Expr::SpaceAfter(expr_above, spaces_below_expr) => {
|
||||
buf.newline();
|
||||
expr_above.format(buf, return_indent);
|
||||
expr_above.format(buf, flags, return_indent);
|
||||
fmt_comments_only(buf, spaces_below_expr.iter(), NewlineAt::Top, return_indent);
|
||||
buf.newline();
|
||||
}
|
||||
|
||||
_ => {
|
||||
buf.newline();
|
||||
loc_condition.format(buf, return_indent);
|
||||
loc_condition.format(buf, flags, return_indent);
|
||||
buf.newline();
|
||||
}
|
||||
}
|
||||
buf.indent(indent);
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
loc_condition.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
loc_condition.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, flags, indent);
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
||||
|
@ -1501,7 +1564,7 @@ fn fmt_if<'a>(
|
|||
|
||||
match &expr_below {
|
||||
Expr::SpaceAfter(expr_above, spaces_above) => {
|
||||
expr_above.format(buf, return_indent);
|
||||
expr_above.format(buf, flags, return_indent);
|
||||
|
||||
// If any of the spaces is a newline, add a newline at the top.
|
||||
// Otherwise leave it as just a comment.
|
||||
|
@ -1519,20 +1582,20 @@ fn fmt_if<'a>(
|
|||
}
|
||||
|
||||
_ => {
|
||||
expr_below.format(buf, return_indent);
|
||||
expr_below.format(buf, flags, return_indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
buf.newline();
|
||||
loc_then.format(buf, return_indent);
|
||||
loc_then.format(buf, flags, return_indent);
|
||||
buf.newline();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buf.push_str("");
|
||||
buf.spaces(1);
|
||||
loc_then.format(buf, return_indent);
|
||||
loc_then.format(buf, flags, return_indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1551,13 +1614,14 @@ fn fmt_if<'a>(
|
|||
buf.spaces(1);
|
||||
}
|
||||
let indent = if indented_else { indent } else { return_indent };
|
||||
final_else.format(buf, indent);
|
||||
final_else.format(buf, flags, indent);
|
||||
}
|
||||
|
||||
fn fmt_closure<'a>(
|
||||
buf: &mut Buf,
|
||||
loc_patterns: &'a [Loc<Pattern<'a>>],
|
||||
loc_ret: &'a Loc<Expr<'a>>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
use self::Expr::*;
|
||||
|
@ -1598,7 +1662,7 @@ fn fmt_closure<'a>(
|
|||
}
|
||||
|
||||
arg.item
|
||||
.format_with_options(buf, Parens::InAsPattern, Newlines::No, indent);
|
||||
.format_with_options(buf, Parens::InAsPattern, Newlines::No, flags, indent);
|
||||
|
||||
if !arg.after.is_empty() {
|
||||
if starts_with_inline_comment(arg.after.iter()) {
|
||||
|
@ -1653,20 +1717,38 @@ fn fmt_closure<'a>(
|
|||
|
||||
if should_outdent {
|
||||
buf.spaces(1);
|
||||
sub_expr.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
sub_expr.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
indent,
|
||||
);
|
||||
} else {
|
||||
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, body_indent);
|
||||
loc_ret.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
body_indent,
|
||||
);
|
||||
}
|
||||
}
|
||||
Record { .. } | List { .. } => {
|
||||
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
|
||||
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, flags, indent);
|
||||
}
|
||||
_ => {
|
||||
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, body_indent);
|
||||
loc_ret.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::Yes,
|
||||
flags,
|
||||
body_indent,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, body_indent);
|
||||
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, flags, body_indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1675,6 +1757,7 @@ fn fmt_backpassing<'a>(
|
|||
loc_patterns: &'a [Loc<Pattern<'a>>],
|
||||
loc_body: &'a Loc<Expr<'a>>,
|
||||
loc_ret: &'a Loc<Expr<'a>>,
|
||||
flags: &MigrationFlags,
|
||||
outer_indent: u16,
|
||||
) {
|
||||
use self::Expr::*;
|
||||
|
@ -1720,6 +1803,7 @@ fn fmt_backpassing<'a>(
|
|||
buf,
|
||||
needs_parens,
|
||||
Newlines::No,
|
||||
flags,
|
||||
if first { outer_indent } else { arg_indent },
|
||||
);
|
||||
fmt_comments_only(buf, pat.after.iter(), NewlineAt::Bottom, arg_indent);
|
||||
|
@ -1759,8 +1843,8 @@ 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, outer_indent);
|
||||
loc_body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, flags, body_indent);
|
||||
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, flags, outer_indent);
|
||||
}
|
||||
|
||||
fn pattern_needs_parens_when_backpassing(pat: &Pattern) -> bool {
|
||||
|
@ -1782,12 +1866,13 @@ fn fmt_record_like<'a, Field, Format, ToSpaceBefore>(
|
|||
buf: &mut Buf,
|
||||
prefix: Option<RecordPrefix<'a>>,
|
||||
fields: Collection<'a, Loc<Field>>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
format_field_multiline: Format,
|
||||
to_space_before: ToSpaceBefore,
|
||||
) where
|
||||
Field: Formattable,
|
||||
Format: Fn(&mut Buf, &Field, u16, &str),
|
||||
Format: Fn(&mut Buf, &Field, &MigrationFlags, u16, &str),
|
||||
ToSpaceBefore: Fn(&'a Field) -> Option<(&'a Field, &'a [CommentOrNewline<'a>])>,
|
||||
{
|
||||
let loc_fields = fields.items;
|
||||
|
@ -1806,13 +1891,13 @@ fn fmt_record_like<'a, Field, Format, ToSpaceBefore>(
|
|||
// doesnt make sense.
|
||||
Some(RecordPrefix::Update(record_var)) => {
|
||||
buf.spaces(1);
|
||||
record_var.format(buf, indent);
|
||||
record_var.format(buf, flags, indent);
|
||||
buf.indent(indent);
|
||||
buf.push_str(" &");
|
||||
}
|
||||
Some(RecordPrefix::Mapper(mapper_var)) => {
|
||||
buf.spaces(1);
|
||||
mapper_var.format(buf, indent);
|
||||
mapper_var.format(buf, flags, indent);
|
||||
buf.indent(indent);
|
||||
buf.push_str(" <-");
|
||||
}
|
||||
|
@ -1848,7 +1933,7 @@ fn fmt_record_like<'a, Field, Format, ToSpaceBefore>(
|
|||
}
|
||||
}
|
||||
|
||||
format_field_multiline(buf, &field.value, field_indent, "");
|
||||
format_field_multiline(buf, &field.value, flags, field_indent, "");
|
||||
}
|
||||
|
||||
if count_leading_newlines(final_comments.iter()) > 1 {
|
||||
|
@ -1864,7 +1949,13 @@ fn fmt_record_like<'a, Field, Format, ToSpaceBefore>(
|
|||
let field_indent = indent;
|
||||
let mut iter = loc_fields.iter().peekable();
|
||||
while let Some(field) = iter.next() {
|
||||
field.format_with_options(buf, Parens::NotNeeded, Newlines::No, field_indent);
|
||||
field.format_with_options(
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
Newlines::No,
|
||||
flags,
|
||||
field_indent,
|
||||
);
|
||||
|
||||
if iter.peek().is_some() {
|
||||
buf.push_str(",");
|
||||
|
@ -1886,6 +1977,7 @@ fn fmt_record_like<'a, Field, Format, ToSpaceBefore>(
|
|||
fn format_assigned_field_multiline<T>(
|
||||
buf: &mut Buf,
|
||||
field: &AssignedField<T>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
separator_prefix: &str,
|
||||
) where
|
||||
|
@ -1906,7 +1998,7 @@ fn format_assigned_field_multiline<T>(
|
|||
buf.push_str(separator_prefix);
|
||||
buf.push_str(":");
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
ann.value.format(buf, flags, indent);
|
||||
buf.push(',');
|
||||
}
|
||||
OptionalValue(name, spaces, ann) => {
|
||||
|
@ -1922,7 +2014,7 @@ fn format_assigned_field_multiline<T>(
|
|||
buf.push_str(separator_prefix);
|
||||
buf.push_str("?");
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
ann.value.format(buf, flags, indent);
|
||||
buf.push(',');
|
||||
}
|
||||
IgnoredValue(name, spaces, ann) => {
|
||||
|
@ -1939,7 +2031,7 @@ fn format_assigned_field_multiline<T>(
|
|||
buf.push_str(separator_prefix);
|
||||
buf.push_str(":");
|
||||
buf.spaces(1);
|
||||
ann.value.format(buf, indent);
|
||||
ann.value.format(buf, flags, indent);
|
||||
buf.push(',');
|
||||
}
|
||||
LabelOnly(name) => {
|
||||
|
@ -1956,7 +2048,7 @@ fn format_assigned_field_multiline<T>(
|
|||
// ```
|
||||
// we'd like to preserve this
|
||||
|
||||
format_assigned_field_multiline(buf, sub_field, indent, separator_prefix);
|
||||
format_assigned_field_multiline(buf, sub_field, flags, indent, separator_prefix);
|
||||
}
|
||||
AssignedField::SpaceAfter(sub_field, spaces) => {
|
||||
// We have something like that:
|
||||
|
@ -1970,7 +2062,7 @@ fn format_assigned_field_multiline<T>(
|
|||
// # comment
|
||||
// otherfield
|
||||
// ```
|
||||
format_assigned_field_multiline(buf, sub_field, indent, separator_prefix);
|
||||
format_assigned_field_multiline(buf, sub_field, flags, indent, separator_prefix);
|
||||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Top, indent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::cmp::max;
|
||||
|
||||
use crate::annotation::{is_collection_multiline, Formattable, Newlines, Parens};
|
||||
use crate::annotation::{is_collection_multiline, Formattable, MigrationFlags, Newlines, Parens};
|
||||
use crate::collection::{fmt_collection, Braces};
|
||||
use crate::expr::fmt_str_literal;
|
||||
use crate::spaces::{fmt_comments_only, fmt_default_spaces, fmt_spaces, NewlineAt, INDENT};
|
||||
|
@ -15,23 +15,27 @@ use roc_parse::header::{
|
|||
use roc_parse::ident::UppercaseIdent;
|
||||
use roc_region::all::Loc;
|
||||
|
||||
pub fn fmt_header<'a>(buf: &mut Buf<'_>, header: &'a SpacesBefore<'a, Header<'a>>) {
|
||||
pub fn fmt_header<'a>(
|
||||
buf: &mut Buf<'_>,
|
||||
header: &'a SpacesBefore<'a, Header<'a>>,
|
||||
flags: &MigrationFlags,
|
||||
) {
|
||||
fmt_comments_only(buf, header.before.iter(), NewlineAt::Bottom, 0);
|
||||
match &header.item {
|
||||
Header::Module(header) => {
|
||||
fmt_module_header(buf, header);
|
||||
fmt_module_header(buf, header, flags);
|
||||
}
|
||||
Header::App(header) => {
|
||||
fmt_app_header(buf, header);
|
||||
fmt_app_header(buf, header, flags);
|
||||
}
|
||||
Header::Package(header) => {
|
||||
fmt_package_header(buf, header);
|
||||
fmt_package_header(buf, header, flags);
|
||||
}
|
||||
Header::Platform(header) => {
|
||||
fmt_platform_header(buf, header);
|
||||
fmt_platform_header(buf, header, flags);
|
||||
}
|
||||
Header::Hosted(header) => {
|
||||
fmt_hosted_header(buf, header);
|
||||
fmt_hosted_header(buf, header, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +53,7 @@ macro_rules! keywords {
|
|||
buf: &mut Buf<'_>,
|
||||
_parens: crate::annotation::Parens,
|
||||
_newlines: Newlines,
|
||||
_flags: &crate::annotation::MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.indent(indent);
|
||||
|
@ -84,10 +89,11 @@ impl<V: Formattable> Formattable for Option<V> {
|
|||
buf: &mut Buf,
|
||||
parens: crate::annotation::Parens,
|
||||
newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
if let Some(v) = self {
|
||||
v.format_with_options(buf, parens, newlines, indent);
|
||||
v.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,12 +115,13 @@ impl<'a> Formattable for ProvidesTo<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: crate::annotation::Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
self.provides_keyword.format(buf, indent);
|
||||
fmt_provides(buf, self.entries, self.types, indent);
|
||||
self.to_keyword.format(buf, indent);
|
||||
fmt_to(buf, self.to.value, indent);
|
||||
self.provides_keyword.format(buf, flags, indent);
|
||||
fmt_provides(buf, self.entries, self.types, flags, indent);
|
||||
self.to_keyword.format(buf, flags, indent);
|
||||
fmt_to(buf, self.to.value, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,9 +135,10 @@ impl<'a> Formattable for PlatformRequires<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: crate::annotation::Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_requires(buf, self, indent);
|
||||
fmt_requires(buf, self, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,10 +152,12 @@ impl<'a, V: Formattable> Formattable for Spaces<'a, V> {
|
|||
buf: &mut Buf,
|
||||
parens: crate::annotation::Parens,
|
||||
newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_default_spaces(buf, self.before, indent);
|
||||
self.item.format_with_options(buf, parens, newlines, indent);
|
||||
self.item
|
||||
.format_with_options(buf, parens, newlines, flags, indent);
|
||||
fmt_default_spaces(buf, self.after, indent);
|
||||
}
|
||||
}
|
||||
|
@ -157,14 +167,22 @@ impl<'a, K: Formattable, V: Formattable> Formattable for KeywordItem<'a, K, V> {
|
|||
self.keyword.is_multiline() || self.item.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,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
self.keyword
|
||||
.format_with_options(buf, parens, newlines, indent);
|
||||
self.item.format_with_options(buf, parens, newlines, indent);
|
||||
.format_with_options(buf, parens, newlines, flags, indent);
|
||||
self.item
|
||||
.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmt_module_header<'a>(buf: &mut Buf, header: &'a ModuleHeader<'a>) {
|
||||
pub fn fmt_module_header<'a>(buf: &mut Buf, header: &'a ModuleHeader<'a>, flags: &MigrationFlags) {
|
||||
buf.indent(0);
|
||||
buf.push_str("module");
|
||||
|
||||
|
@ -177,6 +195,7 @@ pub fn fmt_module_header<'a>(buf: &mut Buf, header: &'a ModuleHeader<'a>) {
|
|||
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Curly,
|
||||
params.pattern.value,
|
||||
|
@ -188,10 +207,10 @@ pub fn fmt_module_header<'a>(buf: &mut Buf, header: &'a ModuleHeader<'a>) {
|
|||
indent = fmt_spaces_with_outdent(buf, params.after_arrow, indent);
|
||||
}
|
||||
|
||||
fmt_exposes(buf, header.exposes, indent);
|
||||
fmt_exposes(buf, header.exposes, flags, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_hosted_header<'a>(buf: &mut Buf, header: &'a HostedHeader<'a>) {
|
||||
pub fn fmt_hosted_header<'a>(buf: &mut Buf, header: &'a HostedHeader<'a>, flags: &MigrationFlags) {
|
||||
buf.indent(0);
|
||||
buf.push_str("hosted");
|
||||
let indent = INDENT;
|
||||
|
@ -199,21 +218,21 @@ pub fn fmt_hosted_header<'a>(buf: &mut Buf, header: &'a HostedHeader<'a>) {
|
|||
|
||||
buf.push_str(header.name.value.as_str());
|
||||
|
||||
header.exposes.keyword.format(buf, indent);
|
||||
fmt_exposes(buf, header.exposes.item, indent);
|
||||
header.imports.keyword.format(buf, indent);
|
||||
fmt_imports(buf, header.imports.item, indent);
|
||||
header.exposes.keyword.format(buf, flags, indent);
|
||||
fmt_exposes(buf, header.exposes.item, flags, indent);
|
||||
header.imports.keyword.format(buf, flags, indent);
|
||||
fmt_imports(buf, header.imports.item, flags, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_app_header<'a>(buf: &mut Buf, header: &'a AppHeader<'a>) {
|
||||
pub fn fmt_app_header<'a>(buf: &mut Buf, header: &'a AppHeader<'a>, flags: &MigrationFlags) {
|
||||
buf.indent(0);
|
||||
buf.push_str("app");
|
||||
|
||||
let indent = fmt_spaces_with_outdent(buf, header.before_provides, 0);
|
||||
fmt_exposes(buf, header.provides, indent);
|
||||
fmt_exposes(buf, header.provides, flags, indent);
|
||||
|
||||
let indent = fmt_spaces_with_outdent(buf, header.before_packages, indent);
|
||||
fmt_packages(buf, header.packages.value, indent);
|
||||
fmt_packages(buf, header.packages.value, flags, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_spaces_with_outdent(buf: &mut Buf, spaces: &[CommentOrNewline], indent: u16) -> u16 {
|
||||
|
@ -227,18 +246,26 @@ pub fn fmt_spaces_with_outdent(buf: &mut Buf, spaces: &[CommentOrNewline], inden
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fmt_package_header<'a>(buf: &mut Buf, header: &'a PackageHeader<'a>) {
|
||||
pub fn fmt_package_header<'a>(
|
||||
buf: &mut Buf,
|
||||
header: &'a PackageHeader<'a>,
|
||||
flags: &MigrationFlags,
|
||||
) {
|
||||
buf.indent(0);
|
||||
buf.push_str("package");
|
||||
|
||||
let indent = fmt_spaces_with_outdent(buf, header.before_exposes, 0);
|
||||
fmt_exposes(buf, header.exposes, indent);
|
||||
fmt_exposes(buf, header.exposes, flags, indent);
|
||||
|
||||
let indent = fmt_spaces_with_outdent(buf, header.before_packages, indent);
|
||||
fmt_packages(buf, header.packages.value, indent);
|
||||
fmt_packages(buf, header.packages.value, flags, indent);
|
||||
}
|
||||
|
||||
pub fn fmt_platform_header<'a>(buf: &mut Buf, header: &'a PlatformHeader<'a>) {
|
||||
pub fn fmt_platform_header<'a>(
|
||||
buf: &mut Buf,
|
||||
header: &'a PlatformHeader<'a>,
|
||||
flags: &MigrationFlags,
|
||||
) {
|
||||
buf.indent(0);
|
||||
buf.push_str("platform");
|
||||
let indent = INDENT;
|
||||
|
@ -246,23 +273,31 @@ pub fn fmt_platform_header<'a>(buf: &mut Buf, header: &'a PlatformHeader<'a>) {
|
|||
|
||||
fmt_package_name(buf, header.name.value, indent);
|
||||
|
||||
header.requires.format(buf, indent);
|
||||
header.exposes.keyword.format(buf, indent);
|
||||
fmt_exposes(buf, header.exposes.item, indent);
|
||||
header.packages.keyword.format(buf, indent);
|
||||
fmt_packages(buf, header.packages.item, indent);
|
||||
header.imports.keyword.format(buf, indent);
|
||||
fmt_imports(buf, header.imports.item, indent);
|
||||
header.provides.keyword.format(buf, indent);
|
||||
fmt_provides(buf, header.provides.item, None, indent);
|
||||
header.requires.format(buf, flags, indent);
|
||||
header.exposes.keyword.format(buf, flags, indent);
|
||||
fmt_exposes(buf, header.exposes.item, flags, indent);
|
||||
header.packages.keyword.format(buf, flags, indent);
|
||||
fmt_packages(buf, header.packages.item, flags, indent);
|
||||
header.imports.keyword.format(buf, flags, indent);
|
||||
fmt_imports(buf, header.imports.item, flags, indent);
|
||||
header.provides.keyword.format(buf, flags, indent);
|
||||
fmt_provides(buf, header.provides.item, None, flags, indent);
|
||||
}
|
||||
|
||||
fn fmt_requires(buf: &mut Buf, requires: &PlatformRequires, indent: u16) {
|
||||
fmt_collection(buf, indent, Braces::Curly, requires.rigids, Newlines::No);
|
||||
fn fmt_requires(buf: &mut Buf, requires: &PlatformRequires, flags: &MigrationFlags, indent: u16) {
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Curly,
|
||||
requires.rigids,
|
||||
Newlines::No,
|
||||
);
|
||||
|
||||
buf.spaces(1);
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Curly,
|
||||
requires.signatures,
|
||||
|
@ -280,6 +315,7 @@ impl<'a> Formattable for TypedIdent<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.indent(indent);
|
||||
|
@ -288,7 +324,7 @@ impl<'a> Formattable for TypedIdent<'a> {
|
|||
buf.push(':');
|
||||
buf.spaces(1);
|
||||
|
||||
self.ann.value.format(buf, indent);
|
||||
self.ann.value.format(buf, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,18 +352,19 @@ impl<'a, T: Formattable> Formattable for Spaced<'a, T> {
|
|||
buf: &mut Buf,
|
||||
parens: crate::annotation::Parens,
|
||||
newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
match self {
|
||||
Spaced::Item(item) => {
|
||||
item.format_with_options(buf, parens, newlines, indent);
|
||||
item.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
Spaced::SpaceBefore(item, spaces) => {
|
||||
fmt_spaces(buf, spaces.iter(), indent);
|
||||
item.format_with_options(buf, parens, newlines, indent);
|
||||
item.format_with_options(buf, parens, newlines, flags, indent);
|
||||
}
|
||||
Spaced::SpaceAfter(item, spaces) => {
|
||||
item.format_with_options(buf, parens, newlines, indent);
|
||||
item.format_with_options(buf, parens, newlines, flags, indent);
|
||||
fmt_spaces(buf, spaces.iter(), indent);
|
||||
}
|
||||
}
|
||||
|
@ -337,25 +374,48 @@ impl<'a, T: Formattable> Formattable for Spaced<'a, T> {
|
|||
fn fmt_imports<'a>(
|
||||
buf: &mut Buf,
|
||||
loc_entries: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_collection(buf, indent, Braces::Square, loc_entries, Newlines::No)
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Square,
|
||||
loc_entries,
|
||||
Newlines::No,
|
||||
)
|
||||
}
|
||||
|
||||
fn fmt_provides<'a>(
|
||||
buf: &mut Buf,
|
||||
loc_exposed_names: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
|
||||
loc_provided_types: Option<Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_collection(buf, indent, Braces::Square, loc_exposed_names, Newlines::No);
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Square,
|
||||
loc_exposed_names,
|
||||
Newlines::No,
|
||||
);
|
||||
if let Some(loc_provided) = loc_provided_types {
|
||||
fmt_default_spaces(buf, &[], indent);
|
||||
fmt_collection(buf, indent, Braces::Curly, loc_provided, Newlines::No);
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Curly,
|
||||
loc_provided,
|
||||
Newlines::No,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_to(buf: &mut Buf, to: To, indent: u16) {
|
||||
fn fmt_to(buf: &mut Buf, to: To, _flags: &MigrationFlags, indent: u16) {
|
||||
match to {
|
||||
To::ExistingPackage(name) => {
|
||||
buf.push_str(name);
|
||||
|
@ -367,9 +427,17 @@ fn fmt_to(buf: &mut Buf, to: To, indent: u16) {
|
|||
fn fmt_exposes<N: Formattable + Copy + core::fmt::Debug>(
|
||||
buf: &mut Buf,
|
||||
loc_entries: Collection<'_, Loc<Spaced<'_, N>>>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_collection(buf, indent, Braces::Square, loc_entries, Newlines::No)
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Square,
|
||||
loc_entries,
|
||||
Newlines::No,
|
||||
)
|
||||
}
|
||||
|
||||
pub trait FormatName {
|
||||
|
@ -398,6 +466,7 @@ impl<'a> Formattable for ModuleName<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
_flags: &MigrationFlags,
|
||||
_indent: u16,
|
||||
) {
|
||||
buf.push_str(self.as_str());
|
||||
|
@ -414,6 +483,7 @@ impl<'a> Formattable for ExposedName<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
_flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.indent(indent);
|
||||
|
@ -430,9 +500,10 @@ impl<'a> FormatName for ExposedName<'a> {
|
|||
fn fmt_packages<'a>(
|
||||
buf: &mut Buf,
|
||||
loc_entries: Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_collection(buf, indent, Braces::Curly, loc_entries, Newlines::No)
|
||||
fmt_collection(buf, flags, indent, Braces::Curly, loc_entries, Newlines::No)
|
||||
}
|
||||
|
||||
impl<'a> Formattable for PackageEntry<'a> {
|
||||
|
@ -445,9 +516,10 @@ impl<'a> Formattable for PackageEntry<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_packages_entry(buf, self, indent);
|
||||
fmt_packages_entry(buf, self, flags, indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -461,12 +533,13 @@ impl<'a> Formattable for ImportsEntry<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_imports_entry(buf, self, indent);
|
||||
fmt_imports_entry(buf, self, flags, indent);
|
||||
}
|
||||
}
|
||||
fn fmt_packages_entry(buf: &mut Buf, entry: &PackageEntry, indent: u16) {
|
||||
fn fmt_packages_entry(buf: &mut Buf, entry: &PackageEntry, _flags: &MigrationFlags, indent: u16) {
|
||||
buf.push_str(entry.shorthand);
|
||||
buf.push(':');
|
||||
fmt_default_spaces(buf, entry.spaces_after_shorthand, indent);
|
||||
|
@ -482,7 +555,7 @@ fn fmt_packages_entry(buf: &mut Buf, entry: &PackageEntry, indent: u16) {
|
|||
fmt_package_name(buf, entry.package_name.value, indent);
|
||||
}
|
||||
|
||||
fn fmt_imports_entry(buf: &mut Buf, entry: &ImportsEntry, indent: u16) {
|
||||
fn fmt_imports_entry(buf: &mut Buf, entry: &ImportsEntry, flags: &MigrationFlags, indent: u16) {
|
||||
use roc_parse::header::ImportsEntry::*;
|
||||
|
||||
buf.indent(indent);
|
||||
|
@ -496,6 +569,7 @@ fn fmt_imports_entry(buf: &mut Buf, entry: &ImportsEntry, indent: u16) {
|
|||
|
||||
fmt_collection(
|
||||
buf,
|
||||
flags,
|
||||
indent,
|
||||
Braces::Curly,
|
||||
*loc_exposes_entries,
|
||||
|
@ -512,14 +586,14 @@ fn fmt_imports_entry(buf: &mut Buf, entry: &ImportsEntry, indent: u16) {
|
|||
if !entries.is_empty() {
|
||||
buf.push('.');
|
||||
|
||||
fmt_collection(buf, indent, Braces::Curly, *entries, Newlines::No)
|
||||
fmt_collection(buf, flags, indent, Braces::Curly, *entries, Newlines::No)
|
||||
}
|
||||
}
|
||||
|
||||
IngestedFile(file_name, typed_ident) => {
|
||||
fmt_str_literal(buf, *file_name, indent);
|
||||
fmt_str_literal(buf, *file_name, flags, indent);
|
||||
buf.push_str_allow_spaces(" as ");
|
||||
typed_ident.format(buf, 0);
|
||||
typed_ident.format(buf, flags, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::annotation::{Formattable, Newlines, Parens};
|
||||
use crate::annotation::{Formattable, MigrationFlags, Newlines, Parens};
|
||||
use crate::expr::{
|
||||
expr_is_multiline, expr_lift_spaces_after, fmt_str_literal, format_sq_literal, is_str_multiline,
|
||||
};
|
||||
|
@ -11,8 +11,14 @@ use roc_parse::ast::{
|
|||
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);
|
||||
pub fn fmt_pattern<'a>(
|
||||
buf: &mut Buf,
|
||||
pattern: &'a Pattern<'a>,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
parens: Parens,
|
||||
) {
|
||||
pattern.format_with_options(buf, parens, Newlines::No, flags, indent);
|
||||
}
|
||||
|
||||
impl<'a> Formattable for PatternAs<'a> {
|
||||
|
@ -25,6 +31,7 @@ impl<'a> Formattable for PatternAs<'a> {
|
|||
buf: &mut Buf,
|
||||
_parens: Parens,
|
||||
_newlines: Newlines,
|
||||
_flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
buf.indent(indent);
|
||||
|
@ -93,8 +100,15 @@ impl<'a> Formattable for Pattern<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn format_with_options(&self, buf: &mut Buf, parens: Parens, _newlines: Newlines, indent: u16) {
|
||||
fmt_pattern_inner(self, buf, parens, indent, self.is_multiline());
|
||||
fn format_with_options(
|
||||
&self,
|
||||
buf: &mut Buf,
|
||||
parens: Parens,
|
||||
_newlines: Newlines,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
) {
|
||||
fmt_pattern_inner(self, buf, parens, flags, indent, self.is_multiline());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,6 +116,7 @@ fn fmt_pattern_inner(
|
|||
pat: &Pattern<'_>,
|
||||
buf: &mut Buf,
|
||||
parens: Parens,
|
||||
flags: &MigrationFlags,
|
||||
indent: u16,
|
||||
outer_is_multiline: bool,
|
||||
) {
|
||||
|
@ -122,7 +137,7 @@ fn fmt_pattern_inner(
|
|||
match me.item {
|
||||
Identifier { ident: string } => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
snakify_camel_ident(buf, string, flags);
|
||||
}
|
||||
Tag(name) | OpaqueRef(name) => {
|
||||
buf.indent(indent);
|
||||
|
@ -154,7 +169,7 @@ fn fmt_pattern_inner(
|
|||
}
|
||||
}
|
||||
|
||||
fmt_pattern_inner(&pat.item, buf, Parens::InApply, indent, is_multiline);
|
||||
fmt_pattern_inner(&pat.item, buf, Parens::InApply, flags, indent, is_multiline);
|
||||
|
||||
if !pat.after.is_empty() {
|
||||
if !is_multiline {
|
||||
|
@ -170,6 +185,7 @@ fn fmt_pattern_inner(
|
|||
&loc_arg.value,
|
||||
buf,
|
||||
Parens::InApply,
|
||||
flags,
|
||||
indent_more,
|
||||
is_multiline,
|
||||
);
|
||||
|
@ -197,7 +213,14 @@ fn fmt_pattern_inner(
|
|||
}
|
||||
}
|
||||
|
||||
fmt_pattern_inner(&item.item, buf, Parens::NotNeeded, indent, is_multiline);
|
||||
fmt_pattern_inner(
|
||||
&item.item,
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
flags,
|
||||
indent,
|
||||
is_multiline,
|
||||
);
|
||||
|
||||
let is_multiline = item.item.is_multiline();
|
||||
|
||||
|
@ -227,13 +250,14 @@ fn fmt_pattern_inner(
|
|||
|
||||
RequiredField(name, loc_pattern) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name);
|
||||
snakify_camel_ident(buf, name, flags);
|
||||
buf.push_str(":");
|
||||
buf.spaces(1);
|
||||
fmt_pattern_inner(
|
||||
&loc_pattern.value,
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
flags,
|
||||
indent,
|
||||
is_multiline,
|
||||
);
|
||||
|
@ -241,10 +265,10 @@ fn fmt_pattern_inner(
|
|||
|
||||
OptionalField(name, loc_pattern) => {
|
||||
buf.indent(indent);
|
||||
buf.push_str(name);
|
||||
snakify_camel_ident(buf, name, flags);
|
||||
buf.push_str(" ?");
|
||||
buf.spaces(1);
|
||||
loc_pattern.format(buf, indent);
|
||||
loc_pattern.format(buf, flags, indent);
|
||||
}
|
||||
|
||||
NumLiteral(string) => {
|
||||
|
@ -274,7 +298,7 @@ fn fmt_pattern_inner(
|
|||
buf.indent(indent);
|
||||
buf.push_str(string);
|
||||
}
|
||||
StrLiteral(literal) => fmt_str_literal(buf, literal, indent),
|
||||
StrLiteral(literal) => fmt_str_literal(buf, literal, flags, indent),
|
||||
SingleQuote(string) => {
|
||||
buf.indent(indent);
|
||||
format_sq_literal(buf, string);
|
||||
|
@ -294,6 +318,7 @@ fn fmt_pattern_inner(
|
|||
&loc_pattern.value,
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
flags,
|
||||
indent,
|
||||
is_multiline,
|
||||
);
|
||||
|
@ -318,6 +343,7 @@ fn fmt_pattern_inner(
|
|||
&loc_pattern.value,
|
||||
buf,
|
||||
Parens::NotNeeded,
|
||||
flags,
|
||||
indent,
|
||||
is_multiline,
|
||||
);
|
||||
|
@ -340,7 +366,7 @@ fn fmt_pattern_inner(
|
|||
// 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);
|
||||
pattern_as.format(buf, flags, indent + INDENT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,9 +378,9 @@ fn fmt_pattern_inner(
|
|||
buf.push('(');
|
||||
}
|
||||
|
||||
fmt_pattern(buf, &pattern.value, indent, parens);
|
||||
fmt_pattern(buf, &pattern.value, flags, indent, parens);
|
||||
|
||||
pattern_as.format(buf, indent + INDENT);
|
||||
pattern_as.format(buf, flags, indent + INDENT);
|
||||
|
||||
if needs_parens {
|
||||
buf.indent(indent);
|
||||
|
@ -376,7 +402,7 @@ fn fmt_pattern_inner(
|
|||
buf.push('.');
|
||||
}
|
||||
|
||||
buf.push_str(ident);
|
||||
snakify_camel_ident(buf, ident, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,3 +526,91 @@ pub fn pattern_lift_spaces_after<'a, 'b: 'a>(
|
|||
after: lifted.after,
|
||||
}
|
||||
}
|
||||
fn snakify_camel_ident(buf: &mut Buf, string: &str, flags: &MigrationFlags) {
|
||||
let chars: Vec<char> = string.chars().collect();
|
||||
if !flags.snakify || (string.contains('_') && !string.ends_with('_')) {
|
||||
buf.push_str(string);
|
||||
return;
|
||||
}
|
||||
let mut index = 0;
|
||||
let len = chars.len();
|
||||
|
||||
while index < len {
|
||||
let prev = if index == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(chars[index - 1])
|
||||
};
|
||||
let c = chars[index];
|
||||
let next = chars.get(index + 1);
|
||||
let boundary = match (prev, c, next) {
|
||||
// LUU, LUN, and LUL (simplified to LU_)
|
||||
(Some(p), curr, _) if !p.is_ascii_uppercase() && curr.is_ascii_uppercase() => true,
|
||||
// UUL
|
||||
(Some(p), curr, Some(n))
|
||||
if p.is_ascii_uppercase()
|
||||
&& curr.is_ascii_uppercase()
|
||||
&& n.is_ascii_lowercase() =>
|
||||
{
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
// those are boundary transitions - should push _ and curr
|
||||
if boundary {
|
||||
buf.push('_');
|
||||
}
|
||||
buf.push(c.to_ascii_lowercase());
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod snakify_test {
|
||||
use bumpalo::Bump;
|
||||
|
||||
use super::snakify_camel_ident;
|
||||
use crate::{annotation::MigrationFlags, Buf};
|
||||
|
||||
fn check_snakify(arena: &Bump, original: &str) -> String {
|
||||
let mut buf = Buf::new_in(arena);
|
||||
buf.indent(0);
|
||||
let flags = MigrationFlags::new(true);
|
||||
snakify_camel_ident(&mut buf, original, &flags);
|
||||
buf.text.to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_snakify_camel_ident() {
|
||||
let arena = Bump::new();
|
||||
assert_eq!(check_snakify(&arena, "A"), "a");
|
||||
assert_eq!(check_snakify(&arena, "Ba"), "ba");
|
||||
assert_eq!(check_snakify(&arena, "aB"), "a_b");
|
||||
assert_eq!(check_snakify(&arena, "aBa"), "a_ba");
|
||||
assert_eq!(check_snakify(&arena, "mBB"), "m_bb");
|
||||
assert_eq!(check_snakify(&arena, "NbA"), "nb_a");
|
||||
assert_eq!(check_snakify(&arena, "doIT"), "do_it");
|
||||
assert_eq!(check_snakify(&arena, "ROC"), "roc");
|
||||
assert_eq!(
|
||||
check_snakify(&arena, "someHTTPRequest"),
|
||||
"some_http_request"
|
||||
);
|
||||
assert_eq!(check_snakify(&arena, "usingXML"), "using_xml");
|
||||
assert_eq!(check_snakify(&arena, "some123"), "some123");
|
||||
assert_eq!(
|
||||
check_snakify(&arena, "theHTTPStatus404"),
|
||||
"the_http_status404"
|
||||
);
|
||||
assert_eq!(
|
||||
check_snakify(&arena, "inThe99thPercentile"),
|
||||
"in_the99th_percentile"
|
||||
);
|
||||
assert_eq!(
|
||||
check_snakify(&arena, "all400SeriesErrorCodes"),
|
||||
"all400_series_error_codes",
|
||||
);
|
||||
assert_eq!(check_snakify(&arena, "number4Yellow"), "number4_yellow");
|
||||
assert_eq!(check_snakify(&arena, "useCases4Cobol"), "use_cases4_cobol");
|
||||
assert_eq!(check_snakify(&arena, "c3PO"), "c3_po")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6019,25 +6019,6 @@ All branches in an `if` must have the same type!
|
|||
"
|
||||
);
|
||||
|
||||
test_report!(
|
||||
closure_underscore_ident,
|
||||
indoc!(
|
||||
r"
|
||||
\the_answer -> 100
|
||||
"
|
||||
),
|
||||
@r"
|
||||
── NAMING PROBLEM in /code/proj/Main.roc ───────────────────────────────────────
|
||||
|
||||
I am trying to parse an identifier here:
|
||||
|
||||
4│ \the_answer -> 100
|
||||
^
|
||||
|
||||
Underscores are not allowed in identifiers. Use camelCase instead!
|
||||
"
|
||||
);
|
||||
|
||||
test_report!(
|
||||
#[ignore]
|
||||
double_binop,
|
||||
|
@ -10697,26 +10678,26 @@ All branches in an `if` must have the same type!
|
|||
);
|
||||
|
||||
test_report!(
|
||||
underscore_in_middle_of_identifier,
|
||||
call_with_declared_identifier_with_more_than_one_underscore,
|
||||
indoc!(
|
||||
r"
|
||||
f = \x, y, z -> x + y + z
|
||||
f__arg = \x, y, z -> x + y + z
|
||||
|
||||
\a, _b -> f a var_name 1
|
||||
\a, b -> f__arg a b 1
|
||||
"
|
||||
),
|
||||
|golden| pretty_assertions::assert_eq!(
|
||||
golden,
|
||||
indoc!(
|
||||
r"
|
||||
── SYNTAX PROBLEM in /code/proj/Main.roc ───────────────────────────────────────
|
||||
r"── NAMING PROBLEM in /code/proj/Main.roc ───────────────────────────────────────
|
||||
|
||||
Underscores are not allowed in identifier names:
|
||||
I am trying to parse an identifier here:
|
||||
|
||||
6│ \a, _b -> f a var_name 1
|
||||
^^^^^^^^
|
||||
4│ f__arg = \x, y, z -> x + y + z
|
||||
^^^^^^
|
||||
|
||||
I recommend using camelCase. It's the standard style in Roc code!
|
||||
While snake case is allowed here, only a single consecutive underscore
|
||||
should be used.
|
||||
"
|
||||
),
|
||||
)
|
||||
|
|
|
@ -231,6 +231,7 @@ pub enum BadIdent {
|
|||
|
||||
UnderscoreAlone(Position),
|
||||
UnderscoreInMiddle(Position),
|
||||
TooManyUnderscores(Position),
|
||||
UnderscoreAtStart {
|
||||
position: Position,
|
||||
/// If this variable was already declared in a pattern (e.g. \_x -> _x),
|
||||
|
@ -252,11 +253,21 @@ fn is_alnum(ch: char) -> bool {
|
|||
}
|
||||
|
||||
fn chomp_lowercase_part(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
chomp_part(char::is_lowercase, is_alnum, true, buffer)
|
||||
chomp_part(
|
||||
char::is_lowercase,
|
||||
is_plausible_ident_continue,
|
||||
true,
|
||||
buffer,
|
||||
)
|
||||
}
|
||||
|
||||
fn chomp_uppercase_part(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
chomp_part(char::is_uppercase, is_alnum, false, buffer)
|
||||
chomp_part(
|
||||
char::is_uppercase,
|
||||
is_plausible_ident_continue,
|
||||
false,
|
||||
buffer,
|
||||
)
|
||||
}
|
||||
|
||||
fn chomp_anycase_part(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
|
@ -265,7 +276,12 @@ fn chomp_anycase_part(buffer: &[u8]) -> Result<&str, Progress> {
|
|||
let allow_bang =
|
||||
char::from_utf8_slice_start(buffer).map_or(false, |(leading, _)| leading.is_lowercase());
|
||||
|
||||
chomp_part(char::is_alphabetic, is_alnum, allow_bang, buffer)
|
||||
chomp_part(
|
||||
char::is_alphabetic,
|
||||
is_plausible_ident_continue,
|
||||
allow_bang,
|
||||
buffer,
|
||||
)
|
||||
}
|
||||
|
||||
fn chomp_integer_part(buffer: &[u8]) -> Result<&str, Progress> {
|
||||
|
@ -429,7 +445,14 @@ fn chomp_opaque_ref(buffer: &[u8], pos: Position) -> Result<&str, BadIdent> {
|
|||
Err(bad_ident(pos.bump_column(width as u32)))
|
||||
} else {
|
||||
let value = unsafe { std::str::from_utf8_unchecked(&buffer[..width]) };
|
||||
Ok(value)
|
||||
if value.contains('_') {
|
||||
// we don't allow underscores in the middle of an identifier
|
||||
// but still parse them (and generate a malformed identifier)
|
||||
// to give good error messages for this case
|
||||
Err(BadIdent::UnderscoreInMiddle(pos.bump_column(width as u32)))
|
||||
} else {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => Err(bad_ident(pos.bump_column(1))),
|
||||
|
@ -486,7 +509,7 @@ fn chomp_identifier_chain<'a>(
|
|||
}
|
||||
|
||||
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
if ch.is_alphabetic() || ch.is_ascii_digit() {
|
||||
if ch.is_alphabetic() || ch.is_ascii_digit() || ch == '_' {
|
||||
chomped += width;
|
||||
} else if ch == '!' && !first_is_uppercase {
|
||||
chomped += width;
|
||||
|
@ -556,19 +579,20 @@ fn chomp_identifier_chain<'a>(
|
|||
BadIdent::WeirdDotAccess(pos.bump_column(chomped as u32 + width)),
|
||||
)),
|
||||
}
|
||||
} else if let Ok(('_', _)) = char::from_utf8_slice_start(&buffer[chomped..]) {
|
||||
// we don't allow underscores in the middle of an identifier
|
||||
// but still parse them (and generate a malformed identifier)
|
||||
// to give good error messages for this case
|
||||
Err((
|
||||
chomped as u32 + 1,
|
||||
BadIdent::UnderscoreInMiddle(pos.bump_column(chomped as u32 + 1)),
|
||||
))
|
||||
} else if first_is_uppercase {
|
||||
// just one segment, starting with an uppercase letter; that's a tag
|
||||
let value = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
|
||||
|
||||
Ok((chomped as u32, Ident::Tag(value)))
|
||||
if value.contains('_') {
|
||||
// we don't allow underscores in the middle of an identifier
|
||||
// but still parse them (and generate a malformed identifier)
|
||||
// to give good error messages for this case
|
||||
Err((
|
||||
chomped as u32,
|
||||
BadIdent::UnderscoreInMiddle(pos.bump_column(chomped as u32)),
|
||||
))
|
||||
} else {
|
||||
Ok((chomped as u32, Ident::Tag(value)))
|
||||
}
|
||||
} else {
|
||||
// just one segment, starting with a lowercase letter; that's a normal identifier
|
||||
let value = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
|
||||
|
@ -689,3 +713,121 @@ fn chomp_access_chain<'a>(buffer: &'a [u8], parts: &mut Vec<'a, Accessor<'a>>) -
|
|||
Ok(chomped as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn assert_ident_parses<'a>(arena: &'a Bump, ident: &str, expected: Ident<'a>) {
|
||||
let s = State::new(ident.as_bytes());
|
||||
let (_, id, _) = parse_ident(arena, s, 0).unwrap();
|
||||
assert_eq!(id, expected);
|
||||
}
|
||||
|
||||
fn assert_ident_parses_tag(arena: &Bump, ident: &str) {
|
||||
assert_ident_parses(arena, ident, Ident::Tag(ident));
|
||||
}
|
||||
fn assert_ident_parses_opaque(arena: &Bump, ident: &str) {
|
||||
assert_ident_parses(arena, ident, Ident::OpaqueRef(ident));
|
||||
}
|
||||
fn assert_ident_parses_simple_access(arena: &Bump, ident: &str) {
|
||||
assert_ident_parses(
|
||||
arena,
|
||||
ident,
|
||||
Ident::Access {
|
||||
module_name: "",
|
||||
parts: arena.alloc([Accessor::RecordField(ident)]),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn assert_ident_parses_malformed(arena: &Bump, ident: &str, pos: Position) {
|
||||
assert_ident_parses(
|
||||
arena,
|
||||
ident,
|
||||
Ident::Malformed(ident, BadIdent::UnderscoreInMiddle(pos)),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_ident_lowercase_camel() {
|
||||
let arena = Bump::new();
|
||||
assert_ident_parses_simple_access(&arena, "hello");
|
||||
assert_ident_parses_simple_access(&arena, "hello23");
|
||||
assert_ident_parses_simple_access(&arena, "helloWorld");
|
||||
assert_ident_parses_simple_access(&arena, "helloWorld23");
|
||||
assert_ident_parses_simple_access(&arena, "helloWorldThisIsQuiteATag");
|
||||
assert_ident_parses_simple_access(&arena, "helloWorldThisIsQuiteATag_");
|
||||
assert_ident_parses_simple_access(&arena, "helloworldthisisquiteatag_");
|
||||
assert_ident_parses_simple_access(&arena, "helloWorldThisIsQuiteATag23");
|
||||
assert_ident_parses_simple_access(&arena, "helloWorldThisIsQuiteATag23_");
|
||||
assert_ident_parses_simple_access(&arena, "helloworldthisisquiteatag23_");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_ident_lowercase_snake() {
|
||||
let arena = Bump::new();
|
||||
assert_ident_parses_simple_access(&arena, "hello_world");
|
||||
assert_ident_parses_simple_access(&arena, "hello_world23");
|
||||
assert_ident_parses_simple_access(&arena, "hello_world_this_is_quite_a_tag");
|
||||
assert_ident_parses_simple_access(&arena, "hello_world_this_is_quite_a_tag_");
|
||||
assert_ident_parses_simple_access(&arena, "hello_world_this_is_quite_a_tag23");
|
||||
assert_ident_parses_simple_access(&arena, "hello_world_this_is_quite_a_tag23_");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_tag_camel() {
|
||||
let arena = Bump::new();
|
||||
assert_ident_parses_tag(&arena, "Hello");
|
||||
assert_ident_parses_tag(&arena, "Hello23");
|
||||
assert_ident_parses_tag(&arena, "HelloWorld");
|
||||
assert_ident_parses_tag(&arena, "HelloWorld23");
|
||||
assert_ident_parses_tag(&arena, "HelloWorldThisIsQuiteATag");
|
||||
assert_ident_parses_tag(&arena, "HelloWorldThisIsQuiteATag23");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_tag_snake_is_malformed() {
|
||||
let arena = Bump::new();
|
||||
assert_ident_parses_malformed(&arena, "Hello_World", Position { offset: 11 });
|
||||
assert_ident_parses_malformed(&arena, "Hello_World23", Position { offset: 13 });
|
||||
assert_ident_parses_malformed(
|
||||
&arena,
|
||||
"Hello_World_This_Is_Quite_A_Tag",
|
||||
Position { offset: 31 },
|
||||
);
|
||||
assert_ident_parses_malformed(
|
||||
&arena,
|
||||
"Hello_World_This_Is_Quite_A_Tag23",
|
||||
Position { offset: 33 },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_opaque_ref_camel() {
|
||||
let arena = Bump::new();
|
||||
assert_ident_parses_opaque(&arena, "@Hello");
|
||||
assert_ident_parses_opaque(&arena, "@Hello23");
|
||||
assert_ident_parses_opaque(&arena, "@HelloWorld");
|
||||
assert_ident_parses_opaque(&arena, "@HelloWorld23");
|
||||
assert_ident_parses_opaque(&arena, "@HelloWorldThisIsQuiteARef");
|
||||
assert_ident_parses_opaque(&arena, "@HelloWorldThisIsQuiteARef23");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_opaque_ref_snake_is_malformed() {
|
||||
let arena = Bump::new();
|
||||
assert_ident_parses_malformed(&arena, "@Hello_World", Position { offset: 12 });
|
||||
assert_ident_parses_malformed(&arena, "@Hello_World23", Position { offset: 14 });
|
||||
assert_ident_parses_malformed(
|
||||
&arena,
|
||||
"@Hello_World_This_Is_Quite_A_Ref",
|
||||
Position { offset: 32 },
|
||||
);
|
||||
assert_ident_parses_malformed(
|
||||
&arena,
|
||||
"@Hello_World_This_Is_Quite_A_Ref23",
|
||||
Position { offset: 34 },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -855,6 +855,7 @@ fn remove_spaces_bad_ident(ident: BadIdent) -> BadIdent {
|
|||
position: Position::zero(),
|
||||
declaration_region,
|
||||
},
|
||||
BadIdent::TooManyUnderscores(_) => BadIdent::TooManyUnderscores(Position::zero()),
|
||||
BadIdent::QualifiedTag(_) => BadIdent::QualifiedTag(Position::zero()),
|
||||
BadIdent::WeirdAccessor(_) => BadIdent::WeirdAccessor(Position::zero()),
|
||||
BadIdent::WeirdDotAccess(_) => BadIdent::WeirdDotAccess(Position::zero()),
|
||||
|
|
|
@ -763,8 +763,8 @@ impl RuntimeError {
|
|||
record: _,
|
||||
field: region,
|
||||
}
|
||||
| RuntimeError::ReadIngestedFileError { region, .. } => *region,
|
||||
RuntimeError::InvalidUnicodeCodePt(region) => *region,
|
||||
| RuntimeError::ReadIngestedFileError { region, .. }
|
||||
| RuntimeError::InvalidUnicodeCodePt(region) => *region,
|
||||
RuntimeError::UnresolvedTypeVar | RuntimeError::ErroneousType => Region::zero(),
|
||||
RuntimeError::LookupNotInScope { loc_name, .. } => loc_name.region,
|
||||
RuntimeError::OpaqueNotDefined { usage, .. } => usage.region,
|
||||
|
|
|
@ -452,12 +452,11 @@ fn number_args_to_mono_id(
|
|||
// Unroll aliases in this loop, as many aliases as we encounter.
|
||||
loop {
|
||||
match content {
|
||||
Content::Structure(flat_type) => {
|
||||
if let FlatType::Apply(outer_symbol, args) = flat_type {
|
||||
return num_num_args_to_mono_id(*outer_symbol, *args, subs, problems);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
Content::Structure(FlatType::Apply(outer_symbol, args)) => {
|
||||
return num_num_args_to_mono_id(*outer_symbol, *args, subs, problems);
|
||||
}
|
||||
Content::Structure(_) => {
|
||||
break;
|
||||
}
|
||||
Content::FlexVar(_) => {
|
||||
// Num *
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bumpalo::Bump;
|
||||
use roc_fmt::{annotation::Formattable, header::fmt_header};
|
||||
use roc_fmt::{annotation::Formattable, annotation::MigrationFlags, header::fmt_header};
|
||||
use roc_parse::{
|
||||
ast::{Defs, Expr, FullAst, Header, Malformed, SpacesBefore},
|
||||
header::parse_module_defs,
|
||||
|
@ -83,24 +83,25 @@ impl<'a> Output<'a> {
|
|||
pub fn format(&self) -> InputOwned {
|
||||
let arena = Bump::new();
|
||||
let mut buf = Buf::new_in(&arena);
|
||||
let flags = MigrationFlags::new(false);
|
||||
match self {
|
||||
Output::Header(header) => {
|
||||
fmt_header(&mut buf, header);
|
||||
fmt_header(&mut buf, header, &flags);
|
||||
buf.fmt_end_of_file();
|
||||
InputOwned::Header(buf.as_str().to_string())
|
||||
}
|
||||
Output::ModuleDefs(defs) => {
|
||||
defs.format(&mut buf, 0);
|
||||
defs.format(&mut buf, &flags, 0);
|
||||
buf.fmt_end_of_file();
|
||||
InputOwned::ModuleDefs(buf.as_str().to_string())
|
||||
}
|
||||
Output::Expr(expr) => {
|
||||
expr.format(&mut buf, 0);
|
||||
expr.format(&mut buf, &flags, 0);
|
||||
InputOwned::Expr(buf.as_str().to_string())
|
||||
}
|
||||
Output::Full(full) => {
|
||||
fmt_header(&mut buf, &full.header);
|
||||
full.defs.format(&mut buf, 0);
|
||||
fmt_header(&mut buf, &full.header, &flags);
|
||||
full.defs.format(&mut buf, &flags, 0);
|
||||
buf.fmt_end_of_file();
|
||||
InputOwned::Full(buf.as_str().to_string())
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
Closure(
|
||||
[
|
||||
@1-11 MalformedIdent(
|
||||
"the_answer",
|
||||
UnderscoreInMiddle(
|
||||
@5,
|
||||
),
|
||||
),
|
||||
],
|
||||
@15-17 Num(
|
||||
"42",
|
||||
),
|
||||
)
|
|
@ -1,42 +0,0 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-3,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "J",
|
||||
vars: [],
|
||||
},
|
||||
ann: @2-3 Apply(
|
||||
"",
|
||||
"R",
|
||||
[],
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@5-8 SpaceBefore(
|
||||
MalformedIdent(
|
||||
"n_p",
|
||||
UnderscoreInMiddle(
|
||||
@7,
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
SpaceAfter(
|
||||
Closure(
|
||||
[
|
||||
@1-11 Identifier {
|
||||
ident: "the_answer",
|
||||
},
|
||||
],
|
||||
@15-17 Num(
|
||||
"42",
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -0,0 +1 @@
|
|||
\the_answer -> 42
|
|
@ -0,0 +1,45 @@
|
|||
SpaceAfter(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(0),
|
||||
],
|
||||
regions: [
|
||||
@0-3,
|
||||
],
|
||||
space_before: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
space_after: [
|
||||
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [
|
||||
Alias {
|
||||
header: TypeHeader {
|
||||
name: @0-1 "J",
|
||||
vars: [],
|
||||
},
|
||||
ann: @2-3 Apply(
|
||||
"",
|
||||
"R",
|
||||
[],
|
||||
),
|
||||
},
|
||||
],
|
||||
value_defs: [],
|
||||
},
|
||||
@4-7 SpaceBefore(
|
||||
Var {
|
||||
module_name: "",
|
||||
ident: "n_p",
|
||||
},
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
)
|
|
@ -1,2 +1,2 @@
|
|||
J:R
|
||||
n_p
|
||||
n_p
|
|
@ -4,6 +4,7 @@ extern crate indoc;
|
|||
#[cfg(test)]
|
||||
mod test_fmt {
|
||||
use bumpalo::Bump;
|
||||
use roc_fmt::annotation::MigrationFlags;
|
||||
use roc_fmt::def::fmt_defs;
|
||||
use roc_fmt::header::fmt_header;
|
||||
use roc_fmt::Buf;
|
||||
|
@ -36,11 +37,12 @@ mod test_fmt {
|
|||
state: State<'a>,
|
||||
buf: &mut Buf<'_>,
|
||||
) {
|
||||
fmt_header(buf, header);
|
||||
let flags = MigrationFlags::new(false);
|
||||
fmt_header(buf, header, &flags);
|
||||
|
||||
match parse_module_defs(arena, state, Defs::default()) {
|
||||
Ok(loc_defs) => {
|
||||
fmt_defs(buf, &loc_defs, 0);
|
||||
fmt_defs(buf, &loc_defs, &flags, 0);
|
||||
}
|
||||
Err(error) => {
|
||||
let src = if src.len() > 1000 {
|
||||
|
@ -1492,7 +1494,7 @@ mod test_fmt {
|
|||
fn parenthetical_def() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
(UserId userId) = 5
|
||||
(UserId user_id) = 5
|
||||
y = 10
|
||||
|
||||
42
|
||||
|
@ -1502,7 +1504,7 @@ mod test_fmt {
|
|||
expr_formats_same(indoc!(
|
||||
r"
|
||||
# A
|
||||
(UserId userId) = 5
|
||||
(UserId user_id) = 5
|
||||
# B
|
||||
y = 10
|
||||
|
||||
|
@ -1539,13 +1541,13 @@ mod test_fmt {
|
|||
fn lambda_returns_record() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
toRecord = \_ -> {
|
||||
to_record = \_ -> {
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
}
|
||||
|
||||
toRecord
|
||||
to_record
|
||||
"
|
||||
));
|
||||
|
||||
|
@ -1560,7 +1562,7 @@ mod test_fmt {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
toRecord = \_ ->
|
||||
to_record = \_ ->
|
||||
val = 0
|
||||
|
||||
{
|
||||
|
@ -1569,32 +1571,32 @@ mod test_fmt {
|
|||
z: 3,
|
||||
}
|
||||
|
||||
toRecord
|
||||
to_record
|
||||
"
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r"
|
||||
toRecord = \_ ->
|
||||
to_record = \_ ->
|
||||
{
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
}
|
||||
|
||||
toRecord
|
||||
to_record
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r"
|
||||
toRecord = \_ -> {
|
||||
to_record = \_ -> {
|
||||
x: 1,
|
||||
y: 2,
|
||||
z: 3,
|
||||
}
|
||||
|
||||
toRecord
|
||||
to_record
|
||||
"
|
||||
),
|
||||
);
|
||||
|
@ -1604,13 +1606,13 @@ mod test_fmt {
|
|||
fn lambda_returns_list() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
toList = \_ -> [
|
||||
to_list = \_ -> [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
|
||||
toList
|
||||
to_list
|
||||
"
|
||||
));
|
||||
|
||||
|
@ -1625,7 +1627,7 @@ mod test_fmt {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
toList = \_ ->
|
||||
to_list = \_ ->
|
||||
val = 0
|
||||
|
||||
[
|
||||
|
@ -1634,32 +1636,32 @@ mod test_fmt {
|
|||
3,
|
||||
]
|
||||
|
||||
toList
|
||||
to_list
|
||||
"
|
||||
));
|
||||
|
||||
expr_formats_to(
|
||||
indoc!(
|
||||
r"
|
||||
toList = \_ ->
|
||||
to_list = \_ ->
|
||||
[
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
|
||||
toList
|
||||
to_list
|
||||
"
|
||||
),
|
||||
indoc!(
|
||||
r"
|
||||
toList = \_ -> [
|
||||
to_list = \_ -> [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
]
|
||||
|
||||
toList
|
||||
to_list
|
||||
"
|
||||
),
|
||||
);
|
||||
|
@ -3116,7 +3118,7 @@ mod test_fmt {
|
|||
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
myDef =
|
||||
my_def =
|
||||
list = [
|
||||
a,
|
||||
b,
|
||||
|
@ -3127,7 +3129,7 @@ mod test_fmt {
|
|||
d,
|
||||
}
|
||||
|
||||
myDef
|
||||
my_def
|
||||
"
|
||||
));
|
||||
|
||||
|
@ -3672,7 +3674,7 @@ mod test_fmt {
|
|||
fn def_when() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
myLongFunctionName = \x ->
|
||||
my_long_function_name = \x ->
|
||||
when b is
|
||||
1 | 2 ->
|
||||
when c is
|
||||
|
@ -4974,10 +4976,10 @@ mod test_fmt {
|
|||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [ mainForHost ]
|
||||
provides [ main_for_host ]
|
||||
|
||||
mainForHost : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
||||
mainForHost = main
|
||||
main_for_host : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
||||
main_for_host = main
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
|
@ -4987,10 +4989,10 @@ mod test_fmt {
|
|||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
provides [main_for_host]
|
||||
|
||||
mainForHost : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
||||
mainForHost = main
|
||||
main_for_host : { init : ({} -> Model) as Init, update : (Model, Str -> Model) as Update, view : (Model -> Str) as View }
|
||||
main_for_host = main
|
||||
"#
|
||||
),
|
||||
);
|
||||
|
@ -5313,8 +5315,8 @@ mod test_fmt {
|
|||
fn backpassing_simple() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
getChar = \ctx ->
|
||||
x <- Task.await (getCharScope scope)
|
||||
get_char = \ctx ->
|
||||
x <- Task.await (get_char_scope scope)
|
||||
42
|
||||
|
||||
42
|
||||
|
@ -5326,8 +5328,8 @@ mod test_fmt {
|
|||
fn backpassing_apply_tag() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
getChar = \ctx ->
|
||||
(T val newScope) <- Task.await (getCharScope scope)
|
||||
get_char = \ctx ->
|
||||
(T val new_scope) <- Task.await (get_char_scope scope)
|
||||
42
|
||||
|
||||
42
|
||||
|
@ -5406,9 +5408,9 @@ mod test_fmt {
|
|||
fn backpassing_body_on_newline() {
|
||||
expr_formats_same(indoc!(
|
||||
r"
|
||||
getChar = \ctx ->
|
||||
get_char = \ctx ->
|
||||
x <-
|
||||
Task.await (getCharScope scope)
|
||||
Task.await (get_char_scope scope)
|
||||
42
|
||||
|
||||
42
|
||||
|
|
|
@ -265,12 +265,10 @@ mod test_snapshots {
|
|||
fail/where_type_variable.expr,
|
||||
fail/wild_case_arrow.expr,
|
||||
malformed/bad_opaque_ref.expr,
|
||||
malformed/malformed_ident_due_to_underscore.expr,
|
||||
malformed/malformed_pattern_field_access.expr, // See https://github.com/roc-lang/roc/issues/399
|
||||
malformed/malformed_pattern_module_name.expr, // See https://github.com/roc-lang/roc/issues/399
|
||||
malformed/module_dot_tuple.expr,
|
||||
malformed/qualified_tag.expr,
|
||||
malformed/underscore_expr_in_def.expr,
|
||||
pass/ability_demand_signature_is_multiline.expr,
|
||||
pass/ability_multi_line.expr,
|
||||
pass/ability_single_line.expr,
|
||||
|
@ -575,6 +573,7 @@ mod test_snapshots {
|
|||
pass/return_with_after.expr,
|
||||
pass/separate_defs.moduledefs,
|
||||
pass/single_arg_closure.expr,
|
||||
pass/single_arg_with_underscore_closure.expr,
|
||||
pass/single_underscore_closure.expr,
|
||||
pass/space_before_colon.full,
|
||||
pass/space_before_parens_space_after.expr,
|
||||
|
@ -627,6 +626,7 @@ mod test_snapshots {
|
|||
pass/unary_not.expr,
|
||||
pass/unary_not_with_parens.expr,
|
||||
pass/underscore_backpassing.expr,
|
||||
pass/underscore_expr_in_def.expr,
|
||||
pass/underscore_in_assignment_pattern.expr,
|
||||
pass/value_def_confusion.expr,
|
||||
pass/var_else.expr,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use log::{debug, info};
|
||||
use roc_fmt::annotation::MigrationFlags;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use bumpalo::Bump;
|
||||
|
@ -92,7 +93,8 @@ impl DocInfo {
|
|||
let arena = &Bump::new();
|
||||
|
||||
let ast = Ast::parse(arena, source).ok()?;
|
||||
let fmt = ast.fmt();
|
||||
let flags = MigrationFlags::new(false);
|
||||
let fmt = ast.fmt(&flags);
|
||||
|
||||
if source == fmt.as_str() {
|
||||
None
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use bumpalo::Bump;
|
||||
use roc_fmt::Buf;
|
||||
use roc_fmt::{annotation::MigrationFlags, Buf};
|
||||
use roc_parse::{
|
||||
ast::{Defs, Header, SpacesBefore},
|
||||
header::parse_module_defs,
|
||||
|
@ -40,12 +40,12 @@ impl<'a> Ast<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn fmt(&self) -> FormattedAst<'a> {
|
||||
pub fn fmt(&self, flags: &MigrationFlags) -> FormattedAst<'a> {
|
||||
let mut buf = Buf::new_in(self.arena);
|
||||
|
||||
roc_fmt::header::fmt_header(&mut buf, &self.module);
|
||||
roc_fmt::header::fmt_header(&mut buf, &self.module, flags);
|
||||
|
||||
roc_fmt::def::fmt_defs(&mut buf, &self.defs, 0);
|
||||
roc_fmt::def::fmt_defs(&mut buf, &self.defs, flags, 0);
|
||||
|
||||
buf.fmt_end_of_file();
|
||||
|
||||
|
|
|
@ -25,8 +25,9 @@ pub fn format_answer<'a>(arena: &'a Bump, answer: Expr<'_>) -> &'a str {
|
|||
Expr::Closure(_, _) => "<function>",
|
||||
_ => {
|
||||
let mut expr = roc_fmt::Buf::new_in(arena);
|
||||
let flags = roc_fmt::annotation::MigrationFlags::new(false);
|
||||
|
||||
answer.format_with_options(&mut expr, Parens::NotNeeded, Newlines::Yes, 0);
|
||||
answer.format_with_options(&mut expr, Parens::NotNeeded, Newlines::Yes, &flags, 0);
|
||||
|
||||
expr.into_bump_str()
|
||||
}
|
||||
|
|
|
@ -1649,10 +1649,10 @@ fn to_bad_ident_expr_report<'b>(
|
|||
|
||||
UnderscoreInMiddle(_pos) => {
|
||||
alloc.stack([
|
||||
alloc.reflow("Underscores are not allowed in identifier names:"),
|
||||
alloc.reflow("Underscores are not allowed in tag or opaque ref names:"),
|
||||
alloc.region(lines.convert_region(surroundings), severity),
|
||||
alloc.concat([alloc
|
||||
.reflow(r"I recommend using camelCase. It's the standard style in Roc code!")]),
|
||||
.reflow(r"I recommend using PascalCase. It's the standard style in Roc code!")]),
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -1681,6 +1681,16 @@ fn to_bad_ident_expr_report<'b>(
|
|||
])
|
||||
}
|
||||
|
||||
TooManyUnderscores(_pos) => {
|
||||
alloc.stack([
|
||||
alloc.reflow("This variable's name is using snake case, but has more than one consecutive underscore ('_') characters."),
|
||||
alloc.region(lines.convert_region(surroundings), severity),
|
||||
alloc.concat([
|
||||
alloc.reflow(r"When using snake case, Roc style recommends only using a single underscore consecutively. This will be fixed by the formatter.")
|
||||
]),
|
||||
])
|
||||
}
|
||||
|
||||
BadOpaqueRef(pos) => {
|
||||
use BadIdentNext::*;
|
||||
let kind = "an opaque reference";
|
||||
|
@ -1849,18 +1859,28 @@ fn to_bad_ident_pattern_report<'b>(
|
|||
)
|
||||
}
|
||||
|
||||
TooManyUnderscores(_pos) => {
|
||||
alloc.stack([
|
||||
alloc.reflow("I am trying to parse an identifier here:"),
|
||||
alloc.region(lines.convert_region(surroundings), severity),
|
||||
alloc.concat([
|
||||
alloc.reflow(r"While snake case is allowed here, only a single consecutive underscore should be used.")
|
||||
]),
|
||||
])
|
||||
}
|
||||
|
||||
UnderscoreInMiddle(pos) => {
|
||||
let region = Region::from_pos(pos.sub(1));
|
||||
|
||||
alloc.stack([
|
||||
alloc.reflow("I am trying to parse an identifier here:"),
|
||||
alloc.reflow("I am trying to parse a tag or opaque ref here:"),
|
||||
alloc.region_with_subregion(
|
||||
lines.convert_region(surroundings),
|
||||
lines.convert_region(region),
|
||||
severity,
|
||||
),
|
||||
alloc.concat([alloc.reflow(
|
||||
r"Underscores are not allowed in identifiers. Use camelCase instead!",
|
||||
r"Underscores are not allowed in tags or opaque refs. Use PascalCase instead!",
|
||||
)]),
|
||||
])
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use roc_fmt::annotation::MigrationFlags;
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_parse::ast::Expr;
|
||||
use roc_problem::Severity;
|
||||
|
@ -58,7 +59,7 @@ impl<'a> Renderer<'a> {
|
|||
use roc_fmt::annotation::Formattable;
|
||||
|
||||
let mut buf = roc_fmt::Buf::new_in(self.arena);
|
||||
expr.format(&mut buf, 0);
|
||||
expr.format(&mut buf, &MigrationFlags::new(false), 0);
|
||||
|
||||
self.alloc.vcat([
|
||||
self.alloc
|
||||
|
@ -204,7 +205,7 @@ impl<'a> Renderer<'a> {
|
|||
let mut buf = roc_fmt::Buf::new_in(self.arena);
|
||||
{
|
||||
use roc_fmt::annotation::Formattable;
|
||||
expr.format(&mut buf, 0);
|
||||
expr.format(&mut buf, &MigrationFlags::new(false), 0);
|
||||
}
|
||||
|
||||
writeln!(writer, "{}", buf.as_str())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue