Extract spacing from parse::header::* items into explicit Spaced enum

This commit is contained in:
Joshua Warner 2021-12-13 17:13:46 -08:00
parent 86c8764012
commit 0786e554c6
11 changed files with 378 additions and 470 deletions

View file

@ -7,11 +7,11 @@ use roc_fmt::module::fmt_module;
use roc_fmt::Buf; use roc_fmt::Buf;
use roc_module::called_via::{BinOp, UnaryOp}; use roc_module::called_via::{BinOp, UnaryOp};
use roc_parse::ast::{ use roc_parse::ast::{
AssignedField, Collection, Expr, Pattern, StrLiteral, StrSegment, Tag, TypeAnnotation, AssignedField, Collection, Expr, Pattern, Spaced, StrLiteral, StrSegment, Tag, TypeAnnotation,
WhenBranch, WhenBranch,
}; };
use roc_parse::header::{ use roc_parse::header::{
AppHeader, Effects, ExposesEntry, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry, AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent, PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent,
}; };
use roc_parse::{ use roc_parse::{
@ -228,16 +228,22 @@ impl<'a> RemoveSpaces<'a> for &'a str {
} }
} }
impl<'a, T: RemoveSpaces<'a> + Copy> RemoveSpaces<'a> for ExposesEntry<'a, T> { impl<'a, T: RemoveSpaces<'a> + Copy> RemoveSpaces<'a> for Spaced<'a, T> {
fn remove_spaces(&self, arena: &'a Bump) -> Self { fn remove_spaces(&self, arena: &'a Bump) -> Self {
match *self { match *self {
ExposesEntry::Exposed(a) => ExposesEntry::Exposed(a.remove_spaces(arena)), Spaced::Item(a) => Spaced::Item(a.remove_spaces(arena)),
ExposesEntry::SpaceBefore(a, _) => a.remove_spaces(arena), Spaced::SpaceBefore(a, _) => a.remove_spaces(arena),
ExposesEntry::SpaceAfter(a, _) => a.remove_spaces(arena), Spaced::SpaceAfter(a, _) => a.remove_spaces(arena),
} }
} }
} }
impl<'a> RemoveSpaces<'a> for ExposedName<'a> {
fn remove_spaces(&self, _arena: &'a Bump) -> Self {
*self
}
}
impl<'a> RemoveSpaces<'a> for ModuleName<'a> { impl<'a> RemoveSpaces<'a> for ModuleName<'a> {
fn remove_spaces(&self, _arena: &'a Bump) -> Self { fn remove_spaces(&self, _arena: &'a Bump) -> Self {
*self *self
@ -261,18 +267,10 @@ impl<'a> RemoveSpaces<'a> for To<'a> {
impl<'a> RemoveSpaces<'a> for TypedIdent<'a> { impl<'a> RemoveSpaces<'a> for TypedIdent<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self { fn remove_spaces(&self, arena: &'a Bump) -> Self {
match *self { TypedIdent {
TypedIdent::Entry { ident: self.ident.remove_spaces(arena),
ident, spaces_before_colon: &[],
spaces_before_colon: _, ann: self.ann.remove_spaces(arena),
ann,
} => TypedIdent::Entry {
ident: ident.remove_spaces(arena),
spaces_before_colon: &[],
ann: ann.remove_spaces(arena),
},
TypedIdent::SpaceBefore(a, _) => a.remove_spaces(arena),
TypedIdent::SpaceAfter(a, _) => a.remove_spaces(arena),
} }
} }
} }
@ -287,29 +285,17 @@ impl<'a> RemoveSpaces<'a> for PlatformRequires<'a> {
} }
impl<'a> RemoveSpaces<'a> for PlatformRigid<'a> { impl<'a> RemoveSpaces<'a> for PlatformRigid<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self { fn remove_spaces(&self, _arena: &'a Bump) -> Self {
match *self { *self
PlatformRigid::Entry { rigid, alias } => PlatformRigid::Entry { rigid, alias },
PlatformRigid::SpaceBefore(a, _) => a.remove_spaces(arena),
PlatformRigid::SpaceAfter(a, _) => a.remove_spaces(arena),
}
} }
} }
impl<'a> RemoveSpaces<'a> for PackageEntry<'a> { impl<'a> RemoveSpaces<'a> for PackageEntry<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self { fn remove_spaces(&self, arena: &'a Bump) -> Self {
match *self { PackageEntry {
PackageEntry::Entry { shorthand: self.shorthand,
shorthand, spaces_after_shorthand: &[],
spaces_after_shorthand: _, package_or_path: self.package_or_path.remove_spaces(arena),
package_or_path,
} => PackageEntry::Entry {
shorthand,
spaces_after_shorthand: &[],
package_or_path: package_or_path.remove_spaces(arena),
},
PackageEntry::SpaceBefore(a, _) => a.remove_spaces(arena),
PackageEntry::SpaceAfter(a, _) => a.remove_spaces(arena),
} }
} }
} }
@ -328,8 +314,6 @@ impl<'a> RemoveSpaces<'a> for ImportsEntry<'a> {
match *self { match *self {
ImportsEntry::Module(a, b) => ImportsEntry::Module(a, b.remove_spaces(arena)), ImportsEntry::Module(a, b) => ImportsEntry::Module(a, b.remove_spaces(arena)),
ImportsEntry::Package(a, b, c) => ImportsEntry::Package(a, b, c.remove_spaces(arena)), ImportsEntry::Package(a, b, c) => ImportsEntry::Package(a, b, c.remove_spaces(arena)),
ImportsEntry::SpaceBefore(a, _) => a.remove_spaces(arena),
ImportsEntry::SpaceAfter(a, _) => a.remove_spaces(arena),
} }
} }
} }

View file

@ -83,7 +83,7 @@ where
} }
/// A Located formattable value is also formattable /// A Located formattable value is also formattable
impl<'a, T> Formattable for Located<T> impl<T> Formattable for Located<T>
where where
T: Formattable, T: Formattable,
{ {

View file

@ -3,9 +3,9 @@ use crate::collection::fmt_collection;
use crate::expr::fmt_str_literal; use crate::expr::fmt_str_literal;
use crate::spaces::{fmt_default_spaces, fmt_spaces, INDENT}; use crate::spaces::{fmt_default_spaces, fmt_spaces, INDENT};
use crate::Buf; use crate::Buf;
use roc_parse::ast::{Collection, Module}; use roc_parse::ast::{Collection, Module, Spaced};
use roc_parse::header::{ use roc_parse::header::{
AppHeader, Effects, ExposesEntry, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry, AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent, PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent,
}; };
use roc_region::all::Located; use roc_region::all::Located;
@ -135,7 +135,7 @@ fn fmt_requires<'a, 'buf>(buf: &mut Buf<'buf>, requires: &PlatformRequires<'a>,
fmt_collection(buf, indent, '{', '}', requires.rigids, Newlines::No); fmt_collection(buf, indent, '{', '}', requires.rigids, Newlines::No);
buf.push_str(" { "); buf.push_str(" { ");
fmt_typed_ident(buf, &requires.signature.value, indent); requires.signature.value.format(buf, indent);
buf.push_str(" }"); buf.push_str(" }");
} }
@ -155,48 +155,17 @@ fn fmt_effects<'a, 'buf>(buf: &mut Buf<'buf>, effects: &Effects<'a>, indent: u16
fmt_collection(buf, indent, '{', '}', effects.entries, Newlines::No) fmt_collection(buf, indent, '{', '}', effects.entries, Newlines::No)
} }
fn fmt_typed_ident<'a, 'buf>(buf: &mut Buf<'buf>, entry: &TypedIdent<'a>, indent: u16) {
use TypedIdent::*;
match entry {
Entry {
ident,
spaces_before_colon,
ann,
} => {
buf.indent(indent);
buf.push_str(ident.value);
fmt_default_spaces(buf, spaces_before_colon, " ", indent);
buf.push_str(": ");
ann.value.format(buf, indent);
}
SpaceBefore(sub_entry, spaces) => {
fmt_spaces(buf, spaces.iter(), indent);
fmt_typed_ident(buf, sub_entry, indent);
}
SpaceAfter(sub_entry, spaces) => {
fmt_typed_ident(buf, sub_entry, indent);
fmt_spaces(buf, spaces.iter(), indent);
}
}
}
impl<'a> Formattable for TypedIdent<'a> { impl<'a> Formattable for TypedIdent<'a> {
fn is_multiline(&self) -> bool { fn is_multiline(&self) -> bool {
false false
} }
fn format<'buf>(&self, buf: &mut Buf<'buf>, indent: u16) { fn format<'buf>(&self, buf: &mut Buf<'buf>, indent: u16) {
fmt_typed_ident(buf, self, indent); buf.indent(indent);
} buf.push_str(self.ident.value);
} fmt_default_spaces(buf, self.spaces_before_colon, " ", indent);
buf.push_str(": ");
impl<'a> Formattable for PlatformRigid<'a> { self.ann.value.format(buf, indent);
fn is_multiline(&self) -> bool {
false
}
fn format<'buf>(&self, buf: &mut Buf<'buf>, indent: u16) {
fmt_platform_rigid(buf, self, indent);
} }
} }
@ -206,30 +175,50 @@ fn fmt_package_name<'buf>(buf: &mut Buf<'buf>, name: PackageName) {
buf.push_str(name.pkg); buf.push_str(name.pkg);
} }
fn fmt_platform_rigid<'a, 'buf>(buf: &mut Buf<'buf>, entry: &PlatformRigid<'a>, indent: u16) { impl<'a, T: Formattable> Formattable for Spaced<'a, T> {
use roc_parse::header::PlatformRigid::*; fn is_multiline(&self) -> bool {
// TODO
false
}
match entry { fn format_with_options<'buf>(
Entry { rigid, alias } => { &self,
buf.push_str(rigid); buf: &mut Buf<'buf>,
buf.push_str("=>"); parens: crate::annotation::Parens,
buf.push_str(alias); newlines: Newlines,
indent: u16,
) {
match self {
Spaced::Item(item) => {
item.format_with_options(buf, parens, newlines, indent);
}
Spaced::SpaceBefore(item, spaces) => {
fmt_spaces(buf, spaces.iter(), indent);
item.format_with_options(buf, parens, newlines, indent);
}
Spaced::SpaceAfter(item, spaces) => {
item.format_with_options(buf, parens, newlines, indent);
fmt_spaces(buf, spaces.iter(), indent);
}
} }
}
}
SpaceBefore(sub_entry, spaces) => { impl<'a> Formattable for PlatformRigid<'a> {
fmt_spaces(buf, spaces.iter(), indent); fn is_multiline(&self) -> bool {
fmt_platform_rigid(buf, sub_entry, indent); false
} }
SpaceAfter(sub_entry, spaces) => {
fmt_platform_rigid(buf, sub_entry, indent); fn format<'buf>(&self, buf: &mut Buf<'buf>, _indent: u16) {
fmt_spaces(buf, spaces.iter(), indent); buf.push_str(self.rigid);
} buf.push_str("=>");
buf.push_str(self.alias);
} }
} }
fn fmt_imports<'a, 'buf>( fn fmt_imports<'a, 'buf>(
buf: &mut Buf<'buf>, buf: &mut Buf<'buf>,
loc_entries: Collection<'a, Located<ImportsEntry<'a>>>, loc_entries: Collection<'a, Located<Spaced<'a, ImportsEntry<'a>>>>,
indent: u16, indent: u16,
) { ) {
fmt_collection(buf, indent, '[', ']', loc_entries, Newlines::No) fmt_collection(buf, indent, '[', ']', loc_entries, Newlines::No)
@ -237,7 +226,7 @@ fn fmt_imports<'a, 'buf>(
fn fmt_provides<'a, 'buf>( fn fmt_provides<'a, 'buf>(
buf: &mut Buf<'buf>, buf: &mut Buf<'buf>,
loc_entries: Collection<'a, Located<ExposesEntry<'a, &'a str>>>, loc_entries: Collection<'a, Located<Spaced<'a, ExposedName<'a>>>>,
indent: u16, indent: u16,
) { ) {
fmt_collection(buf, indent, '[', ']', loc_entries, Newlines::No) fmt_collection(buf, indent, '[', ']', loc_entries, Newlines::No)
@ -252,24 +241,14 @@ fn fmt_to<'buf>(buf: &mut Buf<'buf>, to: To, indent: u16) {
} }
} }
fn fmt_exposes<'a, 'buf, N: FormatName + Copy + 'a>( fn fmt_exposes<'buf, N: Formattable + Copy>(
buf: &mut Buf<'buf>, buf: &mut Buf<'buf>,
loc_entries: Collection<'_, Located<ExposesEntry<'_, N>>>, loc_entries: Collection<'_, Located<Spaced<'_, N>>>,
indent: u16, indent: u16,
) { ) {
fmt_collection(buf, indent, '[', ']', loc_entries, Newlines::No) fmt_collection(buf, indent, '[', ']', loc_entries, Newlines::No)
} }
impl<'a, N: FormatName> Formattable for ExposesEntry<'a, N> {
fn is_multiline(&self) -> bool {
false
}
fn format<'buf>(&self, buf: &mut Buf<'buf>, indent: u16) {
fmt_exposes_entry(buf, self, indent);
}
}
pub trait FormatName { pub trait FormatName {
fn format<'buf>(&self, buf: &mut Buf<'buf>); fn format<'buf>(&self, buf: &mut Buf<'buf>);
} }
@ -286,30 +265,35 @@ impl<'a> FormatName for ModuleName<'a> {
} }
} }
fn fmt_exposes_entry<'a, 'buf, N: FormatName>( impl<'a> Formattable for ModuleName<'a> {
buf: &mut Buf<'buf>, fn is_multiline(&self) -> bool {
entry: &ExposesEntry<'a, N>, false
indent: u16, }
) {
use roc_parse::header::ExposesEntry::*;
match entry { fn format<'buf>(&self, buf: &mut Buf<'buf>, _indent: u16) {
Exposed(ident) => ident.format(buf), buf.push_str(self.as_str());
}
}
SpaceBefore(sub_entry, spaces) => { impl<'a> Formattable for ExposedName<'a> {
fmt_spaces(buf, spaces.iter(), indent); fn is_multiline(&self) -> bool {
fmt_exposes_entry(buf, sub_entry, indent); false
} }
SpaceAfter(sub_entry, spaces) => {
fmt_exposes_entry(buf, sub_entry, indent); fn format<'buf>(&self, buf: &mut Buf<'buf>, _indent: u16) {
fmt_spaces(buf, spaces.iter(), indent); buf.push_str(self.as_str());
} }
}
impl<'a> FormatName for ExposedName<'a> {
fn format<'buf>(&self, buf: &mut Buf<'buf>) {
buf.push_str(self.as_str());
} }
} }
fn fmt_packages<'a, 'buf>( fn fmt_packages<'a, 'buf>(
buf: &mut Buf<'buf>, buf: &mut Buf<'buf>,
loc_entries: Collection<'a, Located<PackageEntry<'a>>>, loc_entries: Collection<'a, Located<Spaced<'a, PackageEntry<'a>>>>,
indent: u16, indent: u16,
) { ) {
fmt_collection(buf, indent, '{', '}', loc_entries, Newlines::No) fmt_collection(buf, indent, '{', '}', loc_entries, Newlines::No)
@ -335,27 +319,10 @@ impl<'a> Formattable for ImportsEntry<'a> {
} }
} }
fn fmt_packages_entry<'a, 'buf>(buf: &mut Buf<'buf>, entry: &PackageEntry<'a>, indent: u16) { fn fmt_packages_entry<'a, 'buf>(buf: &mut Buf<'buf>, entry: &PackageEntry<'a>, indent: u16) {
use PackageEntry::*; buf.push_str(entry.shorthand);
match entry { buf.push(':');
Entry { fmt_default_spaces(buf, entry.spaces_after_shorthand, " ", indent);
shorthand, fmt_package_or_path(buf, &entry.package_or_path.value, indent);
spaces_after_shorthand,
package_or_path,
} => {
buf.push_str(shorthand);
buf.push(':');
fmt_default_spaces(buf, spaces_after_shorthand, " ", indent);
fmt_package_or_path(buf, &package_or_path.value, indent);
}
SpaceBefore(sub_entry, spaces) => {
fmt_spaces(buf, spaces.iter(), indent);
fmt_packages_entry(buf, sub_entry, indent);
}
SpaceAfter(sub_entry, spaces) => {
fmt_packages_entry(buf, sub_entry, indent);
fmt_spaces(buf, spaces.iter(), indent);
}
}
} }
fn fmt_package_or_path<'a, 'buf>( fn fmt_package_or_path<'a, 'buf>(
@ -396,14 +363,5 @@ fn fmt_imports_entry<'a, 'buf>(buf: &mut Buf<'buf>, entry: &ImportsEntry<'a>, in
fmt_collection(buf, indent, '{', '}', *entries, Newlines::No) fmt_collection(buf, indent, '{', '}', *entries, Newlines::No)
} }
} }
SpaceBefore(sub_entry, spaces) => {
fmt_spaces(buf, spaces.iter(), indent);
fmt_imports_entry(buf, sub_entry, indent);
}
SpaceAfter(sub_entry, spaces) => {
fmt_imports_entry(buf, sub_entry, indent);
fmt_spaces(buf, spaces.iter(), indent);
}
} }
} }

View file

@ -23,14 +23,13 @@ use roc_mono::ir::{
UpdateModeIds, UpdateModeIds,
}; };
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem}; use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
use roc_parse::ast::{self, ExtractSpaces, StrLiteral, TypeAnnotation}; use roc_parse::ast::{self, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation};
use roc_parse::header::{ use roc_parse::header::{
ExposesEntry, ImportsEntry, PackageEntry, PackageOrPath, PlatformHeader, To, TypedIdent, ExposedName, ImportsEntry, PackageEntry, PackageOrPath, PlatformHeader, To, TypedIdent,
}; };
use roc_parse::module::module_defs; use roc_parse::module::module_defs;
use roc_parse::parser::{self, ParseProblem, Parser, SyntaxError}; use roc_parse::parser::{self, ParseProblem, Parser, SyntaxError};
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
use roc_reporting::internal_error;
use roc_solve::module::SolvedModule; use roc_solve::module::SolvedModule;
use roc_solve::solve; use roc_solve::solve;
use roc_types::solved_types::Solved; use roc_types::solved_types::Solved;
@ -2603,62 +2602,57 @@ fn parse_header<'a>(
match header.to.value { match header.to.value {
To::ExistingPackage(existing_package) => { To::ExistingPackage(existing_package) => {
let opt_base_package = packages.iter().find(|loc_package_entry| { let opt_base_package = packages.iter().find_map(|loc_package_entry| {
let Located { value, .. } = loc_package_entry; let Located { value, .. } = loc_package_entry;
match value.extract_spaces().item { let item = value.extract_spaces().item;
PackageEntry::Entry { shorthand, .. } => shorthand == existing_package, if item.shorthand == existing_package {
_ => internal_error!(), Some(item)
} else {
None
} }
}); });
match opt_base_package { if let Some(PackageEntry {
Some(Located { shorthand,
value: package_or_path:
PackageEntry::Entry { Located {
shorthand, value: package_or_path,
package_or_path: ..
Located { },
value: package_or_path, ..
.. }) = opt_base_package
}, {
.. match package_or_path {
}, PackageOrPath::Path(StrLiteral::PlainLine(package)) => {
.. // check whether we can find a Package-Config.roc file
}) => { let mut pkg_config_roc = pkg_config_dir;
match package_or_path { pkg_config_roc.push(package);
PackageOrPath::Path(StrLiteral::PlainLine(package)) => { pkg_config_roc.push(PKG_CONFIG_FILE_NAME);
// check whether we can find a Package-Config.roc file pkg_config_roc.set_extension(ROC_FILE_EXTENSION);
let mut pkg_config_roc = pkg_config_dir;
pkg_config_roc.push(package);
pkg_config_roc.push(PKG_CONFIG_FILE_NAME);
pkg_config_roc.set_extension(ROC_FILE_EXTENSION);
if pkg_config_roc.as_path().exists() { if pkg_config_roc.as_path().exists() {
let load_pkg_config_msg = load_pkg_config( let load_pkg_config_msg = load_pkg_config(
arena, arena,
&pkg_config_roc, &pkg_config_roc,
shorthand, shorthand,
module_id, module_id,
module_ids, module_ids,
ident_ids_by_module, ident_ids_by_module,
)?; )?;
Ok(( Ok((
module_id, module_id,
Msg::Many(vec![ Msg::Many(vec![app_module_header_msg, load_pkg_config_msg]),
app_module_header_msg, ))
load_pkg_config_msg, } else {
]), Ok((module_id, app_module_header_msg))
))
} else {
Ok((module_id, app_module_header_msg))
}
} }
_ => unreachable!(),
} }
_ => unreachable!(),
} }
_ => panic!("could not find base"), } else {
panic!("could not find base")
} }
} }
To::NewPackage(package_or_path) => match package_or_path { To::NewPackage(package_or_path) => match package_or_path {
@ -2765,9 +2759,9 @@ struct HeaderInfo<'a> {
is_root_module: bool, is_root_module: bool,
opt_shorthand: Option<&'a str>, opt_shorthand: Option<&'a str>,
header_src: &'a str, header_src: &'a str,
packages: &'a [Located<PackageEntry<'a>>], packages: &'a [Located<Spaced<'a, PackageEntry<'a>>>],
exposes: &'a [Located<ExposesEntry<'a, &'a str>>], exposes: &'a [Located<Spaced<'a, ExposedName<'a>>>],
imports: &'a [Located<ImportsEntry<'a>>], imports: &'a [Located<Spaced<'a, ImportsEntry<'a>>>],
to_platform: Option<To<'a>>, to_platform: Option<To<'a>>,
} }
@ -2900,7 +2894,8 @@ fn send_header<'a>(
// For example, if module A has [ B.{ foo } ], then // For example, if module A has [ B.{ foo } ], then
// when we get here for B, `foo` will already have // when we get here for B, `foo` will already have
// an IdentId. We must reuse that! // an IdentId. We must reuse that!
let ident_id = ident_ids.get_or_insert(&loc_exposed.value.as_str().into()); let ident_id =
ident_ids.get_or_insert(&loc_exposed.value.extract_spaces().item.as_str().into());
let symbol = Symbol::new(home, ident_id); let symbol = Symbol::new(home, ident_id);
exposed.push(symbol); exposed.push(symbol);
@ -2913,24 +2908,13 @@ fn send_header<'a>(
ident_ids.clone() ident_ids.clone()
}; };
let mut parse_entries: Vec<_> = packages.iter().map(|x| &x.value).collect(); let package_entries = packages
let mut package_entries = MutMap::default(); .iter()
.map(|pkg| {
while let Some(parse_entry) = parse_entries.pop() { let pkg = pkg.value.extract_spaces().item;
use PackageEntry::*; (pkg.shorthand, pkg.package_or_path.value)
match parse_entry { })
Entry { .collect::<MutMap<_, _>>();
shorthand,
package_or_path,
..
} => {
package_entries.insert(*shorthand, package_or_path.value);
}
SpaceBefore(inner, _) | SpaceAfter(inner, _) => {
parse_entries.push(inner);
}
}
}
// Send the deps to the coordinator thread for processing, // Send the deps to the coordinator thread for processing,
// then continue on to parsing and canonicalizing defs. // then continue on to parsing and canonicalizing defs.
@ -2989,15 +2973,14 @@ struct PlatformHeaderInfo<'a> {
header_src: &'a str, header_src: &'a str,
app_module_id: ModuleId, app_module_id: ModuleId,
packages: &'a [Located<PackageEntry<'a>>], packages: &'a [Located<PackageEntry<'a>>],
provides: &'a [Located<ExposesEntry<'a, &'a str>>], provides: &'a [Located<Spaced<'a, ExposedName<'a>>>],
requires: &'a [Located<TypedIdent<'a>>], requires: &'a [Located<TypedIdent<'a>>],
imports: &'a [Located<ImportsEntry<'a>>], imports: &'a [Located<Spaced<'a, ImportsEntry<'a>>>],
} }
// TODO refactor so more logic is shared with `send_header` // TODO refactor so more logic is shared with `send_header`
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn send_header_two<'a>( fn send_header_two<'a>(
arena: &'a Bump,
info: PlatformHeaderInfo<'a>, info: PlatformHeaderInfo<'a>,
parse_state: parser::State<'a>, parse_state: parser::State<'a>,
module_ids: Arc<Mutex<PackageModuleIds<'a>>>, module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
@ -3105,15 +3088,17 @@ fn send_header_two<'a>(
.entry(app_module_id) .entry(app_module_id)
.or_insert_with(IdentIds::default); .or_insert_with(IdentIds::default);
for (loc_ident, _) in unpack_exposes_entries(arena, requires) { for entry in requires {
let ident: Ident = loc_ident.value.into(); let entry = entry.value;
let ident: Ident = entry.ident.value.into();
let ident_id = ident_ids.get_or_insert(&ident); let ident_id = ident_ids.get_or_insert(&ident);
let symbol = Symbol::new(app_module_id, ident_id); let symbol = Symbol::new(app_module_id, ident_id);
// Since this value is exposed, add it to our module's default scope. // Since this value is exposed, add it to our module's default scope.
debug_assert!(!scope.contains_key(&ident.clone())); debug_assert!(!scope.contains_key(&ident.clone()));
scope.insert(ident, (symbol, loc_ident.region)); scope.insert(ident, (symbol, entry.ident.region));
} }
} }
@ -3133,7 +3118,8 @@ fn send_header_two<'a>(
// For example, if module A has [ B.{ foo } ], then // For example, if module A has [ B.{ foo } ], then
// when we get here for B, `foo` will already have // when we get here for B, `foo` will already have
// an IdentId. We must reuse that! // an IdentId. We must reuse that!
let ident_id = ident_ids.get_or_insert(&loc_exposed.value.as_str().into()); let ident_id =
ident_ids.get_or_insert(&loc_exposed.value.extract_spaces().item.as_str().into());
let symbol = Symbol::new(home, ident_id); let symbol = Symbol::new(home, ident_id);
exposed.push(symbol); exposed.push(symbol);
@ -3146,24 +3132,10 @@ fn send_header_two<'a>(
ident_ids.clone() ident_ids.clone()
}; };
let mut parse_entries: Vec<_> = packages.iter().map(|x| &x.value).collect(); let package_entries = packages
let mut package_entries = MutMap::default(); .iter()
.map(|pkg| (pkg.value.shorthand, pkg.value.package_or_path.value))
while let Some(parse_entry) = parse_entries.pop() { .collect::<MutMap<_, _>>();
use PackageEntry::*;
match parse_entry {
Entry {
shorthand,
package_or_path,
..
} => {
package_entries.insert(*shorthand, package_or_path.value);
}
SpaceBefore(inner, _) | SpaceAfter(inner, _) => {
parse_entries.push(inner);
}
}
}
// Send the deps to the coordinator thread for processing, // Send the deps to the coordinator thread for processing,
// then continue on to parsing and canonicalizing defs. // then continue on to parsing and canonicalizing defs.
@ -3174,7 +3146,7 @@ fn send_header_two<'a>(
let module_name = ModuleNameEnum::PkgConfig; let module_name = ModuleNameEnum::PkgConfig;
let main_for_host = { let main_for_host = {
let ident_str: Ident = provides[0].value.as_str().into(); let ident_str: Ident = provides[0].value.extract_spaces().item.as_str().into();
let ident_id = ident_ids.get_or_insert(&ident_str); let ident_id = ident_ids.get_or_insert(&ident_str);
Symbol::new(home, ident_id) Symbol::new(home, ident_id)
@ -3355,7 +3327,7 @@ fn fabricate_pkg_config_module<'a>(
header_src: &'a str, header_src: &'a str,
module_timing: ModuleTiming, module_timing: ModuleTiming,
) -> (ModuleId, Msg<'a>) { ) -> (ModuleId, Msg<'a>) {
let provides: &'a [Located<ExposesEntry<'a, &'a str>>] = header.provides.items; let provides: &'a [Located<Spaced<'a, ExposedName<'a>>>] = header.provides.items;
let info = PlatformHeaderInfo { let info = PlatformHeaderInfo {
filename, filename,
@ -3365,12 +3337,14 @@ fn fabricate_pkg_config_module<'a>(
app_module_id, app_module_id,
packages: &[], packages: &[],
provides, provides,
requires: arena.alloc([header.requires.signature]), requires: &*arena.alloc([Located::at(
header.requires.signature.region,
header.requires.signature.extract_spaces().item,
)]),
imports: header.imports.items, imports: header.imports.items,
}; };
send_header_two( send_header_two(
arena,
info, info,
parse_state, parse_state,
module_ids, module_ids,
@ -3413,12 +3387,12 @@ fn fabricate_effects_module<'a>(
let mut module_ids = (*module_ids).lock(); let mut module_ids = (*module_ids).lock();
for exposed in header.exposes.iter() { for exposed in header.exposes.iter() {
if let ExposesEntry::Exposed(module_name) = exposed.value { let module_name = exposed.value.extract_spaces().item;
module_ids.get_or_insert(&PQModuleName::Qualified(
shorthand, module_ids.get_or_insert(&PQModuleName::Qualified(
module_name.as_str().into(), shorthand,
)); module_name.as_str().into(),
} ));
} }
} }
@ -3633,33 +3607,16 @@ fn fabricate_effects_module<'a>(
fn unpack_exposes_entries<'a>( fn unpack_exposes_entries<'a>(
arena: &'a Bump, arena: &'a Bump,
entries: &'a [Located<TypedIdent<'a>>], entries: &'a [Located<Spaced<'a, TypedIdent<'a>>>],
) -> bumpalo::collections::Vec<'a, (&'a Located<&'a str>, &'a Located<TypeAnnotation<'a>>)> { ) -> bumpalo::collections::Vec<'a, (Located<&'a str>, Located<TypeAnnotation<'a>>)> {
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
let mut stack: Vec<&TypedIdent> = Vec::with_capacity_in(entries.len(), arena); let iter = entries.iter().map(|entry| {
let mut output = Vec::with_capacity_in(entries.len(), arena); let entry: TypedIdent<'a> = entry.value.extract_spaces().item;
(entry.ident, entry.ann)
});
for entry in entries.iter() { Vec::from_iter_in(iter, arena)
stack.push(&entry.value);
}
while let Some(effects_entry) = stack.pop() {
match effects_entry {
TypedIdent::Entry {
ident,
spaces_before_colon: _,
ann,
} => {
output.push((ident, ann));
}
TypedIdent::SpaceAfter(nested, _) | TypedIdent::SpaceBefore(nested, _) => {
stack.push(nested);
}
}
}
output
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@ -3816,10 +3773,12 @@ fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, Loadi
Ok(Msg::Parsed(parsed)) Ok(Msg::Parsed(parsed))
} }
fn exposed_from_import<'a>(entry: &ImportsEntry<'a>) -> (QualifiedModuleName<'a>, Vec<Ident>) { fn exposed_from_import<'a>(
entry: &Spaced<'a, ImportsEntry<'a>>,
) -> (QualifiedModuleName<'a>, Vec<Ident>) {
use roc_parse::header::ImportsEntry::*; use roc_parse::header::ImportsEntry::*;
match entry { match entry.extract_spaces().item {
Module(module_name, exposes) => { Module(module_name, exposes) => {
let mut exposed = Vec::with_capacity(exposes.len()); let mut exposed = Vec::with_capacity(exposes.len());
@ -3849,21 +3808,11 @@ fn exposed_from_import<'a>(entry: &ImportsEntry<'a>) -> (QualifiedModuleName<'a>
(qualified_module_name, exposed) (qualified_module_name, exposed)
} }
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => {
// Ignore spaces.
exposed_from_import(*sub_entry)
}
} }
} }
fn ident_from_exposed(entry: &ExposesEntry<'_, &str>) -> Ident { fn ident_from_exposed(entry: &Spaced<'_, ExposedName<'_>>) -> Ident {
use roc_parse::header::ExposesEntry::*; entry.extract_spaces().item.as_str().into()
match entry {
Exposed(ident) => (*ident).into(),
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => ident_from_exposed(sub_entry),
}
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]

View file

@ -1,9 +1,6 @@
use std::fmt::Debug; use std::fmt::Debug;
use crate::header::{ use crate::header::{AppHeader, InterfaceHeader, PlatformHeader};
AppHeader, ExposesEntry, ImportsEntry, InterfaceHeader, PackageEntry, PlatformHeader,
PlatformRigid, TypedIdent,
};
use crate::ident::Ident; use crate::ident::Ident;
use bumpalo::collections::{String, Vec}; use bumpalo::collections::{String, Vec};
use bumpalo::Bump; use bumpalo::Bump;
@ -17,6 +14,33 @@ pub struct Spaces<'a, T> {
pub after: &'a [CommentOrNewline<'a>], pub after: &'a [CommentOrNewline<'a>],
} }
#[derive(Copy, Clone, PartialEq)]
pub enum Spaced<'a, T> {
Item(T),
// Spaces
SpaceBefore(&'a Spaced<'a, T>, &'a [CommentOrNewline<'a>]),
SpaceAfter(&'a Spaced<'a, T>, &'a [CommentOrNewline<'a>]),
}
impl<'a, T: Debug> Debug for Spaced<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Item(item) => item.fmt(f),
Self::SpaceBefore(item, space) => f
.debug_tuple("SpaceBefore")
.field(item)
.field(space)
.finish(),
Self::SpaceAfter(item, space) => f
.debug_tuple("SpaceAfter")
.field(item)
.field(space)
.finish(),
}
}
}
pub trait ExtractSpaces<'a>: Sized + Copy { pub trait ExtractSpaces<'a>: Sized + Copy {
type Item; type Item;
fn extract_spaces(&self) -> Spaces<'a, Self::Item>; fn extract_spaces(&self) -> Spaces<'a, Self::Item>;
@ -674,6 +698,15 @@ pub trait Spaceable<'a> {
} }
} }
impl<'a, T> Spaceable<'a> for Spaced<'a, T> {
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
Spaced::SpaceBefore(self, spaces)
}
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
Spaced::SpaceAfter(self, spaces)
}
}
impl<'a> Spaceable<'a> for Expr<'a> { impl<'a> Spaceable<'a> for Expr<'a> {
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self { fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
Expr::SpaceBefore(self, spaces) Expr::SpaceBefore(self, spaces)
@ -701,24 +734,6 @@ impl<'a> Spaceable<'a> for TypeAnnotation<'a> {
} }
} }
impl<'a> Spaceable<'a> for ImportsEntry<'a> {
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
ImportsEntry::SpaceBefore(self, spaces)
}
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
ImportsEntry::SpaceAfter(self, spaces)
}
}
impl<'a> Spaceable<'a> for TypedIdent<'a> {
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
TypedIdent::SpaceBefore(self, spaces)
}
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
TypedIdent::SpaceAfter(self, spaces)
}
}
impl<'a, Val> Spaceable<'a> for AssignedField<'a, Val> { impl<'a, Val> Spaceable<'a> for AssignedField<'a, Val> {
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self { fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
AssignedField::SpaceBefore(self, spaces) AssignedField::SpaceBefore(self, spaces)
@ -823,8 +838,55 @@ macro_rules! impl_extract_spaces {
impl_extract_spaces!(Expr); impl_extract_spaces!(Expr);
impl_extract_spaces!(Tag); impl_extract_spaces!(Tag);
impl_extract_spaces!(AssignedField<T>); impl_extract_spaces!(AssignedField<T>);
impl_extract_spaces!(PlatformRigid);
impl_extract_spaces!(TypedIdent); impl<'a, T: Copy> ExtractSpaces<'a> for Spaced<'a, T> {
impl_extract_spaces!(ImportsEntry); type Item = T;
impl_extract_spaces!(ExposesEntry<T>);
impl_extract_spaces!(PackageEntry); fn extract_spaces(&self) -> Spaces<'a, T> {
match self {
Spaced::SpaceBefore(item, before) => match item {
Spaced::SpaceBefore(_, _) => todo!(),
Spaced::SpaceAfter(item, after) => {
if let Spaced::Item(item) = item {
Spaces {
before,
item: *item,
after,
}
} else {
todo!();
}
}
Spaced::Item(item) => Spaces {
before,
item: *item,
after: &[],
},
},
Spaced::SpaceAfter(item, after) => match item {
Spaced::SpaceBefore(item, before) => {
if let Spaced::Item(item) = item {
Spaces {
before,
item: *item,
after,
}
} else {
todo!();
}
}
Spaced::SpaceAfter(_, _) => todo!(),
Spaced::Item(item) => Spaces {
before: &[],
item: *item,
after,
},
},
Spaced::Item(item) => Spaces {
before: &[],
item: *item,
after: &[],
},
}
}
}

View file

@ -1,4 +1,4 @@
use crate::ast::{Collection, CommentOrNewline, Spaceable, StrLiteral, TypeAnnotation}; use crate::ast::{Collection, CommentOrNewline, Spaced, StrLiteral, TypeAnnotation};
use crate::blankspace::space0_e; use crate::blankspace::space0_e;
use crate::ident::lowercase_ident; use crate::ident::lowercase_ident;
use crate::parser::Progress::{self, *}; use crate::parser::Progress::{self, *};
@ -57,11 +57,30 @@ impl<'a> ModuleName<'a> {
} }
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct ExposedName<'a>(&'a str);
impl<'a> From<ExposedName<'a>> for &'a str {
fn from(name: ExposedName<'a>) -> Self {
name.0
}
}
impl<'a> ExposedName<'a> {
pub fn new(name: &'a str) -> Self {
ExposedName(name)
}
pub fn as_str(&'a self) -> &'a str {
self.0
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct InterfaceHeader<'a> { pub struct InterfaceHeader<'a> {
pub name: Loc<ModuleName<'a>>, pub name: Loc<ModuleName<'a>>,
pub exposes: Collection<'a, Loc<ExposesEntry<'a, &'a str>>>, pub exposes: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
pub imports: Collection<'a, Loc<ImportsEntry<'a>>>, pub imports: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>,
// Potential comments and newlines - these will typically all be empty. // Potential comments and newlines - these will typically all be empty.
pub before_header: &'a [CommentOrNewline<'a>], pub before_header: &'a [CommentOrNewline<'a>],
@ -81,9 +100,9 @@ pub enum To<'a> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct AppHeader<'a> { pub struct AppHeader<'a> {
pub name: Loc<StrLiteral<'a>>, pub name: Loc<StrLiteral<'a>>,
pub packages: Collection<'a, Loc<PackageEntry<'a>>>, pub packages: Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>,
pub imports: Collection<'a, Loc<ImportsEntry<'a>>>, pub imports: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>,
pub provides: Collection<'a, Loc<ExposesEntry<'a, &'a str>>>, pub provides: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
pub to: Loc<To<'a>>, pub to: Loc<To<'a>>,
// Potential comments and newlines - these will typically all be empty. // Potential comments and newlines - these will typically all be empty.
@ -102,7 +121,7 @@ pub struct AppHeader<'a> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct PackageHeader<'a> { pub struct PackageHeader<'a> {
pub name: Loc<PackageName<'a>>, pub name: Loc<PackageName<'a>>,
pub exposes: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>, pub exposes: Vec<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
pub packages: Vec<'a, (Loc<&'a str>, Loc<PackageOrPath<'a>>)>, pub packages: Vec<'a, (Loc<&'a str>, Loc<PackageOrPath<'a>>)>,
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>, pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
@ -118,37 +137,25 @@ pub struct PackageHeader<'a> {
} }
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum PlatformRigid<'a> { pub struct PlatformRigid<'a> {
Entry { rigid: &'a str, alias: &'a str }, pub rigid: &'a str,
pub alias: &'a str,
// Spaces
SpaceBefore(&'a PlatformRigid<'a>, &'a [CommentOrNewline<'a>]),
SpaceAfter(&'a PlatformRigid<'a>, &'a [CommentOrNewline<'a>]),
}
impl<'a> Spaceable<'a> for PlatformRigid<'a> {
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
PlatformRigid::SpaceBefore(self, spaces)
}
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
PlatformRigid::SpaceAfter(self, spaces)
}
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct PlatformRequires<'a> { pub struct PlatformRequires<'a> {
pub rigids: Collection<'a, Loc<PlatformRigid<'a>>>, pub rigids: Collection<'a, Loc<Spaced<'a, PlatformRigid<'a>>>>,
pub signature: Loc<TypedIdent<'a>>, pub signature: Loc<Spaced<'a, TypedIdent<'a>>>,
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct PlatformHeader<'a> { pub struct PlatformHeader<'a> {
pub name: Loc<PackageName<'a>>, pub name: Loc<PackageName<'a>>,
pub requires: PlatformRequires<'a>, pub requires: PlatformRequires<'a>,
pub exposes: Collection<'a, Loc<ExposesEntry<'a, ModuleName<'a>>>>, pub exposes: Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>,
pub packages: Collection<'a, Loc<PackageEntry<'a>>>, pub packages: Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>,
pub imports: Collection<'a, Loc<ImportsEntry<'a>>>, pub imports: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>,
pub provides: Collection<'a, Loc<ExposesEntry<'a, &'a str>>>, pub provides: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
pub effects: Effects<'a>, pub effects: Effects<'a>,
// Potential comments and newlines - these will typically all be empty. // Potential comments and newlines - these will typically all be empty.
@ -174,26 +181,7 @@ pub struct Effects<'a> {
pub spaces_after_type_name: &'a [CommentOrNewline<'a>], pub spaces_after_type_name: &'a [CommentOrNewline<'a>],
pub effect_shortname: &'a str, pub effect_shortname: &'a str,
pub effect_type_name: &'a str, pub effect_type_name: &'a str,
pub entries: Collection<'a, Loc<TypedIdent<'a>>>, pub entries: Collection<'a, Loc<Spaced<'a, TypedIdent<'a>>>>,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ExposesEntry<'a, T> {
/// e.g. `Task`
Exposed(T),
// Spaces
SpaceBefore(&'a ExposesEntry<'a, T>, &'a [CommentOrNewline<'a>]),
SpaceAfter(&'a ExposesEntry<'a, T>, &'a [CommentOrNewline<'a>]),
}
impl<'a, T> Spaceable<'a> for ExposesEntry<'a, T> {
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
ExposesEntry::SpaceBefore(self, spaces)
}
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
ExposesEntry::SpaceAfter(self, spaces)
}
} }
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
@ -201,71 +189,35 @@ pub enum ImportsEntry<'a> {
/// e.g. `Task` or `Task.{ Task, after }` /// e.g. `Task` or `Task.{ Task, after }`
Module( Module(
ModuleName<'a>, ModuleName<'a>,
Collection<'a, Loc<ExposesEntry<'a, &'a str>>>, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
), ),
/// e.g. `pf.Task` or `pf.Task.{ after }` or `pf.{ Task.{ Task, after } }` /// e.g. `pf.Task` or `pf.Task.{ after }` or `pf.{ Task.{ Task, after } }`
Package( Package(
&'a str, &'a str,
ModuleName<'a>, ModuleName<'a>,
Collection<'a, Loc<ExposesEntry<'a, &'a str>>>, Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
), ),
// Spaces
SpaceBefore(&'a ImportsEntry<'a>, &'a [CommentOrNewline<'a>]),
SpaceAfter(&'a ImportsEntry<'a>, &'a [CommentOrNewline<'a>]),
} }
impl<'a> ExposesEntry<'a, &'a str> { /// e.g.
pub fn as_str(&'a self) -> &'a str { ///
use ExposesEntry::*; /// printLine : Str -> Effect {}
#[derive(Copy, Clone, Debug, PartialEq)]
match self { pub struct TypedIdent<'a> {
Exposed(string) => string, pub ident: Loc<&'a str>,
SpaceBefore(sub_entry, _) | SpaceAfter(sub_entry, _) => sub_entry.as_str(), pub spaces_before_colon: &'a [CommentOrNewline<'a>],
} pub ann: Loc<TypeAnnotation<'a>>,
}
} }
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum TypedIdent<'a> { pub struct PackageEntry<'a> {
/// e.g. pub shorthand: &'a str,
/// pub spaces_after_shorthand: &'a [CommentOrNewline<'a>],
/// printLine : Str -> Effect {} pub package_or_path: Loc<PackageOrPath<'a>>,
Entry {
ident: Loc<&'a str>,
spaces_before_colon: &'a [CommentOrNewline<'a>],
ann: Loc<TypeAnnotation<'a>>,
},
// Spaces
SpaceBefore(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]),
SpaceAfter(&'a TypedIdent<'a>, &'a [CommentOrNewline<'a>]),
} }
#[derive(Copy, Clone, Debug, PartialEq)] pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPackageEntry<'a>> {
pub enum PackageEntry<'a> {
Entry {
shorthand: &'a str,
spaces_after_shorthand: &'a [CommentOrNewline<'a>],
package_or_path: Loc<PackageOrPath<'a>>,
},
// Spaces
SpaceBefore(&'a PackageEntry<'a>, &'a [CommentOrNewline<'a>]),
SpaceAfter(&'a PackageEntry<'a>, &'a [CommentOrNewline<'a>]),
}
impl<'a> Spaceable<'a> for PackageEntry<'a> {
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
PackageEntry::SpaceBefore(self, spaces)
}
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
PackageEntry::SpaceAfter(self, spaces)
}
}
pub fn package_entry<'a>() -> impl Parser<'a, PackageEntry<'a>, EPackageEntry<'a>> {
move |arena, state| { move |arena, state| {
// You may optionally have a package shorthand, // You may optionally have a package shorthand,
// e.g. "uc" in `uc: roc/unicode 1.0.0` // e.g. "uc" in `uc: roc/unicode 1.0.0`
@ -293,19 +245,19 @@ pub fn package_entry<'a>() -> impl Parser<'a, PackageEntry<'a>, EPackageEntry<'a
.parse(arena, state)?; .parse(arena, state)?;
let entry = match opt_shorthand { let entry = match opt_shorthand {
Some((shorthand, spaces_after_shorthand)) => PackageEntry::Entry { Some((shorthand, spaces_after_shorthand)) => PackageEntry {
shorthand, shorthand,
spaces_after_shorthand, spaces_after_shorthand,
package_or_path, package_or_path,
}, },
None => PackageEntry::Entry { None => PackageEntry {
shorthand: "", shorthand: "",
spaces_after_shorthand: &[], spaces_after_shorthand: &[],
package_or_path, package_or_path,
}, },
}; };
Ok((MadeProgress, entry, state)) Ok((MadeProgress, Spaced::Item(entry), state))
} }
} }

View file

@ -1,7 +1,7 @@
use crate::ast::{Collection, CommentOrNewline, Def, Module}; use crate::ast::{Collection, CommentOrNewline, Def, Module, Spaced};
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e}; use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
use crate::header::{ use crate::header::{
package_entry, package_name, package_or_path, AppHeader, Effects, ExposesEntry, ImportsEntry, package_entry, package_name, package_or_path, AppHeader, Effects, ExposedName, ImportsEntry,
InterfaceHeader, ModuleName, PackageEntry, PlatformHeader, PlatformRequires, PlatformRigid, To, InterfaceHeader, ModuleName, PackageEntry, PlatformHeader, PlatformRequires, PlatformRigid, To,
TypedIdent, TypedIdent,
}; };
@ -220,7 +220,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
let opt_imports: Option<( let opt_imports: Option<(
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
Collection<'a, Located<ImportsEntry<'a>>>, Collection<'a, Located<Spaced<'a, ImportsEntry<'a>>>>,
)> = opt_imports; )> = opt_imports;
let ((before_imports, after_imports), imports) = let ((before_imports, after_imports), imports) =
@ -303,7 +303,7 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
#[derive(Debug)] #[derive(Debug)]
struct ProvidesTo<'a> { struct ProvidesTo<'a> {
entries: Collection<'a, Located<ExposesEntry<'a, &'a str>>>, entries: Collection<'a, Located<Spaced<'a, ExposedName<'a>>>>,
to: Located<To<'a>>, to: Located<To<'a>>,
before_provides_keyword: &'a [CommentOrNewline<'a>], before_provides_keyword: &'a [CommentOrNewline<'a>],
@ -362,7 +362,7 @@ fn provides_without_to<'a>() -> impl Parser<
'a, 'a,
( (
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
Collection<'a, Located<ExposesEntry<'a, &'a str>>>, Collection<'a, Located<Spaced<'a, ExposedName<'a>>>>,
), ),
EProvides<'a>, EProvides<'a>,
> { > {
@ -385,14 +385,14 @@ fn provides_without_to<'a>() -> impl Parser<
EProvides::Open, EProvides::Open,
EProvides::Space, EProvides::Space,
EProvides::IndentListEnd, EProvides::IndentListEnd,
ExposesEntry::SpaceBefore Spaced::SpaceBefore
) )
) )
} }
fn exposes_entry<'a, F, E>( fn exposes_entry<'a, F, E>(
to_expectation: F, to_expectation: F,
) -> impl Parser<'a, Located<ExposesEntry<'a, &'a str>>, E> ) -> impl Parser<'a, Located<Spaced<'a, ExposedName<'a>>>, E>
where where
F: Fn(crate::parser::Row, crate::parser::Col) -> E, F: Fn(crate::parser::Row, crate::parser::Col) -> E,
F: Copy, F: Copy,
@ -400,7 +400,7 @@ where
{ {
loc!(map!( loc!(map!(
specialize(|_, r, c| to_expectation(r, c), unqualified_ident()), specialize(|_, r, c| to_expectation(r, c), unqualified_ident()),
ExposesEntry::Exposed |n| Spaced::Item(ExposedName::new(n))
)) ))
} }
@ -444,7 +444,7 @@ fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a
#[inline(always)] #[inline(always)]
fn requires_rigids<'a>( fn requires_rigids<'a>(
min_indent: u16, min_indent: u16,
) -> impl Parser<'a, Collection<'a, Located<PlatformRigid<'a>>>, ERequires<'a>> { ) -> impl Parser<'a, Collection<'a, Located<Spaced<'a, PlatformRigid<'a>>>>, ERequires<'a>> {
collection_trailing_sep_e!( collection_trailing_sep_e!(
word1(b'{', ERequires::ListStart), word1(b'{', ERequires::ListStart),
specialize(|_, r, c| ERequires::Rigid(r, c), loc!(requires_rigid())), specialize(|_, r, c| ERequires::Rigid(r, c), loc!(requires_rigid())),
@ -454,23 +454,24 @@ fn requires_rigids<'a>(
ERequires::Open, ERequires::Open,
ERequires::Space, ERequires::Space,
ERequires::IndentListEnd, ERequires::IndentListEnd,
PlatformRigid::SpaceBefore Spaced::SpaceBefore
) )
} }
#[inline(always)] #[inline(always)]
fn requires_rigid<'a>() -> impl Parser<'a, PlatformRigid<'a>, ()> { fn requires_rigid<'a>() -> impl Parser<'a, Spaced<'a, PlatformRigid<'a>>, ()> {
map!( map!(
and!( and!(
lowercase_ident(), lowercase_ident(),
skip_first!(word2(b'=', b'>', |_, _| ()), uppercase_ident()) skip_first!(word2(b'=', b'>', |_, _| ()), uppercase_ident())
), ),
|(rigid, alias)| PlatformRigid::Entry { rigid, alias } |(rigid, alias)| Spaced::Item(PlatformRigid { rigid, alias })
) )
} }
#[inline(always)] #[inline(always)]
fn requires_typed_ident<'a>() -> impl Parser<'a, Located<TypedIdent<'a>>, ERequires<'a>> { fn requires_typed_ident<'a>() -> impl Parser<'a, Located<Spaced<'a, TypedIdent<'a>>>, ERequires<'a>>
{
skip_first!( skip_first!(
word1(b'{', ERequires::ListStart), word1(b'{', ERequires::ListStart),
skip_second!( skip_second!(
@ -491,7 +492,7 @@ fn exposes_values<'a>() -> impl Parser<
'a, 'a,
( (
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
Collection<'a, Located<ExposesEntry<'a, &'a str>>>, Collection<'a, Located<Spaced<'a, ExposedName<'a>>>>,
), ),
EExposes, EExposes,
> { > {
@ -515,7 +516,7 @@ fn exposes_values<'a>() -> impl Parser<
EExposes::Open, EExposes::Open,
EExposes::Space, EExposes::Space,
EExposes::IndentListEnd, EExposes::IndentListEnd,
ExposesEntry::SpaceBefore Spaced::SpaceBefore
) )
) )
} }
@ -545,7 +546,7 @@ fn exposes_modules<'a>() -> impl Parser<
'a, 'a,
( (
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
Collection<'a, Located<ExposesEntry<'a, ModuleName<'a>>>>, Collection<'a, Located<Spaced<'a, ModuleName<'a>>>>,
), ),
EExposes, EExposes,
> { > {
@ -569,14 +570,14 @@ fn exposes_modules<'a>() -> impl Parser<
EExposes::Open, EExposes::Open,
EExposes::Space, EExposes::Space,
EExposes::IndentListEnd, EExposes::IndentListEnd,
ExposesEntry::SpaceBefore Spaced::SpaceBefore
) )
) )
} }
fn exposes_module<'a, F, E>( fn exposes_module<'a, F, E>(
to_expectation: F, to_expectation: F,
) -> impl Parser<'a, Located<ExposesEntry<'a, ModuleName<'a>>>, E> ) -> impl Parser<'a, Located<Spaced<'a, ModuleName<'a>>>, E>
where where
F: Fn(crate::parser::Row, crate::parser::Col) -> E, F: Fn(crate::parser::Row, crate::parser::Col) -> E,
F: Copy, F: Copy,
@ -584,13 +585,13 @@ where
{ {
loc!(map!( loc!(map!(
specialize(|_, r, c| to_expectation(r, c), module_name()), specialize(|_, r, c| to_expectation(r, c), module_name()),
ExposesEntry::Exposed Spaced::Item
)) ))
} }
#[derive(Debug)] #[derive(Debug)]
struct Packages<'a> { struct Packages<'a> {
entries: Collection<'a, Located<PackageEntry<'a>>>, entries: Collection<'a, Located<Spaced<'a, PackageEntry<'a>>>>,
before_packages_keyword: &'a [CommentOrNewline<'a>], before_packages_keyword: &'a [CommentOrNewline<'a>],
after_packages_keyword: &'a [CommentOrNewline<'a>], after_packages_keyword: &'a [CommentOrNewline<'a>],
} }
@ -618,7 +619,7 @@ fn packages<'a>() -> impl Parser<'a, Packages<'a>, EPackages<'a>> {
EPackages::Open, EPackages::Open,
EPackages::Space, EPackages::Space,
EPackages::IndentListEnd, EPackages::IndentListEnd,
PackageEntry::SpaceBefore Spaced::SpaceBefore
) )
), ),
|((before_packages_keyword, after_packages_keyword), entries): ( |((before_packages_keyword, after_packages_keyword), entries): (
@ -639,7 +640,7 @@ fn imports<'a>() -> impl Parser<
'a, 'a,
( (
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]), (&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
Collection<'a, Located<ImportsEntry<'a>>>, Collection<'a, Located<Spaced<'a, ImportsEntry<'a>>>>,
), ),
EImports, EImports,
> { > {
@ -663,7 +664,7 @@ fn imports<'a>() -> impl Parser<
EImports::Open, EImports::Open,
EImports::Space, EImports::Space,
EImports::IndentListEnd, EImports::IndentListEnd,
ImportsEntry::SpaceBefore Spaced::SpaceBefore
) )
) )
} }
@ -706,7 +707,7 @@ fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> {
EEffects::Open, EEffects::Open,
EEffects::Space, EEffects::Space,
EEffects::IndentListEnd, EEffects::IndentListEnd,
TypedIdent::SpaceBefore Spaced::SpaceBefore
) )
.parse(arena, state)?; .parse(arena, state)?;
@ -726,7 +727,7 @@ fn effects<'a>() -> impl Parser<'a, Effects<'a>, EEffects<'a>> {
} }
#[inline(always)] #[inline(always)]
fn typed_ident<'a>() -> impl Parser<'a, TypedIdent<'a>, ETypedIdent<'a>> { fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<'a>> {
// e.g. // e.g.
// //
// printLine : Str -> Effect {} // printLine : Str -> Effect {}
@ -752,11 +753,11 @@ fn typed_ident<'a>() -> impl Parser<'a, TypedIdent<'a>, ETypedIdent<'a>> {
) )
), ),
|((ident, spaces_before_colon), ann)| { |((ident, spaces_before_colon), ann)| {
TypedIdent::Entry { Spaced::Item(TypedIdent {
ident, ident,
spaces_before_colon, spaces_before_colon,
ann, ann,
} })
} }
) )
} }
@ -775,12 +776,12 @@ where
} }
#[inline(always)] #[inline(always)]
fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>, EImports> { fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports> {
let min_indent = 1; let min_indent = 1;
type Temp<'a> = ( type Temp<'a> = (
(Option<&'a str>, ModuleName<'a>), (Option<&'a str>, ModuleName<'a>),
Option<Collection<'a, Located<ExposesEntry<'a, &'a str>>>>, Option<Collection<'a, Located<Spaced<'a, ExposedName<'a>>>>>,
); );
map_with_arena!( map_with_arena!(
@ -806,18 +807,20 @@ fn imports_entry<'a>() -> impl Parser<'a, ImportsEntry<'a>, EImports> {
EImports::Open, EImports::Open,
EImports::Space, EImports::Space,
EImports::IndentSetEnd, EImports::IndentSetEnd,
ExposesEntry::SpaceBefore Spaced::SpaceBefore
) )
)) ))
), ),
|_arena, ((opt_shortname, module_name), opt_values): Temp<'a>| { |_arena, ((opt_shortname, module_name), opt_values): Temp<'a>| {
let exposed_values = opt_values.unwrap_or_else(Collection::empty); let exposed_values = opt_values.unwrap_or_else(Collection::empty);
match opt_shortname { let entry = match opt_shortname {
Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values), Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values),
None => ImportsEntry::Module(module_name, exposed_values), None => ImportsEntry::Module(module_name, exposed_values),
} };
Spaced::Item(entry)
} }
) )
} }

View file

@ -6,7 +6,7 @@ Platform {
}, },
requires: PlatformRequires { requires: PlatformRequires {
rigids: [], rigids: [],
signature: |L 0-0, C 38-47| Entry { signature: |L 0-0, C 38-47| TypedIdent {
ident: |L 0-0, C 38-42| "main", ident: |L 0-0, C 38-42| "main",
spaces_before_colon: [], spaces_before_colon: [],
ann: |L 0-0, C 45-47| Record { ann: |L 0-0, C 45-47| Record {

View file

@ -4,7 +4,7 @@ App {
"quicksort", "quicksort",
), ),
packages: [ packages: [
|L 1-1, C 15-31| Entry { |L 1-1, C 15-31| PackageEntry {
shorthand: "pf", shorthand: "pf",
spaces_after_shorthand: [], spaces_after_shorthand: [],
package_or_path: |L 1-1, C 19-31| Path( package_or_path: |L 1-1, C 19-31| Path(
@ -24,7 +24,7 @@ App {
), ),
], ],
provides: [ provides: [
|L 3-3, C 15-24| Exposed( |L 3-3, C 15-24| ExposedName(
"quicksort", "quicksort",
), ),
], ],

View file

@ -4,7 +4,7 @@ App {
"quicksort", "quicksort",
), ),
packages: [ packages: [
|L 1-1, C 15-31| Entry { |L 1-1, C 15-31| PackageEntry {
shorthand: "pf", shorthand: "pf",
spaces_after_shorthand: [], spaces_after_shorthand: [],
package_or_path: |L 1-1, C 19-31| Path( package_or_path: |L 1-1, C 19-31| Path(
@ -23,7 +23,7 @@ App {
Collection { Collection {
items: [ items: [
|L 3-3, C 8-11| SpaceBefore( |L 3-3, C 8-11| SpaceBefore(
Exposed( ExposedName(
"Baz", "Baz",
), ),
[ [
@ -31,7 +31,7 @@ App {
], ],
), ),
|L 4-4, C 8-16| SpaceBefore( |L 4-4, C 8-16| SpaceBefore(
Exposed( ExposedName(
"FortyTwo", "FortyTwo",
), ),
[ [
@ -49,7 +49,7 @@ App {
), ),
], ],
provides: [ provides: [
|L 7-7, C 15-24| Exposed( |L 7-7, C 15-24| ExposedName(
"quicksort", "quicksort",
), ),
], ],

View file

@ -6,12 +6,12 @@ Platform {
}, },
requires: PlatformRequires { requires: PlatformRequires {
rigids: [ rigids: [
|L 1-1, C 14-26| Entry { |L 1-1, C 14-26| PlatformRigid {
rigid: "model", rigid: "model",
alias: "Model", alias: "Model",
}, },
], ],
signature: |L 1-1, C 30-39| Entry { signature: |L 1-1, C 30-39| TypedIdent {
ident: |L 1-1, C 30-34| "main", ident: |L 1-1, C 30-34| "main",
spaces_before_colon: [], spaces_before_colon: [],
ann: |L 1-1, C 37-39| Record { ann: |L 1-1, C 37-39| Record {
@ -22,7 +22,7 @@ Platform {
}, },
exposes: [], exposes: [],
packages: [ packages: [
|L 3-3, C 15-27| Entry { |L 3-3, C 15-27| PackageEntry {
shorthand: "foo", shorthand: "foo",
spaces_after_shorthand: [], spaces_after_shorthand: [],
package_or_path: |L 3-3, C 20-27| Path( package_or_path: |L 3-3, C 20-27| Path(
@ -34,7 +34,7 @@ Platform {
], ],
imports: [], imports: [],
provides: [ provides: [
|L 5-5, C 15-26| Exposed( |L 5-5, C 15-26| ExposedName(
"mainForHost", "mainForHost",
), ),
], ],