mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
New package
header syntax
Implements the new package header syntax as discussed in Zulip [1].
package [Csv] {
parser: "../parser/main.roc"
}
Old headers still parse and are automatically upgraded to the new
syntax by the formatter.
[1] 418444862
This commit is contained in:
parent
8dedd9f03c
commit
e3b600c282
16 changed files with 169 additions and 132 deletions
|
@ -1,3 +1 @@
|
||||||
package "csv"
|
package [Csv] {}
|
||||||
exposes [Csv]
|
|
||||||
packages {}
|
|
||||||
|
|
|
@ -1,3 +1 @@
|
||||||
package "json"
|
package [JsonParser] {}
|
||||||
exposes [JsonParser]
|
|
||||||
packages {}
|
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
package "builtins"
|
package [
|
||||||
exposes [Str, Num, Bool, Result, List, Dict, Set, Decode, Encode, Hash, Box, TotallyNotJson, Inspect]
|
Str,
|
||||||
packages {}
|
Num,
|
||||||
|
Bool,
|
||||||
|
Result,
|
||||||
|
List,
|
||||||
|
Dict,
|
||||||
|
Set,
|
||||||
|
Decode,
|
||||||
|
Encode,
|
||||||
|
Hash,
|
||||||
|
Box,
|
||||||
|
TotallyNotJson,
|
||||||
|
Inspect,
|
||||||
|
] {}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::spaces::RemoveSpaces;
|
||||||
use crate::spaces::{fmt_comments_only, fmt_default_spaces, fmt_spaces, NewlineAt, INDENT};
|
use crate::spaces::{fmt_comments_only, fmt_default_spaces, fmt_spaces, NewlineAt, INDENT};
|
||||||
use crate::Buf;
|
use crate::Buf;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_parse::ast::{Collection, Header, Module, Spaced, Spaces};
|
use roc_parse::ast::{Collection, CommentOrNewline, Header, Module, Spaced, Spaces};
|
||||||
use roc_parse::header::{
|
use roc_parse::header::{
|
||||||
AppHeader, ExposedName, ExposesKeyword, GeneratesKeyword, HostedHeader, ImportsEntry,
|
AppHeader, ExposedName, ExposesKeyword, GeneratesKeyword, HostedHeader, ImportsEntry,
|
||||||
ImportsKeyword, Keyword, KeywordItem, ModuleHeader, ModuleName, PackageEntry, PackageHeader,
|
ImportsKeyword, Keyword, KeywordItem, ModuleHeader, ModuleName, PackageEntry, PackageHeader,
|
||||||
|
@ -177,15 +177,8 @@ pub fn fmt_module_header<'a>(buf: &mut Buf, header: &'a ModuleHeader<'a>) {
|
||||||
buf.indent(0);
|
buf.indent(0);
|
||||||
buf.push_str("module");
|
buf.push_str("module");
|
||||||
|
|
||||||
if header.before_exposes.iter().all(|c| c.is_newline()) {
|
let indent = fmt_spaces_with_outdent(buf, header.before_exposes, INDENT);
|
||||||
buf.spaces(1);
|
|
||||||
fmt_exposes(buf, header.exposes, 0);
|
|
||||||
} else {
|
|
||||||
let indent = INDENT;
|
|
||||||
|
|
||||||
fmt_default_spaces(buf, header.before_exposes, indent);
|
|
||||||
fmt_exposes(buf, header.exposes, indent);
|
fmt_exposes(buf, header.exposes, 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>) {
|
||||||
|
@ -209,37 +202,32 @@ pub fn fmt_app_header<'a>(buf: &mut Buf, header: &'a AppHeader<'a>) {
|
||||||
buf.indent(0);
|
buf.indent(0);
|
||||||
buf.push_str("app");
|
buf.push_str("app");
|
||||||
|
|
||||||
let indent = INDENT;
|
let indent = fmt_spaces_with_outdent(buf, header.before_provides, INDENT);
|
||||||
|
|
||||||
if header.before_provides.iter().all(|c| c.is_newline()) {
|
|
||||||
buf.spaces(1);
|
|
||||||
fmt_exposes(buf, header.provides, 0);
|
|
||||||
} else {
|
|
||||||
fmt_default_spaces(buf, header.before_provides, indent);
|
|
||||||
fmt_exposes(buf, header.provides, indent);
|
fmt_exposes(buf, header.provides, indent);
|
||||||
|
|
||||||
|
let indent = fmt_spaces_with_outdent(buf, header.before_packages, INDENT);
|
||||||
|
fmt_packages(buf, header.packages.value, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if header.before_packages.iter().all(|c| c.is_newline()) {
|
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);
|
buf.spaces(1);
|
||||||
fmt_packages(buf, header.packages.value, 0);
|
0
|
||||||
} else {
|
} else {
|
||||||
fmt_default_spaces(buf, header.before_packages, indent);
|
fmt_default_spaces(buf, spaces, indent);
|
||||||
fmt_packages(buf, header.packages.value, indent);
|
indent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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>) {
|
||||||
buf.indent(0);
|
buf.indent(0);
|
||||||
buf.push_str("package");
|
buf.push_str("package");
|
||||||
let indent = INDENT;
|
|
||||||
fmt_default_spaces(buf, header.before_name, indent);
|
|
||||||
|
|
||||||
fmt_package_name(buf, header.name.value, indent);
|
let indent = fmt_spaces_with_outdent(buf, header.before_exposes, INDENT);
|
||||||
|
fmt_exposes(buf, header.exposes, indent);
|
||||||
|
|
||||||
header.exposes.keyword.format(buf, indent);
|
let indent = fmt_spaces_with_outdent(buf, header.before_packages, INDENT);
|
||||||
fmt_exposes(buf, header.exposes.item, indent);
|
fmt_packages(buf, header.packages.value, indent);
|
||||||
header.packages.keyword.format(buf, indent);
|
|
||||||
fmt_packages(buf, header.packages.item, 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>) {
|
||||||
|
|
|
@ -299,9 +299,9 @@ impl<'a> RemoveSpaces<'a> for Module<'a> {
|
||||||
.remove_spaces(arena),
|
.remove_spaces(arena),
|
||||||
}),
|
}),
|
||||||
Header::Package(header) => Header::Package(PackageHeader {
|
Header::Package(header) => Header::Package(PackageHeader {
|
||||||
before_name: &[],
|
before_exposes: &[],
|
||||||
name: header.name.remove_spaces(arena),
|
|
||||||
exposes: header.exposes.remove_spaces(arena),
|
exposes: header.exposes.remove_spaces(arena),
|
||||||
|
before_packages: &[],
|
||||||
packages: header.packages.remove_spaces(arena),
|
packages: header.packages.remove_spaces(arena),
|
||||||
}),
|
}),
|
||||||
Header::Platform(header) => Header::Platform(PlatformHeader {
|
Header::Platform(header) => Header::Platform(PlatformHeader {
|
||||||
|
|
|
@ -4851,12 +4851,12 @@ fn build_package_header<'a>(
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
) -> Result<(ModuleId, PQModuleName<'a>, ModuleHeader<'a>), LoadingProblem<'a>> {
|
) -> Result<(ModuleId, PQModuleName<'a>, ModuleHeader<'a>), LoadingProblem<'a>> {
|
||||||
let exposes = bumpalo::collections::Vec::from_iter_in(
|
let exposes = bumpalo::collections::Vec::from_iter_in(
|
||||||
unspace(arena, header.exposes.item.items).iter().copied(),
|
unspace(arena, header.exposes.items).iter().copied(),
|
||||||
arena,
|
arena,
|
||||||
);
|
);
|
||||||
let packages = unspace(arena, header.packages.item.items);
|
let packages = unspace(arena, header.packages.value.items);
|
||||||
let exposes_ids = get_exposes_ids(
|
let exposes_ids = get_exposes_ids(
|
||||||
header.exposes.item.items,
|
header.exposes.items,
|
||||||
arena,
|
arena,
|
||||||
&module_ids,
|
&module_ids,
|
||||||
&ident_ids_by_module,
|
&ident_ids_by_module,
|
||||||
|
|
|
@ -294,12 +294,10 @@ pub struct ProvidesTo<'a> {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct PackageHeader<'a> {
|
pub struct PackageHeader<'a> {
|
||||||
pub before_name: &'a [CommentOrNewline<'a>],
|
pub before_exposes: &'a [CommentOrNewline<'a>],
|
||||||
pub name: Loc<PackageName<'a>>,
|
pub exposes: Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>,
|
||||||
|
pub before_packages: &'a [CommentOrNewline<'a>],
|
||||||
pub exposes: KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>>,
|
pub packages: Loc<Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>,
|
||||||
pub packages:
|
|
||||||
KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
|
|
@ -86,7 +86,7 @@ pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
||||||
map!(
|
map!(
|
||||||
skip_first!(
|
skip_first!(
|
||||||
keyword("package", EHeader::Start),
|
keyword("package", EHeader::Start),
|
||||||
increment_min_indent(package_header())
|
increment_min_indent(one_of![package_header(), old_package_header()])
|
||||||
),
|
),
|
||||||
Header::Package
|
Header::Package
|
||||||
),
|
),
|
||||||
|
@ -377,14 +377,57 @@ fn old_app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
fn package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
||||||
record!(PackageHeader {
|
record!(PackageHeader {
|
||||||
before_name: space0_e(EHeader::IndentStart),
|
before_exposes: space0_e(EHeader::IndentStart),
|
||||||
name: loc!(specialize_err(EHeader::PackageName, package_name())),
|
exposes: specialize_err(EHeader::Exposes, exposes_module_collection()),
|
||||||
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
before_packages: space0_e(EHeader::IndentStart),
|
||||||
packages: specialize_err(EHeader::Packages, packages()),
|
packages: specialize_err(EHeader::Packages, loc!(packages_collection())),
|
||||||
})
|
})
|
||||||
.trace("package_header")
|
.trace("package_header")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
struct OldPackageHeader<'a> {
|
||||||
|
before_name: &'a [CommentOrNewline<'a>],
|
||||||
|
exposes: KeywordItem<'a, ExposesKeyword, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>>,
|
||||||
|
packages:
|
||||||
|
Loc<KeywordItem<'a, PackagesKeyword, Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn old_package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
||||||
|
map_with_arena!(
|
||||||
|
record!(OldPackageHeader {
|
||||||
|
before_name: skip_second!(
|
||||||
|
space0_e(EHeader::IndentStart),
|
||||||
|
specialize_err(EHeader::PackageName, package_name())
|
||||||
|
),
|
||||||
|
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
||||||
|
packages: specialize_err(EHeader::Packages, loc!(packages())),
|
||||||
|
}),
|
||||||
|
|arena: &'a bumpalo::Bump, old: OldPackageHeader<'a>| {
|
||||||
|
let before_exposes = merge_n_spaces!(
|
||||||
|
arena,
|
||||||
|
old.before_name,
|
||||||
|
old.exposes.keyword.before,
|
||||||
|
old.exposes.keyword.after
|
||||||
|
);
|
||||||
|
let before_packages = merge_spaces(
|
||||||
|
arena,
|
||||||
|
old.packages.value.keyword.before,
|
||||||
|
old.packages.value.keyword.after,
|
||||||
|
);
|
||||||
|
|
||||||
|
PackageHeader {
|
||||||
|
before_exposes,
|
||||||
|
exposes: old.exposes.item,
|
||||||
|
before_packages,
|
||||||
|
packages: old.packages.map(|kw| kw.item),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.trace("old_package_header")
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
||||||
record!(PlatformHeader {
|
record!(PlatformHeader {
|
||||||
|
@ -638,14 +681,19 @@ fn exposes_modules<'a>() -> impl Parser<
|
||||||
EExposes::IndentExposes,
|
EExposes::IndentExposes,
|
||||||
EExposes::IndentListStart
|
EExposes::IndentListStart
|
||||||
),
|
),
|
||||||
item: collection_trailing_sep_e!(
|
item: exposes_module_collection(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exposes_module_collection<'a>(
|
||||||
|
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, ModuleName<'a>>>>, EExposes> {
|
||||||
|
collection_trailing_sep_e!(
|
||||||
byte(b'[', EExposes::ListStart),
|
byte(b'[', EExposes::ListStart),
|
||||||
exposes_module(EExposes::Identifier),
|
exposes_module(EExposes::Identifier),
|
||||||
byte(b',', EExposes::ListEnd),
|
byte(b',', EExposes::ListEnd),
|
||||||
byte(b']', EExposes::ListEnd),
|
byte(b']', EExposes::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
),
|
)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exposes_module<'a, F, E>(
|
fn exposes_module<'a, F, E>(
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
package "rtfeldman/blah" exposes [] packages {}
|
package [] {}
|
||||||
|
|
|
@ -2,26 +2,10 @@ Module {
|
||||||
comments: [],
|
comments: [],
|
||||||
header: Package(
|
header: Package(
|
||||||
PackageHeader {
|
PackageHeader {
|
||||||
before_name: [],
|
before_exposes: [],
|
||||||
name: @8-24 PackageName(
|
exposes: [],
|
||||||
"rtfeldman/blah",
|
before_packages: [],
|
||||||
),
|
packages: @11-13 [],
|
||||||
exposes: KeywordItem {
|
|
||||||
keyword: Spaces {
|
|
||||||
before: [],
|
|
||||||
item: ExposesKeyword,
|
|
||||||
after: [],
|
|
||||||
},
|
|
||||||
item: [],
|
|
||||||
},
|
|
||||||
packages: KeywordItem {
|
|
||||||
keyword: Spaces {
|
|
||||||
before: [],
|
|
||||||
item: PackagesKeyword,
|
|
||||||
after: [],
|
|
||||||
},
|
|
||||||
item: [],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
package "rtfeldman/blah" exposes [] packages {}
|
package [] {}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
package "foo/barbaz"
|
package [Foo, Bar] {
|
||||||
exposes [Foo, Bar]
|
foo: "./foo",
|
||||||
packages { foo: "./foo" }
|
}
|
||||||
|
|
|
@ -2,46 +2,36 @@ Module {
|
||||||
comments: [],
|
comments: [],
|
||||||
header: Package(
|
header: Package(
|
||||||
PackageHeader {
|
PackageHeader {
|
||||||
before_name: [],
|
before_exposes: [],
|
||||||
name: @8-20 PackageName(
|
exposes: [
|
||||||
"foo/barbaz",
|
@9-12 ModuleName(
|
||||||
),
|
|
||||||
exposes: KeywordItem {
|
|
||||||
keyword: Spaces {
|
|
||||||
before: [
|
|
||||||
Newline,
|
|
||||||
],
|
|
||||||
item: ExposesKeyword,
|
|
||||||
after: [],
|
|
||||||
},
|
|
||||||
item: [
|
|
||||||
@34-37 ModuleName(
|
|
||||||
"Foo",
|
"Foo",
|
||||||
),
|
),
|
||||||
@39-42 ModuleName(
|
@14-17 ModuleName(
|
||||||
"Bar",
|
"Bar",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
},
|
before_packages: [],
|
||||||
packages: KeywordItem {
|
packages: @19-39 [
|
||||||
keyword: Spaces {
|
@25-37 SpaceBefore(
|
||||||
before: [
|
SpaceAfter(
|
||||||
Newline,
|
PackageEntry {
|
||||||
],
|
|
||||||
item: PackagesKeyword,
|
|
||||||
after: [],
|
|
||||||
},
|
|
||||||
item: [
|
|
||||||
@59-71 PackageEntry {
|
|
||||||
shorthand: "foo",
|
shorthand: "foo",
|
||||||
spaces_after_shorthand: [],
|
spaces_after_shorthand: [],
|
||||||
platform_marker: None,
|
platform_marker: None,
|
||||||
package_name: @64-71 PackageName(
|
package_name: @30-37 PackageName(
|
||||||
"./foo",
|
"./foo",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
[
|
||||||
|
Newline,
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
},
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
package "foo/barbaz"
|
package [Foo, Bar] {
|
||||||
exposes [Foo, Bar]
|
foo: "./foo"
|
||||||
packages { foo: "./foo" }
|
}
|
||||||
|
|
|
@ -4840,6 +4840,28 @@ mod test_fmt {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn old_style_package_header_is_upgraded() {
|
||||||
|
module_formats_to(
|
||||||
|
indoc!(
|
||||||
|
"
|
||||||
|
package \"csv\"
|
||||||
|
exposes [Csv]
|
||||||
|
packages {
|
||||||
|
parser: \"parser/main.roc\"
|
||||||
|
}
|
||||||
|
"
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
"
|
||||||
|
package [Csv] {
|
||||||
|
parser: \"parser/main.roc\",
|
||||||
|
}
|
||||||
|
"
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_line_app() {
|
fn single_line_app() {
|
||||||
module_formats_same(indoc!(
|
module_formats_same(indoc!(
|
||||||
|
|
|
@ -244,15 +244,14 @@ impl IterTokens for AppHeader<'_> {
|
||||||
impl IterTokens for PackageHeader<'_> {
|
impl IterTokens for PackageHeader<'_> {
|
||||||
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
||||||
let Self {
|
let Self {
|
||||||
before_name: _,
|
before_exposes: _,
|
||||||
name,
|
|
||||||
exposes,
|
exposes,
|
||||||
|
before_packages: _,
|
||||||
packages,
|
packages,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
(name.iter_tokens(arena).into_iter())
|
(exposes.iter_tokens(arena).into_iter())
|
||||||
.chain(exposes.item.iter_tokens(arena))
|
.chain(packages.value.iter_tokens(arena))
|
||||||
.chain(packages.item.iter_tokens(arena))
|
|
||||||
.collect_in(arena)
|
.collect_in(arena)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue