Parse hosted modules

This commit is contained in:
Richard Feldman 2022-01-29 21:10:50 -05:00
parent 8633cedf4d
commit 484ce2fbc9
No known key found for this signature in database
GPG key ID: 7E4127D1E4241798
5 changed files with 217 additions and 18 deletions

View file

@ -1,6 +1,6 @@
use std::fmt::Debug;
use crate::header::{AppHeader, InterfaceHeader, PlatformHeader};
use crate::header::{AppHeader, InterfaceHeader, PlatformHeader, HostedHeader};
use crate::ident::Ident;
use bumpalo::collections::{String, Vec};
use bumpalo::Bump;
@ -70,6 +70,7 @@ pub enum Module<'a> {
Interface { header: InterfaceHeader<'a> },
App { header: AppHeader<'a> },
Platform { header: PlatformHeader<'a> },
Hosted { header: HostedHeader<'a> },
}
#[derive(Clone, Copy, Debug, PartialEq)]

View file

@ -81,6 +81,27 @@ pub struct InterfaceHeader<'a> {
pub after_imports: &'a [CommentOrNewline<'a>],
}
#[derive(Clone, Debug, PartialEq)]
pub struct HostedHeader<'a> {
pub name: Loc<ModuleName<'a>>,
pub exposes: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
pub imports: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>,
pub generates: UppercaseIdent<'a>,
pub generates_with: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
// 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),

View file

@ -1,14 +1,17 @@
use crate::ast::{Collection, CommentOrNewline, Def, Module, Spaced};
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
use crate::header::{
package_entry, package_name, AppHeader, Effects, ExposedName, ImportsEntry, InterfaceHeader,
ModuleName, PackageEntry, PlatformHeader, PlatformRequires, To, TypedIdent,
package_entry, package_name, AppHeader, Effects, ExposedName, HostedHeader, ImportsEntry,
InterfaceHeader, ModuleName, PackageEntry, PlatformHeader, PlatformRequires, To, TypedIdent,
};
use crate::ident::{
self, lowercase_ident, unqualified_ident, uppercase, uppercase_ident, UppercaseIdent,
};
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase_ident, UppercaseIdent};
use crate::parser::Progress::{self, *};
use crate::parser::{
backtrackable, optional, specialize, specialize_region, word1, EEffects, EExposes, EHeader,
EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser, SourceError, SyntaxError,
backtrackable, optional, specialize, specialize_region, word1, EEffects, EExposes, EGenerates,
EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser,
SourceError, SyntaxError,
};
use crate::state::State;
use crate::string_literal;
@ -58,6 +61,15 @@ fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
and!(
space0_e(0, EHeader::Space, EHeader::IndentStart),
one_of![
map!(
skip_first!(keyword_e("interface", EHeader::Start), interface_header()),
|mut header: InterfaceHeader<'a>| -> Clos<'a> {
Box::new(|spaces| {
header.before_header = spaces;
Module::Interface { header }
})
}
),
map!(
skip_first!(keyword_e("app", EHeader::Start), app_header()),
|mut header: AppHeader<'a>| -> Clos<'a> {
@ -77,11 +89,11 @@ fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
}
),
map!(
skip_first!(keyword_e("interface", EHeader::Start), interface_header()),
|mut header: InterfaceHeader<'a>| -> Clos<'a> {
skip_first!(keyword_e("hosted", EHeader::Start), hosted_header()),
|mut header: HostedHeader<'a>| -> Clos<'a> {
Box::new(|spaces| {
header.before_header = spaces;
Module::Interface { header }
Module::Hosted { header }
})
}
)
@ -121,6 +133,46 @@ fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>, EHeader<'a>> {
}
}
#[inline(always)]
fn hosted_header<'a>() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> {
|arena, state| {
let min_indent = 1;
let (_, after_hosted_keyword, state) =
space0_e(min_indent, EHeader::Space, EHeader::IndentStart).parse(arena, state)?;
let (_, name, state) = loc!(module_name_help(EHeader::ModuleName)).parse(arena, state)?;
let (_, ((before_exposes, after_exposes), exposes), state) =
specialize(EHeader::Exposes, exposes_values()).parse(arena, state)?;
let (_, ((before_imports, after_imports), imports), state) =
specialize(EHeader::Imports, imports()).parse(arena, state)?;
let (_, ((before_generates, after_generates), generates), state) =
specialize(EHeader::Generates, generates()).parse(arena, state)?;
let (_, ((before_with, after_with), generates_with), state) =
specialize(EHeader::GeneratesWith, generates_with()).parse(arena, state)?;
let header = HostedHeader {
name,
exposes,
imports,
generates,
generates_with,
before_header: &[] as &[_],
after_hosted_keyword,
before_exposes,
after_exposes,
before_imports,
after_imports,
before_generates,
after_generates,
before_with,
after_with,
};
Ok((MadeProgress, header, state))
}
}
fn chomp_module_name(buffer: &[u8]) -> Result<&str, Progress> {
use encode_unicode::CharExt;
@ -678,6 +730,64 @@ fn packages<'a>() -> impl Parser<'a, Packages<'a>, EPackages<'a>> {
)
}
#[inline(always)]
fn generates<'a>() -> impl Parser<
'a,
(
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
UppercaseIdent<'a>,
),
EGenerates,
> {
let min_indent = 1;
and!(
spaces_around_keyword(
min_indent,
"generates",
EGenerates::Generates,
EGenerates::Space,
EGenerates::IndentGenerates,
EGenerates::IndentTypeStart
),
specialize(|(), pos| EGenerates::Identifier(pos), uppercase())
)
}
#[inline(always)]
fn generates_with<'a>() -> impl Parser<
'a,
(
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
),
EGeneratesWith,
> {
let min_indent = 1;
and!(
spaces_around_keyword(
min_indent,
"with",
EGeneratesWith::With,
EGeneratesWith::Space,
EGeneratesWith::IndentWith,
EGeneratesWith::IndentListStart
),
collection_trailing_sep_e!(
word1(b'[', EGeneratesWith::ListStart),
exposes_entry(EGeneratesWith::Identifier),
word1(b',', EGeneratesWith::ListEnd),
word1(b']', EGeneratesWith::ListEnd),
min_indent,
EGeneratesWith::Open,
EGeneratesWith::Space,
EGeneratesWith::IndentListEnd,
Spaced::SpaceBefore
)
)
}
#[inline(always)]
fn imports<'a>() -> impl Parser<
'a,

View file

@ -72,6 +72,8 @@ pub enum EHeader<'a> {
Requires(ERequires<'a>, Position),
Packages(EPackages<'a>, Position),
Effects(EEffects<'a>, Position),
Generates(EGenerates, Position),
GeneratesWith(EGeneratesWith, Position),
Space(BadInputError, Position),
Start(Position),
@ -202,6 +204,38 @@ pub enum EImports {
SetEnd(Position),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EGenerates {
Open(Position),
Generates(Position),
IndentGenerates(Position),
Identifier(Position),
Space(BadInputError, Position),
IndentTypeStart(Position),
IndentTypeEnd(Position),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EGeneratesWith {
Open(Position),
With(Position),
IndentWith(Position),
IndentListStart(Position),
IndentListEnd(Position),
ListStart(Position),
ListEnd(Position),
Identifier(Position),
ExposingDot(Position),
ShorthandDot(Position),
Shorthand(Position),
ModuleName(Position),
Space(BadInputError, Position),
IndentSetStart(Position),
IndentSetEnd(Position),
SetStart(Position),
SetEnd(Position),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BadInputError {
HasTab,