use crate::ast::{Collection, CommentOrNewline, Spaced, StrLiteral, TypeAnnotation}; use crate::blankspace::space0_e; use crate::ident::{lowercase_ident, UppercaseIdent}; use crate::parser::Progress::*; use crate::parser::{specialize, word1, EPackageEntry, EPackageName, Parser}; use crate::state::State; use crate::string_literal; use bumpalo::collections::Vec; use roc_module::symbol::Symbol; use roc_region::all::Loc; #[derive(Debug)] pub enum HeaderFor<'a> { App { to_platform: To<'a>, }, Hosted { generates: UppercaseIdent<'a>, generates_with: &'a [Loc>], }, /// Only created during canonicalization, never actually parsed from source Builtin { generates_with: &'a [Symbol], }, Platform { /// usually `pf` config_shorthand: &'a str, /// the type scheme of the main function (required by the platform) /// (currently unused) #[allow(dead_code)] platform_main_type: TypedIdent<'a>, /// provided symbol to host (commonly `mainForHost`) main_for_host: roc_module::symbol::Symbol, }, Interface, } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum Version<'a> { Exact(&'a str), Range { min: &'a str, min_comparison: VersionComparison, max: &'a str, max_comparison: VersionComparison, }, } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum VersionComparison { AllowsEqual, DisallowsEqual, } #[derive(Copy, Clone, PartialEq, Debug)] pub struct PackageName<'a>(&'a str); impl<'a> PackageName<'a> { pub fn to_str(self) -> &'a str { self.0 } pub fn as_str(&self) -> &'a str { self.0 } } impl<'a> From> for &'a str { fn from(name: PackageName<'a>) -> &'a str { name.0 } } impl<'a> From<&'a str> for PackageName<'a> { fn from(string: &'a str) -> Self { Self(string) } } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct ModuleName<'a>(&'a str); impl<'a> From> for &'a str { fn from(name: ModuleName<'a>) -> Self { name.0 } } impl<'a> ModuleName<'a> { pub const fn new(name: &'a str) -> Self { ModuleName(name) } pub const fn as_str(&'a self) -> &'a str { self.0 } } #[derive(Debug)] pub enum ModuleNameEnum<'a> { /// A filename App(StrLiteral<'a>), Interface(ModuleName<'a>), Hosted(ModuleName<'a>), Platform, } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct ExposedName<'a>(&'a str); impl<'a> From> for &'a str { fn from(name: ExposedName<'a>) -> Self { name.0 } } impl<'a> ExposedName<'a> { pub const fn new(name: &'a str) -> Self { ExposedName(name) } pub fn as_str(&'a self) -> &'a str { self.0 } } #[derive(Clone, Debug, PartialEq)] pub struct InterfaceHeader<'a> { pub name: Loc>, pub exposes: Collection<'a, Loc>>>, pub imports: Collection<'a, Loc>>>, // Potential comments and newlines - these will typically all be empty. pub before_header: &'a [CommentOrNewline<'a>], pub after_interface_keyword: &'a [CommentOrNewline<'a>], pub before_exposes: &'a [CommentOrNewline<'a>], pub after_exposes: &'a [CommentOrNewline<'a>], pub before_imports: &'a [CommentOrNewline<'a>], pub after_imports: &'a [CommentOrNewline<'a>], } #[derive(Clone, Debug, PartialEq)] pub struct HostedHeader<'a> { pub name: Loc>, pub exposes: Collection<'a, Loc>>>, pub imports: Collection<'a, Loc>>>, pub generates: UppercaseIdent<'a>, pub generates_with: Collection<'a, Loc>>>, // Potential comments and newlines - these will typically all be empty. pub before_header: &'a [CommentOrNewline<'a>], pub after_hosted_keyword: &'a [CommentOrNewline<'a>], pub before_exposes: &'a [CommentOrNewline<'a>], pub after_exposes: &'a [CommentOrNewline<'a>], pub before_imports: &'a [CommentOrNewline<'a>], pub after_imports: &'a [CommentOrNewline<'a>], pub before_generates: &'a [CommentOrNewline<'a>], pub after_generates: &'a [CommentOrNewline<'a>], pub before_with: &'a [CommentOrNewline<'a>], pub after_with: &'a [CommentOrNewline<'a>], } #[derive(Copy, Clone, Debug, PartialEq)] pub enum To<'a> { ExistingPackage(&'a str), NewPackage(PackageName<'a>), } #[derive(Clone, Debug, PartialEq)] pub struct AppHeader<'a> { pub name: Loc>, pub packages: Collection<'a, Loc>>>, pub imports: Collection<'a, Loc>>>, pub provides: Collection<'a, Loc>>>, pub provides_types: Option>>>>, pub to: Loc>, // Potential comments and newlines - these will typically all be empty. pub before_header: &'a [CommentOrNewline<'a>], pub after_app_keyword: &'a [CommentOrNewline<'a>], pub before_packages: &'a [CommentOrNewline<'a>], pub after_packages: &'a [CommentOrNewline<'a>], pub before_imports: &'a [CommentOrNewline<'a>], pub after_imports: &'a [CommentOrNewline<'a>], pub before_provides: &'a [CommentOrNewline<'a>], pub after_provides: &'a [CommentOrNewline<'a>], pub before_to: &'a [CommentOrNewline<'a>], pub after_to: &'a [CommentOrNewline<'a>], } #[derive(Clone, Debug, PartialEq)] pub struct PackageHeader<'a> { pub name: Loc>, pub exposes: Vec<'a, Loc>>>, pub packages: Vec<'a, (Loc<&'a str>, Loc>)>, pub imports: Vec<'a, Loc>>, // Potential comments and newlines - these will typically all be empty. pub before_header: &'a [CommentOrNewline<'a>], pub after_package_keyword: &'a [CommentOrNewline<'a>], pub before_exposes: &'a [CommentOrNewline<'a>], pub after_exposes: &'a [CommentOrNewline<'a>], pub before_packages: &'a [CommentOrNewline<'a>], pub after_packages: &'a [CommentOrNewline<'a>], pub before_imports: &'a [CommentOrNewline<'a>], pub after_imports: &'a [CommentOrNewline<'a>], } #[derive(Clone, Debug, PartialEq)] pub struct PlatformRequires<'a> { pub rigids: Collection<'a, Loc>>>, pub signature: Loc>>, } #[derive(Clone, Debug, PartialEq)] pub struct PlatformHeader<'a> { pub name: Loc>, pub requires: PlatformRequires<'a>, pub exposes: Collection<'a, Loc>>>, pub packages: Collection<'a, Loc>>>, pub imports: Collection<'a, Loc>>>, pub provides: Collection<'a, Loc>>>, // Potential comments and newlines - these will typically all be empty. pub before_header: &'a [CommentOrNewline<'a>], pub after_platform_keyword: &'a [CommentOrNewline<'a>], pub before_requires: &'a [CommentOrNewline<'a>], pub after_requires: &'a [CommentOrNewline<'a>], pub before_exposes: &'a [CommentOrNewline<'a>], pub after_exposes: &'a [CommentOrNewline<'a>], pub before_packages: &'a [CommentOrNewline<'a>], pub after_packages: &'a [CommentOrNewline<'a>], pub before_imports: &'a [CommentOrNewline<'a>], pub after_imports: &'a [CommentOrNewline<'a>], pub before_provides: &'a [CommentOrNewline<'a>], pub after_provides: &'a [CommentOrNewline<'a>], } #[derive(Copy, Clone, Debug, PartialEq)] pub enum ImportsEntry<'a> { /// e.g. `Task` or `Task.{ Task, after }` Module( ModuleName<'a>, Collection<'a, Loc>>>, ), /// e.g. `pf.Task` or `pf.Task.{ after }` or `pf.{ Task.{ Task, after } }` Package( &'a str, ModuleName<'a>, Collection<'a, Loc>>>, ), } /// e.g. /// /// printLine : Str -> Effect {} #[derive(Copy, Clone, Debug, PartialEq)] pub struct TypedIdent<'a> { pub ident: Loc<&'a str>, pub spaces_before_colon: &'a [CommentOrNewline<'a>], pub ann: Loc>, } #[derive(Copy, Clone, Debug, PartialEq)] pub struct PackageEntry<'a> { pub shorthand: &'a str, pub spaces_after_shorthand: &'a [CommentOrNewline<'a>], pub package_name: Loc>, } pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPackageEntry<'a>> { move |arena, state| { // You may optionally have a package shorthand, // e.g. "uc" in `uc: roc/unicode 1.0.0` // // (Indirect dependencies don't have a shorthand.) let min_indent = 1; let (_, opt_shorthand, state) = maybe!(and!( skip_second!( specialize(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()), word1(b':', EPackageEntry::Colon) ), space0_e(min_indent, EPackageEntry::IndentPackage) )) .parse(arena, state)?; let (_, package_or_path, state) = loc!(specialize(EPackageEntry::BadPackage, package_name())).parse(arena, state)?; let entry = match opt_shorthand { Some((shorthand, spaces_after_shorthand)) => PackageEntry { shorthand, spaces_after_shorthand, package_name: package_or_path, }, None => PackageEntry { shorthand: "", spaces_after_shorthand: &[], package_name: package_or_path, }, }; Ok((MadeProgress, Spaced::Item(entry), state)) } } pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName<'a>> { move |arena, state: State<'a>| { let pos = state.pos(); specialize(EPackageName::BadPath, string_literal::parse()) .parse(arena, state) .and_then(|(progress, text, next_state)| match text { StrLiteral::PlainLine(text) => Ok((progress, PackageName(text), next_state)), StrLiteral::Line(_) => Err((progress, EPackageName::Escapes(pos), next_state)), StrLiteral::Block(_) => Err((progress, EPackageName::Multiline(pos), next_state)), }) } }