Skip to content

Commit

Permalink
Merge pull request roc-lang#6708 from roc-lang/module-params-syntax
Browse files Browse the repository at this point in the history
Parse and format module params
  • Loading branch information
ayazhafiz authored May 12, 2024
2 parents 9c653b1 + 058079e commit e5ea6dc
Show file tree
Hide file tree
Showing 46 changed files with 988 additions and 161 deletions.
57 changes: 41 additions & 16 deletions crates/compiler/can/src/desugar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use roc_module::called_via::{BinOp, CalledVia};
use roc_module::ident::ModuleName;
use roc_parse::ast::Expr::{self, *};
use roc_parse::ast::{
AssignedField, Collection, Pattern, RecordBuilderField, StrLiteral, StrSegment, ValueDef,
WhenBranch,
AssignedField, Collection, ModuleImportParams, Pattern, RecordBuilderField, StrLiteral,
StrSegment, ValueDef, WhenBranch,
};
use roc_region::all::{LineInfo, Loc, Region};

Expand Down Expand Up @@ -131,11 +131,26 @@ fn desugar_value_def<'a>(
}
}
ModuleImport(roc_parse::ast::ModuleImport {
before_name: _,
name: _,
alias: _,
exposed: _,
}) => *def,
before_name,
name,
params,
alias,
exposed,
}) => {
let desugared_params =
params.map(|ModuleImportParams { before, params }| ModuleImportParams {
before,
params: desugar_field_collection(arena, params, src, line_info, module_path),
});

ModuleImport(roc_parse::ast::ModuleImport {
before_name,
name: *name,
params: desugared_params,
alias: *alias,
exposed: *exposed,
})
}
IngestedFileImport(_) => *def,

Stmt(stmt_expr) => {
Expand Down Expand Up @@ -383,15 +398,7 @@ pub fn desugar_expr<'a>(
})
}
Record(fields) => {
let mut allocated = Vec::with_capacity_in(fields.len(), arena);
for field in fields.iter() {
let value = desugar_field(arena, &field.value, src, line_info, module_path);
allocated.push(Loc {
value,
region: field.region,
});
}
let fields = fields.replace_items(allocated.into_bump_slice());
let fields = desugar_field_collection(arena, *fields, src, line_info, module_path);
arena.alloc(Loc {
region: loc_expr.region,
value: Record(fields),
Expand Down Expand Up @@ -825,6 +832,24 @@ fn desugar_str_segments<'a>(
.into_bump_slice()
}

fn desugar_field_collection<'a>(
arena: &'a Bump,
fields: Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>,
src: &'a str,
line_info: &mut Option<LineInfo>,
module_path: &str,
) -> Collection<'a, Loc<AssignedField<'a, Expr<'a>>>> {
let mut allocated = Vec::with_capacity_in(fields.len(), arena);

for field in fields.iter() {
let value = desugar_field(arena, &field.value, src, line_info, module_path);

allocated.push(Loc::at(field.region, value));
}

fields.replace_items(allocated.into_bump_slice())
}

fn desugar_field<'a>(
arena: &'a Bump,
field: &'a AssignedField<'a, Expr<'a>>,
Expand Down
50 changes: 31 additions & 19 deletions crates/compiler/fmt/src/def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use crate::spaces::{fmt_default_newline, fmt_default_spaces, fmt_spaces, INDENT}
use crate::Buf;
use roc_parse::ast::{
AbilityMember, Defs, Expr, ExtractSpaces, ImportAlias, ImportAsKeyword, ImportExposingKeyword,
ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport, Pattern, Spaces,
StrLiteral, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport,
ModuleImportParams, Pattern, Spaces, StrLiteral, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
};
use roc_parse::header::Keyword;
use roc_region::all::Loc;
Expand Down Expand Up @@ -192,12 +192,14 @@ impl<'a> Formattable for ModuleImport<'a> {
let Self {
before_name,
name,
params,
alias,
exposed,
} = self;

!before_name.is_empty()
|| name.is_multiline()
|| params.is_multiline()
|| alias.is_multiline()
|| match exposed {
Some(a) => a.keyword.is_multiline() || is_collection_multiline(&a.item),
Expand All @@ -215,39 +217,49 @@ impl<'a> Formattable for ModuleImport<'a> {
let Self {
before_name,
name,
params,
alias,
exposed,
} = self;

buf.indent(indent);
buf.push_str("import");

let indent = indent + INDENT;
let indent = if !before_name.is_empty()
|| (params.is_multiline() && exposed.is_some())
|| alias.is_multiline()
|| exposed.map_or(false, |e| e.keyword.is_multiline())
{
indent + INDENT
} else {
indent
};

fmt_default_spaces(buf, before_name, indent);

buf.indent(indent);
name.format(buf, indent);

if let Some(alias) = alias {
alias.format(buf, indent);
}
params.format(buf, indent);
alias.format(buf, indent);

if let Some(exposed) = exposed {
exposed.keyword.format(buf, indent);
fmt_collection(buf, indent, Braces::Square, exposed.item, Newlines::No);
}
}
}

let list_indent = if !before_name.is_empty()
|| alias.is_multiline()
|| exposed.keyword.is_multiline()
{
indent
} else {
// Align list with import keyword
indent - INDENT
};
impl<'a> Formattable for ModuleImportParams<'a> {
fn is_multiline(&self) -> bool {
let ModuleImportParams { before, params } = self;

fmt_collection(buf, list_indent, Braces::Square, exposed.item, Newlines::No);
}
!before.is_empty() || is_collection_multiline(params)
}

fn format_with_options(&self, buf: &mut Buf, _parens: Parens, newlines: Newlines, indent: u16) {
let ModuleImportParams { before, params } = self;

fmt_default_spaces(buf, before, indent);
fmt_collection(buf, indent, Braces::Curly, *params, newlines);
}
}

Expand Down
28 changes: 22 additions & 6 deletions crates/compiler/fmt/src/module.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::cmp::max;

use crate::annotation::{is_collection_multiline, Formattable, Newlines, Parens};
use crate::collection::{fmt_collection, Braces};
use crate::expr::fmt_str_literal;
Expand Down Expand Up @@ -177,7 +179,20 @@ pub fn fmt_module_header<'a>(buf: &mut Buf, header: &'a ModuleHeader<'a>) {
buf.indent(0);
buf.push_str("module");

let indent = fmt_spaces_with_outdent(buf, header.before_exposes, INDENT);
let mut indent = fmt_spaces_with_outdent(buf, header.after_keyword, 0);

if let Some(params) = &header.params {
if is_collection_multiline(&params.params) {
indent = INDENT;
}

fmt_collection(buf, indent, Braces::Curly, params.params, Newlines::Yes);

indent = fmt_spaces_with_outdent(buf, params.before_arrow, indent);
buf.push_str("->");
indent = fmt_spaces_with_outdent(buf, params.after_arrow, indent);
}

fmt_exposes(buf, header.exposes, indent);
}

Expand All @@ -202,18 +217,19 @@ pub fn fmt_app_header<'a>(buf: &mut Buf, header: &'a AppHeader<'a>) {
buf.indent(0);
buf.push_str("app");

let indent = fmt_spaces_with_outdent(buf, header.before_provides, INDENT);
let indent = fmt_spaces_with_outdent(buf, header.before_provides, 0);
fmt_exposes(buf, header.provides, indent);

let indent = fmt_spaces_with_outdent(buf, header.before_packages, INDENT);
let indent = fmt_spaces_with_outdent(buf, header.before_packages, indent);
fmt_packages(buf, header.packages.value, indent);
}

pub fn fmt_spaces_with_outdent(buf: &mut Buf, spaces: &[CommentOrNewline], indent: u16) -> u16 {
if spaces.iter().all(|c| c.is_newline()) {
buf.spaces(1);
0
indent
} else {
let indent = max(INDENT, indent + INDENT);
fmt_default_spaces(buf, spaces, indent);
indent
}
Expand All @@ -223,10 +239,10 @@ pub fn fmt_package_header<'a>(buf: &mut Buf, header: &'a PackageHeader<'a>) {
buf.indent(0);
buf.push_str("package");

let indent = fmt_spaces_with_outdent(buf, header.before_exposes, INDENT);
let indent = fmt_spaces_with_outdent(buf, header.before_exposes, 0);
fmt_exposes(buf, header.exposes, indent);

let indent = fmt_spaces_with_outdent(buf, header.before_packages, INDENT);
let indent = fmt_spaces_with_outdent(buf, header.before_packages, indent);
fmt_packages(buf, header.packages.value, indent);
}

Expand Down
33 changes: 27 additions & 6 deletions crates/compiler/fmt/src/spaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ use roc_parse::{
AbilityImpls, AbilityMember, AssignedField, Collection, CommentOrNewline, Defs, Expr,
Header, Implements, ImplementsAbilities, ImplementsAbility, ImplementsClause, ImportAlias,
ImportAsKeyword, ImportExposingKeyword, ImportedModuleName, IngestedFileAnnotation,
IngestedFileImport, Module, ModuleImport, Pattern, PatternAs, RecordBuilderField, Spaced,
Spaces, StrLiteral, StrSegment, Tag, TypeAnnotation, TypeDef, TypeHeader, ValueDef,
WhenBranch,
IngestedFileImport, Module, ModuleImport, ModuleImportParams, Pattern, PatternAs,
RecordBuilderField, Spaced, Spaces, StrLiteral, StrSegment, Tag, TypeAnnotation, TypeDef,
TypeHeader, ValueDef, WhenBranch,
},
header::{
AppHeader, ExposedName, HostedHeader, ImportsEntry, KeywordItem, ModuleHeader, ModuleName,
PackageEntry, PackageHeader, PackageName, PlatformHeader, PlatformRequires, ProvidesTo, To,
TypedIdent,
ModuleParams, PackageEntry, PackageHeader, PackageName, PlatformHeader, PlatformRequires,
ProvidesTo, To, TypedIdent,
},
ident::{BadIdent, UppercaseIdent},
};
Expand Down Expand Up @@ -285,7 +285,8 @@ impl<'a> RemoveSpaces<'a> for Module<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self {
let header = match &self.header {
Header::Module(header) => Header::Module(ModuleHeader {
before_exposes: &[],
after_keyword: &[],
params: header.params.remove_spaces(arena),
exposes: header.exposes.remove_spaces(arena),
interface_imports: header.interface_imports.remove_spaces(arena),
}),
Expand Down Expand Up @@ -330,6 +331,16 @@ impl<'a> RemoveSpaces<'a> for Module<'a> {
}
}

impl<'a> RemoveSpaces<'a> for ModuleParams<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self {
ModuleParams {
params: self.params.remove_spaces(arena),
before_arrow: &[],
after_arrow: &[],
}
}
}

impl<'a> RemoveSpaces<'a> for Region {
fn remove_spaces(&self, _arena: &'a Bump) -> Self {
Region::zero()
Expand Down Expand Up @@ -589,12 +600,22 @@ impl<'a> RemoveSpaces<'a> for ModuleImport<'a> {
ModuleImport {
before_name: &[],
name: self.name.remove_spaces(arena),
params: self.params.remove_spaces(arena),
alias: self.alias.remove_spaces(arena),
exposed: self.exposed.remove_spaces(arena),
}
}
}

impl<'a> RemoveSpaces<'a> for ModuleImportParams<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self {
ModuleImportParams {
before: &[],
params: self.params.remove_spaces(arena),
}
}
}

impl<'a> RemoveSpaces<'a> for IngestedFileImport<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self {
IngestedFileImport {
Expand Down
Loading

0 comments on commit e5ea6dc

Please sign in to comment.