Switch to always encoding package names / paths as strings

This will simplify parsing and make it possible to have a uniform lexer for the language. Previously unquoted package names were allowed to include '-'s, which aren't valid identifiers.

In the future, we'll distinguish local paths from packages in the package-manager by looking for a ".roc" suffix, which should only be present in local paths.
This commit is contained in:
Joshua Warner 2021-12-20 18:23:41 -08:00
parent f680b83b9e
commit 8b58d5cbc7
31 changed files with 120 additions and 293 deletions

View file

@ -12,7 +12,7 @@ use roc_parse::ast::{
}; };
use roc_parse::header::{ use roc_parse::header::{
AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry, AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent, PackageName, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent,
}; };
use roc_parse::{ use roc_parse::{
ast::{Def, Module}, ast::{Def, Module},
@ -296,16 +296,7 @@ impl<'a> RemoveSpaces<'a> for PackageEntry<'a> {
PackageEntry { PackageEntry {
shorthand: self.shorthand, shorthand: self.shorthand,
spaces_after_shorthand: &[], spaces_after_shorthand: &[],
package_or_path: self.package_or_path.remove_spaces(arena), package_name: self.package_name.remove_spaces(arena),
}
}
}
impl<'a> RemoveSpaces<'a> for PackageOrPath<'a> {
fn remove_spaces(&self, arena: &'a Bump) -> Self {
match *self {
PackageOrPath::Package(a, b) => PackageOrPath::Package(a, b),
PackageOrPath::Path(p) => PackageOrPath::Path(p.remove_spaces(arena)),
} }
} }
} }

View file

@ -1,4 +1,4 @@
platform examples/multi-module platform "examples/multi-module"
requires {}{ main : Str } requires {}{ main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/multi-dep-thunk platform "examples/multi-dep-thunk"
requires {}{ main : Str } requires {}{ main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -6,7 +6,7 @@ use crate::Buf;
use roc_parse::ast::{Collection, Module, Spaced}; use roc_parse::ast::{Collection, Module, Spaced};
use roc_parse::header::{ use roc_parse::header::{
AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry, AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent, PackageName, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent,
}; };
use roc_region::all::Loc; use roc_region::all::Loc;
@ -91,7 +91,7 @@ pub fn fmt_platform_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a PlatformHe
buf.push_str("platform"); buf.push_str("platform");
fmt_default_spaces(buf, header.after_platform_keyword, indent); fmt_default_spaces(buf, header.after_platform_keyword, indent);
fmt_package_name(buf, header.name.value); fmt_package_name(buf, header.name.value, indent);
// requires // requires
fmt_default_spaces(buf, header.before_requires, indent); fmt_default_spaces(buf, header.before_requires, indent);
@ -171,10 +171,10 @@ impl<'a> Formattable for TypedIdent<'a> {
} }
} }
fn fmt_package_name<'buf>(buf: &mut Buf<'buf>, name: PackageName) { fn fmt_package_name<'buf>(buf: &mut Buf<'buf>, name: PackageName, _indent: u16) {
buf.push_str(name.account); buf.push('"');
buf.push('/'); buf.push_str_allow_spaces(name.0);
buf.push_str(name.pkg); buf.push('"');
} }
impl<'a, T: Formattable> Formattable for Spaced<'a, T> { impl<'a, T: Formattable> Formattable for Spaced<'a, T> {
@ -239,7 +239,7 @@ fn fmt_to<'buf>(buf: &mut Buf<'buf>, to: To, indent: u16) {
To::ExistingPackage(name) => { To::ExistingPackage(name) => {
buf.push_str(name); buf.push_str(name);
} }
To::NewPackage(package_or_path) => fmt_package_or_path(buf, &package_or_path, indent), To::NewPackage(package_name) => fmt_package_name(buf, package_name, indent),
} }
} }
@ -324,20 +324,7 @@ fn fmt_packages_entry<'a, 'buf>(buf: &mut Buf<'buf>, entry: &PackageEntry<'a>, i
buf.push_str(entry.shorthand); buf.push_str(entry.shorthand);
buf.push(':'); buf.push(':');
fmt_default_spaces(buf, entry.spaces_after_shorthand, indent); fmt_default_spaces(buf, entry.spaces_after_shorthand, indent);
fmt_package_or_path(buf, &entry.package_or_path.value, indent); fmt_package_name(buf, entry.package_name.value, indent);
}
fn fmt_package_or_path<'a, 'buf>(
buf: &mut Buf<'buf>,
package_or_path: &PackageOrPath<'a>,
indent: u16,
) {
match package_or_path {
PackageOrPath::Package(_name, _version) => {
todo!("format package");
}
PackageOrPath::Path(str_literal) => fmt_str_literal(buf, *str_literal, indent),
}
} }
fn fmt_imports_entry<'a, 'buf>(buf: &mut Buf<'buf>, entry: &ImportsEntry<'a>, indent: u16) { fn fmt_imports_entry<'a, 'buf>(buf: &mut Buf<'buf>, entry: &ImportsEntry<'a>, indent: u16) {

View file

@ -2651,7 +2651,7 @@ mod test_fmt {
#[test] #[test]
fn single_line_platform() { fn single_line_platform() {
module_formats_same( module_formats_same(
"platform folkertdev/foo \ "platform \"folkertdev/foo\" \
requires { model=>Model, msg=>Msg } { main : Effect {} } \ requires { model=>Model, msg=>Msg } { main : Effect {} } \
exposes [] \ exposes [] \
packages {} \ packages {} \

View file

@ -24,9 +24,8 @@ use roc_mono::ir::{
}; };
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem}; use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
use roc_parse::ast::{self, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation}; use roc_parse::ast::{self, ExtractSpaces, Spaced, StrLiteral, TypeAnnotation};
use roc_parse::header::{ use roc_parse::header::PackageName;
ExposedName, ImportsEntry, PackageEntry, PackageOrPath, PlatformHeader, To, TypedIdent, use roc_parse::header::{ExposedName, ImportsEntry, PackageEntry, PlatformHeader, To, TypedIdent};
};
use roc_parse::module::module_defs; use roc_parse::module::module_defs;
use roc_parse::parser::{ParseProblem, Parser, SyntaxError}; use roc_parse::parser::{ParseProblem, Parser, SyntaxError};
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
@ -668,7 +667,7 @@ struct ModuleHeader<'a> {
is_root_module: bool, is_root_module: bool,
exposed_ident_ids: IdentIds, exposed_ident_ids: IdentIds,
deps_by_name: MutMap<PQModuleName<'a>, ModuleId>, deps_by_name: MutMap<PQModuleName<'a>, ModuleId>,
packages: MutMap<&'a str, PackageOrPath<'a>>, packages: MutMap<&'a str, PackageName<'a>>,
imported_modules: MutMap<ModuleId, Region>, imported_modules: MutMap<ModuleId, Region>,
package_qualified_imported_modules: MutSet<PackageQualified<'a, ModuleId>>, package_qualified_imported_modules: MutSet<PackageQualified<'a, ModuleId>>,
exposes: Vec<Symbol>, exposes: Vec<Symbol>,
@ -887,7 +886,7 @@ struct State<'a> {
/// From now on, these will be used by multiple threads; time to make an Arc<Mutex<_>>! /// From now on, these will be used by multiple threads; time to make an Arc<Mutex<_>>!
pub arc_modules: Arc<Mutex<PackageModuleIds<'a>>>, pub arc_modules: Arc<Mutex<PackageModuleIds<'a>>>,
pub arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageOrPath<'a>>>>, pub arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
pub ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>, pub ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
@ -980,7 +979,7 @@ enum BuildTask<'a> {
LoadModule { LoadModule {
module_name: PQModuleName<'a>, module_name: PQModuleName<'a>,
module_ids: Arc<Mutex<PackageModuleIds<'a>>>, module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
shorthands: Arc<Mutex<MutMap<&'a str, PackageOrPath<'a>>>>, shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>, ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
}, },
Parse { Parse {
@ -1680,8 +1679,8 @@ fn update<'a>(
{ {
let mut shorthands = (*state.arc_shorthands).lock(); let mut shorthands = (*state.arc_shorthands).lock();
for (shorthand, package_or_path) in header.packages.iter() { for (shorthand, package_name) in header.packages.iter() {
shorthands.insert(shorthand, *package_or_path); shorthands.insert(shorthand, *package_name);
} }
if let PkgConfig { if let PkgConfig {
@ -2215,7 +2214,7 @@ fn finish_specialization(
let path_to_platform = { let path_to_platform = {
use PlatformPath::*; use PlatformPath::*;
let package_or_path = match platform_path { let package_name = match platform_path {
Valid(To::ExistingPackage(shorthand)) => { Valid(To::ExistingPackage(shorthand)) => {
match (*state.arc_shorthands).lock().get(shorthand) { match (*state.arc_shorthands).lock().get(shorthand) {
Some(p_or_p) => *p_or_p, Some(p_or_p) => *p_or_p,
@ -2229,11 +2228,7 @@ fn finish_specialization(
} }
}; };
match package_or_path { package_name.0
PackageOrPath::Path(StrLiteral::PlainLine(path)) => path,
PackageOrPath::Path(_) => unreachable!("invalid"),
_ => todo!("packages"),
}
}; };
let platform_path = path_to_platform.into(); let platform_path = path_to_platform.into();
@ -2434,7 +2429,7 @@ fn load_module<'a>(
src_dir: &Path, src_dir: &Path,
module_name: PQModuleName<'a>, module_name: PQModuleName<'a>,
module_ids: Arc<Mutex<PackageModuleIds<'a>>>, module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageOrPath<'a>>>>, arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>, ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> { ) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
let module_start_time = SystemTime::now(); let module_start_time = SystemTime::now();
@ -2456,13 +2451,9 @@ fn load_module<'a>(
let shorthands = arc_shorthands.lock(); let shorthands = arc_shorthands.lock();
match shorthands.get(shorthand) { match shorthands.get(shorthand) {
Some(PackageOrPath::Path(StrLiteral::PlainLine(path))) => { Some(PackageName(path)) => {
filename.push(path); filename.push(path);
} }
Some(PackageOrPath::Path(_str_liteal)) => {
unreachable!("invalid structure for path")
}
Some(PackageOrPath::Package(_name, _version)) => todo!("packages"),
None => unreachable!("there is no shorthand named {:?}", shorthand), None => unreachable!("there is no shorthand named {:?}", shorthand),
} }
@ -2614,16 +2605,16 @@ fn parse_header<'a>(
if let Some(PackageEntry { if let Some(PackageEntry {
shorthand, shorthand,
package_or_path: package_name:
Loc { Loc {
value: package_or_path, value: package_name,
.. ..
}, },
.. ..
}) = opt_base_package }) = opt_base_package
{ {
match package_or_path { let package = package_name.0;
PackageOrPath::Path(StrLiteral::PlainLine(package)) => {
// check whether we can find a Package-Config.roc file // check whether we can find a Package-Config.roc file
let mut pkg_config_roc = pkg_config_dir; let mut pkg_config_roc = pkg_config_dir;
pkg_config_roc.push(package); pkg_config_roc.push(package);
@ -2647,25 +2638,11 @@ fn parse_header<'a>(
} else { } else {
Ok((module_id, app_module_header_msg)) Ok((module_id, app_module_header_msg))
} }
}
_ => unreachable!(),
}
} else { } else {
panic!("could not find base") panic!("could not find base")
} }
} }
To::NewPackage(package_or_path) => match package_or_path { To::NewPackage(_package_name) => Ok((module_id, app_module_header_msg)),
PackageOrPath::Package(_, _) => panic!("TODO implement packages"),
PackageOrPath::Path(StrLiteral::PlainLine(_package)) => {
Ok((module_id, app_module_header_msg))
}
PackageOrPath::Path(StrLiteral::Block(_)) => {
panic!("TODO implement block package path")
}
PackageOrPath::Path(StrLiteral::Line(_)) => {
panic!("TODO implement line package path")
}
},
} }
} }
Ok((ast::Module::Platform { header }, _parse_state)) => Ok(fabricate_effects_module( Ok((ast::Module::Platform { header }, _parse_state)) => Ok(fabricate_effects_module(
@ -2910,7 +2887,7 @@ fn send_header<'a>(
.iter() .iter()
.map(|pkg| { .map(|pkg| {
let pkg = pkg.value; let pkg = pkg.value;
(pkg.shorthand, pkg.package_or_path.value) (pkg.shorthand, pkg.package_name.value)
}) })
.collect::<MutMap<_, _>>(); .collect::<MutMap<_, _>>();
@ -3131,7 +3108,7 @@ fn send_header_two<'a>(
let package_entries = packages let package_entries = packages
.iter() .iter()
.map(|pkg| (pkg.value.shorthand, pkg.value.package_or_path.value)) .map(|pkg| (pkg.value.shorthand, pkg.value.package_name.value))
.collect::<MutMap<_, _>>(); .collect::<MutMap<_, _>>();
// Send the deps to the coordinator thread for processing, // Send the deps to the coordinator thread for processing,

View file

@ -1,19 +1,13 @@
use crate::ast::{Collection, CommentOrNewline, Spaced, 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::*;
use crate::parser::{specialize, word1, EPackageEntry, EPackageName, EPackageOrPath, Parser}; use crate::parser::{specialize, word1, EPackageEntry, EPackageName, Parser};
use crate::state::State; use crate::state::State;
use crate::string_literal; use crate::string_literal;
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use roc_region::all::Loc; use roc_region::all::Loc;
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct PackageName<'a> {
pub account: &'a str,
pub pkg: &'a str,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum Version<'a> { pub enum Version<'a> {
Exact(&'a str), Exact(&'a str),
@ -32,10 +26,7 @@ pub enum VersionComparison {
} }
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub enum PackageOrPath<'a> { pub struct PackageName<'a>(pub &'a str);
Package(PackageName<'a>, Version<'a>),
Path(StrLiteral<'a>),
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct ModuleName<'a>(&'a str); pub struct ModuleName<'a>(&'a str);
@ -93,7 +84,7 @@ pub struct InterfaceHeader<'a> {
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum To<'a> { pub enum To<'a> {
ExistingPackage(&'a str), ExistingPackage(&'a str),
NewPackage(PackageOrPath<'a>), NewPackage(PackageName<'a>),
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -121,7 +112,7 @@ pub struct AppHeader<'a> {
pub struct PackageHeader<'a> { pub struct PackageHeader<'a> {
pub name: Loc<PackageName<'a>>, pub name: Loc<PackageName<'a>>,
pub exposes: Vec<'a, Loc<Spaced<'a, ExposedName<'a>>>>, 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<PackageName<'a>>)>,
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>, pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
// Potential comments and newlines - these will typically all be empty. // Potential comments and newlines - these will typically all be empty.
@ -213,7 +204,7 @@ pub struct TypedIdent<'a> {
pub struct PackageEntry<'a> { pub struct PackageEntry<'a> {
pub shorthand: &'a str, pub shorthand: &'a str,
pub spaces_after_shorthand: &'a [CommentOrNewline<'a>], pub spaces_after_shorthand: &'a [CommentOrNewline<'a>],
pub package_or_path: Loc<PackageOrPath<'a>>, pub package_name: Loc<PackageName<'a>>,
} }
pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPackageEntry<'a>> { pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPackageEntry<'a>> {
@ -232,27 +223,24 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac
space0_e( space0_e(
min_indent, min_indent,
EPackageEntry::Space, EPackageEntry::Space,
EPackageEntry::IndentPackageOrPath EPackageEntry::IndentPackage
) )
)) ))
.parse(arena, state)?; .parse(arena, state)?;
let (_, package_or_path, state) = loc!(specialize( let (_, package_or_path, state) =
EPackageEntry::BadPackageOrPath, loc!(specialize(EPackageEntry::BadPackage, package_name())).parse(arena, state)?;
package_or_path()
))
.parse(arena, state)?;
let entry = match opt_shorthand { let entry = match opt_shorthand {
Some((shorthand, spaces_after_shorthand)) => PackageEntry { Some((shorthand, spaces_after_shorthand)) => PackageEntry {
shorthand, shorthand,
spaces_after_shorthand, spaces_after_shorthand,
package_or_path, package_name: package_or_path,
}, },
None => PackageEntry { None => PackageEntry {
shorthand: "", shorthand: "",
spaces_after_shorthand: &[], spaces_after_shorthand: &[],
package_or_path, package_name: package_or_path,
}, },
}; };
@ -260,113 +248,15 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac
} }
} }
pub fn package_or_path<'a>() -> impl Parser<'a, PackageOrPath<'a>, EPackageOrPath<'a>> { pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName<'a>> {
one_of![ move |arena, state: State<'a>| {
map!( let pos = state.pos;
specialize(EPackageOrPath::BadPath, string_literal::parse()), specialize(EPackageName::BadPath, string_literal::parse())
PackageOrPath::Path .parse(arena, state)
), .and_then(|(progress, text, next_state)| match text {
map!( StrLiteral::PlainLine(text) => Ok((progress, PackageName(text), next_state)),
and!( StrLiteral::Line(_) => Err((progress, EPackageName::Escapes(pos), next_state)),
specialize(EPackageOrPath::BadPackage, package_name()), StrLiteral::Block(_) => Err((progress, EPackageName::Multiline(pos), next_state)),
skip_first!(skip_spaces(), package_version()) })
),
|(name, version)| { PackageOrPath::Package(name, version) }
)
]
}
fn skip_spaces<'a, T>() -> impl Parser<'a, (), T>
where
T: 'a,
{
|_, mut state: State<'a>| {
let mut chomped = 0usize;
let mut it = state.bytes().iter();
while let Some(b' ') = it.next() {
chomped += 1;
}
if chomped == 0 {
Ok((NoProgress, (), state))
} else {
state.pos.column += chomped as u16;
state = state.advance(chomped);
Ok((MadeProgress, (), state))
}
}
}
fn package_version<'a, T>() -> impl Parser<'a, Version<'a>, T>
where
T: 'a,
{
move |_, _| todo!("TODO parse package version")
}
#[inline(always)]
pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName> {
use encode_unicode::CharExt;
// e.g. rtfeldman/blah
//
// Package names and accounts can be capitalized and can contain dashes.
// They cannot contain underscores or other special characters.
// They must be ASCII.
|_, mut state: State<'a>| match chomp_package_part(state.bytes()) {
Err(progress) => Err((progress, EPackageName::Account(state.pos), state)),
Ok(account) => {
let mut chomped = account.len();
if let Ok(('/', width)) = char::from_utf8_slice_start(&state.bytes()[chomped..]) {
chomped += width;
match chomp_package_part(&state.bytes()[chomped..]) {
Err(progress) => Err((
progress,
EPackageName::Pkg(state.pos.bump_column(chomped as u16)),
state,
)),
Ok(pkg) => {
chomped += pkg.len();
state.pos.column += chomped as u16;
state = state.advance(chomped);
let value = PackageName { account, pkg };
Ok((MadeProgress, value, state))
}
}
} else {
Err((
MadeProgress,
EPackageName::MissingSlash(state.pos.bump_column(chomped as u16)),
state,
))
}
}
}
}
fn chomp_package_part(buffer: &[u8]) -> Result<&str, Progress> {
use encode_unicode::CharExt;
let mut chomped = 0;
while let Ok((ch, width)) = char::from_utf8_slice_start(&buffer[chomped..]) {
if ch == '-' || ch.is_ascii_alphanumeric() {
chomped += width;
} else {
// we're done
break;
}
}
if chomped == 0 {
Err(Progress::NoProgress)
} else {
let name = unsafe { std::str::from_utf8_unchecked(&buffer[..chomped]) };
Ok(name)
} }
} }

View file

@ -1,9 +1,8 @@
use crate::ast::{Collection, CommentOrNewline, Def, Module, Spaced}; 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, ExposedName, ImportsEntry, package_entry, package_name, AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader,
InterfaceHeader, ModuleName, PackageEntry, PlatformHeader, PlatformRequires, PlatformRigid, To, ModuleName, PackageEntry, PlatformHeader, PlatformRequires, PlatformRigid, To, TypedIdent,
TypedIdent,
}; };
use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident}; use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident};
use crate::parser::Progress::{self, *}; use crate::parser::Progress::{self, *};
@ -312,7 +311,7 @@ fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
|_, pos| EProvides::Identifier(pos), |_, pos| EProvides::Identifier(pos),
map!(lowercase_ident(), To::ExistingPackage) map!(lowercase_ident(), To::ExistingPackage)
), ),
specialize(EProvides::Package, map!(package_or_path(), To::NewPackage)) specialize(EProvides::Package, map!(package_name(), To::NewPackage))
] ]
} }

View file

@ -79,7 +79,7 @@ pub enum EHeader<'a> {
Start(Position), Start(Position),
ModuleName(Position), ModuleName(Position),
AppName(EString<'a>, Position), AppName(EString<'a>, Position),
PlatformName(EPackageName, Position), PlatformName(EPackageName<'a>, Position),
IndentStart(Position), IndentStart(Position),
} }
@ -96,7 +96,7 @@ pub enum EProvides<'a> {
ListStart(Position), ListStart(Position),
ListEnd(Position), ListEnd(Position),
Identifier(Position), Identifier(Position),
Package(EPackageOrPath<'a>, Position), Package(EPackageName<'a>, Position),
Space(BadInputError, Position), Space(BadInputError, Position),
} }
@ -151,25 +151,19 @@ pub enum EPackages<'a> {
PackageEntry(EPackageEntry<'a>, Position), PackageEntry(EPackageEntry<'a>, Position),
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EPackageName {
MissingSlash(Position),
Account(Position),
Pkg(Position),
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum EPackageOrPath<'a> { pub enum EPackageName<'a> {
BadPath(EString<'a>, Position), BadPath(EString<'a>, Position),
BadPackage(EPackageName, Position), Escapes(Position),
Multiline(Position),
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum EPackageEntry<'a> { pub enum EPackageEntry<'a> {
BadPackageOrPath(EPackageOrPath<'a>, Position), BadPackage(EPackageName<'a>, Position),
Shorthand(Position), Shorthand(Position),
Colon(Position), Colon(Position),
IndentPackageOrPath(Position), IndentPackage(Position),
Space(BadInputError, Position), Space(BadInputError, Position),
} }

View file

@ -1,15 +1,14 @@
Platform { Platform {
header: PlatformHeader { header: PlatformHeader {
name: |L 0-0, C 9-23| PackageName { name: |L 0-0, C 9-25| PackageName(
account: "rtfeldman", "rtfeldman/blah",
pkg: "blah", ),
},
requires: PlatformRequires { requires: PlatformRequires {
rigids: [], rigids: [],
signature: |L 0-0, C 38-47| TypedIdent { signature: |L 0-0, C 40-49| TypedIdent {
ident: |L 0-0, C 38-42| "main", ident: |L 0-0, C 40-44| "main",
spaces_before_colon: [], spaces_before_colon: [],
ann: |L 0-0, C 45-47| Record { ann: |L 0-0, C 47-49| Record {
fields: [], fields: [],
ext: None, ext: None,
}, },

View file

@ -1 +1 @@
platform rtfeldman/blah requires {} { main : {} } exposes [] packages {} imports [] provides [] effects fx.Blah {} platform "rtfeldman/blah" requires {} { main : {} } exposes [] packages {} imports [] provides [] effects fx.Blah {}

View file

@ -7,11 +7,9 @@ App {
|L 1-1, C 15-31| PackageEntry { |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_name: |L 1-1, C 19-31| PackageName(
PlainLine(
"./platform", "./platform",
), ),
),
}, },
], ],
imports: [ imports: [

View file

@ -7,11 +7,9 @@ App {
|L 1-1, C 15-31| PackageEntry { |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_name: |L 1-1, C 19-31| PackageName(
PlainLine(
"./platform", "./platform",
), ),
),
}, },
], ],
imports: [ imports: [

View file

@ -1,9 +1,8 @@
Platform { Platform {
header: PlatformHeader { header: PlatformHeader {
name: |L 0-0, C 9-21| PackageName { name: |L 0-0, C 9-23| PackageName(
account: "examples", "examples/cli",
pkg: "cli", ),
},
requires: PlatformRequires { requires: PlatformRequires {
rigids: [], rigids: [],
signature: |L 1-1, C 17-34| TypedIdent { signature: |L 1-1, C 17-34| TypedIdent {

View file

@ -1,4 +1,4 @@
platform examples/cli platform "examples/cli"
requires {}{ main : Task {} [] } # TODO FIXME requires {}{ main : Task {} [] } # TODO FIXME
exposes [] exposes []
packages {} packages {}

View file

@ -7,12 +7,10 @@ App {
imports: [], imports: [],
provides: [], provides: [],
to: |L 0-0, C 30-38| NewPackage( to: |L 0-0, C 30-38| NewPackage(
Path( PackageName(
PlainLine(
"./blah", "./blah",
), ),
), ),
),
before_header: [], before_header: [],
after_app_keyword: [], after_app_keyword: [],
before_packages: [], before_packages: [],

View file

@ -1,9 +1,8 @@
Platform { Platform {
header: PlatformHeader { header: PlatformHeader {
name: |L 0-0, C 9-19| PackageName { name: |L 0-0, C 9-21| PackageName(
account: "foo", "foo/barbaz",
pkg: "barbaz", ),
},
requires: PlatformRequires { requires: PlatformRequires {
rigids: [ rigids: [
|L 1-1, C 14-26| PlatformRigid { |L 1-1, C 14-26| PlatformRigid {
@ -25,11 +24,9 @@ Platform {
|L 3-3, C 15-27| PackageEntry { |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_name: |L 3-3, C 20-27| PackageName(
PlainLine(
"./foo", "./foo",
), ),
),
}, },
], ],
imports: [], imports: [],

View file

@ -1,4 +1,4 @@
platform foo/barbaz platform "foo/barbaz"
requires {model=>Model} { main : {} } requires {model=>Model} { main : {} }
exposes [] exposes []
packages { foo: "./foo" } packages { foo: "./foo" }

View file

@ -1,4 +1,4 @@
platform folkertdev/foo platform "folkertdev/foo"
requires { model=>Model, msg=>Msg } { main : Effect {} } requires { model=>Model, msg=>Msg } { main : Effect {} }
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/cli platform "examples/cli"
requires {} { main : Task {} [] }# TODO FIXME requires {} { main : Task {} [] }# TODO FIXME
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform folkertdev/foo platform "folkertdev/foo"
requires {} { main : Effect {} } requires {} { main : Effect {} }
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/cli platform "examples/cli"
requires {} { main : Str -> Task {} [] }# TODO FIXME requires {} { main : Str -> Task {} [] }# TODO FIXME
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/add platform "examples/add"
requires {} { main : I64 -> I64 } requires {} { main : I64 -> I64 }
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/hello-world platform "examples/hello-world"
requires {} { main : Str } requires {} { main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/hello-swift platform "examples/hello-swift"
requires {} { main : Str } requires {} { main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/hello-world platform "examples/hello-world"
requires {} { main : Str } requires {} { main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/hello-world platform "examples/hello-world"
requires {} { main : Str } requires {} { main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/hello-world platform "examples/hello-world"
requires {} { main : Str } requires {} { main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -1,4 +1,4 @@
platform examples/quicksort platform "examples/quicksort"
requires {} { quicksort : List I64 -> List I64 } requires {} { quicksort : List I64 -> List I64 }
exposes [] exposes []
packages {} packages {}

View file

@ -2938,8 +2938,8 @@ fn to_header_report<'a>(
alloc.region_with_subregion(surroundings, region), alloc.region_with_subregion(surroundings, region),
alloc.concat(vec![ alloc.concat(vec![
alloc.reflow("I am expecting a platform name next, like "), alloc.reflow("I am expecting a platform name next, like "),
alloc.parser_suggestion("roc/core"), alloc.parser_suggestion("\"roc/core\""),
alloc.reflow("."), alloc.reflow(". Platform names must be quoted."),
]), ]),
]); ]);

View file

@ -6076,7 +6076,7 @@ I need all branches in an `if` to have the same type!
report_header_problem_as( report_header_problem_as(
indoc!( indoc!(
r#" r#"
platform folkertdev/foo platform "folkertdev/foo"
requires { main : Effect {} } requires { main : Effect {} }
exposes [] exposes []
packages {} packages {}
@ -6096,7 +6096,7 @@ I need all branches in an `if` to have the same type!
I am partway through parsing a header, but I got stuck here: I am partway through parsing a header, but I got stuck here:
1 platform folkertdev/foo 1 platform "folkertdev/foo"
2 requires { main : Effect {} } 2 requires { main : Effect {} }
^ ^