Allow for shorter app headers

This commit is contained in:
Richard Feldman 2020-11-18 23:55:57 -05:00
parent ecfdadb5e3
commit 1868051105
6 changed files with 57 additions and 22 deletions

View file

@ -1,6 +1,4 @@
app "quicksort" app "quicksort" provides [ swap, partition, partitionHelp, quicksort ] to "./platform"
packages { base: "./platform" }
provides [ swap, partition, partitionHelp, quicksort ] to base
quicksort : List (Num a), Int, Int -> List (Num a) quicksort : List (Num a), Int, Int -> List (Num a)
quicksort = \list, low, high -> quicksort = \list, low, high ->

View file

@ -1,4 +1,4 @@
app "quicksort" packages { base: "./platform" } provides [ quicksort ] to base app "quicksort" provides [ quicksort ] to "./platform"
quicksort = \originalList -> quicksort = \originalList ->
quicksortHelp : List (Num a), Int, Int -> List (Num a) quicksortHelp : List (Num a), Int, Int -> List (Num a)

View file

@ -76,13 +76,19 @@ pub struct InterfaceHeader<'a> {
pub after_imports: &'a [CommentOrNewline<'a>], pub after_imports: &'a [CommentOrNewline<'a>],
} }
#[derive(Clone, Debug, PartialEq)]
pub enum To<'a> {
ExistingPackage(&'a str),
NewPackage(PackageOrPath<'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: Vec<'a, Loc<PackageEntry<'a>>>, pub packages: Vec<'a, Loc<PackageEntry<'a>>>,
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>, pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>, pub provides: Vec<'a, Loc<ExposesEntry<'a, &'a str>>>,
pub to: Loc<&'a str>, 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.
pub after_app_keyword: &'a [CommentOrNewline<'a>], pub after_app_keyword: &'a [CommentOrNewline<'a>],
@ -256,7 +262,7 @@ pub fn package_entry<'a>() -> impl Parser<'a, PackageEntry<'a>> {
} }
} }
fn package_or_path<'a>() -> impl Parser<'a, PackageOrPath<'a>> { pub fn package_or_path<'a>() -> impl Parser<'a, PackageOrPath<'a>> {
map!( map!(
either!( either!(
string_literal::parse(), string_literal::parse(),

View file

@ -2,13 +2,14 @@ use crate::ast::{Attempting, CommentOrNewline, Def, Module};
use crate::blankspace::{space0, space0_around, space0_before, space1}; use crate::blankspace::{space0, space0_around, space0_before, space1};
use crate::expr::def; use crate::expr::def;
use crate::header::{ use crate::header::{
package_entry, AppHeader, Effects, ExposesEntry, ImportsEntry, InterfaceHeader, ModuleName, package_entry, package_or_path, AppHeader, Effects, ExposesEntry, ImportsEntry,
PackageEntry, PackageName, PlatformHeader, TypedIdent, InterfaceHeader, ModuleName, PackageEntry, PackageName, PackageOrPath, PlatformHeader, To,
TypedIdent,
}; };
use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident}; use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident};
use crate::parser::{ use crate::parser::{
self, ascii_char, ascii_string, loc, optional, peek_utf8_char, peek_utf8_char_at, unexpected, self, ascii_char, ascii_string, loc, optional, peek_utf8_char, peek_utf8_char_at, unexpected,
unexpected_eof, ParseResult, Parser, State, unexpected_eof, Either, ParseResult, Parser, State,
}; };
use crate::string_literal; use crate::string_literal;
use crate::type_annotation; use crate::type_annotation;
@ -293,7 +294,7 @@ pub fn module_defs<'a>() -> impl Parser<'a, Vec<'a, Located<Def<'a>>>> {
struct ProvidesTo<'a> { struct ProvidesTo<'a> {
entries: Vec<'a, Located<ExposesEntry<'a, &'a str>>>, entries: Vec<'a, Located<ExposesEntry<'a, &'a str>>>,
to: Located<&'a str>, to: Located<To<'a>>,
before_provides_keyword: &'a [CommentOrNewline<'a>], before_provides_keyword: &'a [CommentOrNewline<'a>],
after_provides_keyword: &'a [CommentOrNewline<'a>], after_provides_keyword: &'a [CommentOrNewline<'a>],
@ -316,14 +317,30 @@ fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>> {
), ),
and!( and!(
space1(1), space1(1),
skip_first!(ascii_string("to"), and!(space1(1), loc!(lowercase_ident()))) skip_first!(
ascii_string("to"),
and!(
space1(1),
loc!(either!(lowercase_ident(), package_or_path()))
)
)
) )
) )
), ),
|( |(
(before_provides_keyword, after_provides_keyword), (before_provides_keyword, after_provides_keyword),
(entries, (before_to_keyword, (after_to_keyword, to))), (entries, (before_to_keyword, (after_to_keyword, loc_to))),
)| { )| {
let loc_to: Located<Either<&'a str, PackageOrPath<'a>>> = loc_to;
let to_val = match loc_to.value {
Either::First(pkg) => To::ExistingPackage(pkg),
Either::Second(pkg) => To::NewPackage(pkg),
};
let to = Located {
value: to_val,
region: loc_to.region,
};
ProvidesTo { ProvidesTo {
entries, entries,
to, to,

View file

@ -26,7 +26,9 @@ mod test_parse {
use roc_parse::ast::{ use roc_parse::ast::{
self, Attempting, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch, self, Attempting, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch,
}; };
use roc_parse::header::{AppHeader, InterfaceHeader, ModuleName}; use roc_parse::header::{
AppHeader, ExposesEntry, InterfaceHeader, ModuleName, PackageEntry, PackageOrPath, To,
};
use roc_parse::module::{app_header, interface_header, module_defs}; use roc_parse::module::{app_header, interface_header, module_defs};
use roc_parse::parser::{Fail, FailReason, Parser, State}; use roc_parse::parser::{Fail, FailReason, Parser, State};
use roc_parse::test_helpers::parse_expr_with; use roc_parse::test_helpers::parse_expr_with;
@ -2211,7 +2213,7 @@ mod test_parse {
packages, packages,
imports, imports,
provides, provides,
to: Located::new(0, 0, 53, 57, "blah"), to: Located::new(0, 0, 53, 57, To::ExistingPackage("blah")),
after_app_keyword: &[], after_app_keyword: &[],
before_packages: &[], before_packages: &[],
after_packages: &[], after_packages: &[],
@ -2237,6 +2239,8 @@ mod test_parse {
#[test] #[test]
fn minimal_app_header() { fn minimal_app_header() {
use PackageOrPath::Path;
let arena = Bump::new(); let arena = Bump::new();
let packages = Vec::new_in(&arena); let packages = Vec::new_in(&arena);
let imports = Vec::new_in(&arena); let imports = Vec::new_in(&arena);
@ -2247,7 +2251,7 @@ mod test_parse {
packages, packages,
imports, imports,
provides, provides,
to: Located::new(0, 0, 30, 34, "blah"), to: Located::new(0, 0, 30, 38, To::NewPackage(Path(PlainLine("./blah")))),
after_app_keyword: &[], after_app_keyword: &[],
before_packages: &[], before_packages: &[],
after_packages: &[], after_packages: &[],
@ -2261,7 +2265,7 @@ mod test_parse {
let src = indoc!( let src = indoc!(
r#" r#"
app "test-app" provides [] to blah app "test-app" provides [] to "./blah"
"# "#
); );
let actual = app_header() let actual = app_header()
@ -2273,17 +2277,27 @@ mod test_parse {
#[test] #[test]
fn full_app_header() { fn full_app_header() {
use ExposesEntry::Exposed;
use PackageOrPath::Path;
let pkg_entry = PackageEntry::Entry {
shorthand: "base",
spaces_after_shorthand: &[],
package_or_path: Located::new(0, 0, 33, 45, Path(PlainLine("./platform"))),
};
let loc_pkg_entry = Located::new(0, 0, 27, 45, pkg_entry);
let arena = Bump::new(); let arena = Bump::new();
let packages = Vec::new_in(&arena); let packages = bumpalo::vec![in &arena; loc_pkg_entry];
let imports = Vec::new_in(&arena); let imports = Vec::new_in(&arena);
let provides = Vec::new_in(&arena); let provide_entry = Located::new(0, 0, 59, 68, Exposed("quicksort"));
let module_name = StrLiteral::PlainLine("test-app"); let provides = bumpalo::vec![in &arena; provide_entry];
let module_name = StrLiteral::PlainLine("quicksort");
let expected = AppHeader { let expected = AppHeader {
name: Located::new(0, 0, 4, 14, module_name), name: Located::new(0, 0, 4, 15, module_name),
packages, packages,
imports, imports,
provides, provides,
to: Located::new(0, 0, 30, 34, "blah"), to: Located::new(0, 0, 74, 78, To::ExistingPackage("base")),
after_app_keyword: &[], after_app_keyword: &[],
before_packages: &[], before_packages: &[],
after_packages: &[], after_packages: &[],

View file

@ -1,4 +1,4 @@
app "quicksort" packages { base: "./platform" } provides [ quicksort ] to base app "quicksort" provides [ main ] to "./platform"
quicksort = \originalList -> quicksort = \originalList ->