Parse app header provided types

This commit is contained in:
Richard Feldman 2022-01-23 11:52:59 -05:00
parent c1c0ffb25f
commit 01942fd98e
6 changed files with 61 additions and 15 deletions

View file

@ -7,8 +7,8 @@ use crate::header::{
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase_ident, UppercaseIdent};
use crate::parser::Progress::{self, *};
use crate::parser::{
backtrackable, specialize, specialize_region, word1, EEffects, EExposes, EHeader, EImports,
EPackages, EProvides, ERequires, ETypedIdent, Parser, SourceError, SyntaxError,
backtrackable, optional, specialize, specialize_region, word1, EEffects, EExposes, EHeader,
EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser, SourceError, SyntaxError,
};
use crate::state::State;
use crate::string_literal;
@ -227,6 +227,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
packages,
imports,
provides: provides.entries,
provides_types: provides.types,
to: provides.to,
before_header: &[] as &[_],
after_app_keyword,
@ -265,7 +266,7 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
let (_, ((before_imports, after_imports), imports), state) =
specialize(EHeader::Imports, imports()).parse(arena, state)?;
let (_, ((before_provides, after_provides), provides), state) =
let (_, ((before_provides, after_provides), (provides, _provides_type)), state) =
specialize(EHeader::Provides, provides_without_to()).parse(arena, state)?;
let (_, effects, state) = specialize(EHeader::Effects, effects()).parse(arena, state)?;
@ -299,6 +300,7 @@ fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
#[derive(Debug)]
struct ProvidesTo<'a> {
entries: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
types: Option<Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>>,
to: Loc<To<'a>>,
before_provides_keyword: &'a [CommentOrNewline<'a>],
@ -337,11 +339,12 @@ fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> {
)
),
|(
((before_provides_keyword, after_provides_keyword), entries),
((before_provides_keyword, after_provides_keyword), (entries, provides_types)),
((before_to_keyword, after_to_keyword), to),
)| {
ProvidesTo {
entries,
types: provides_types,
to,
before_provides_keyword,
after_provides_keyword,
@ -357,7 +360,10 @@ fn provides_without_to<'a>() -> impl Parser<
'a,
(
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
(
Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
Option<Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>>,
),
),
EProvides<'a>,
> {
@ -371,20 +377,55 @@ fn provides_without_to<'a>() -> impl Parser<
EProvides::IndentProvides,
EProvides::IndentListStart
),
collection_trailing_sep_e!(
word1(b'[', EProvides::ListStart),
exposes_entry(EProvides::Identifier),
word1(b',', EProvides::ListEnd),
word1(b']', EProvides::ListEnd),
min_indent,
EProvides::Open,
EProvides::Space,
EProvides::IndentListEnd,
Spaced::SpaceBefore
and!(
collection_trailing_sep_e!(
word1(b'[', EProvides::ListStart),
exposes_entry(EProvides::Identifier),
word1(b',', EProvides::ListEnd),
word1(b']', EProvides::ListEnd),
min_indent,
EProvides::Open,
EProvides::Space,
EProvides::IndentListEnd,
Spaced::SpaceBefore
),
// Optionally
optional(provides_types())
)
)
}
#[inline(always)]
fn provides_types<'a>(
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, EProvides<'a>> {
let min_indent = 1;
collection_trailing_sep_e!(
word1(b'{', EProvides::ListStart),
provides_type_entry(EProvides::Identifier),
word1(b',', EProvides::ListEnd),
word1(b'}', EProvides::ListEnd),
min_indent,
EProvides::Open,
EProvides::Space,
EProvides::IndentListEnd,
Spaced::SpaceBefore
)
}
fn provides_type_entry<'a, F, E>(
to_expectation: F,
) -> impl Parser<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>, E>
where
F: Fn(Position) -> E,
F: Copy,
E: 'a,
{
loc!(map!(
specialize(|_, pos| to_expectation(pos), ident::uppercase()),
Spaced::Item
))
}
fn exposes_entry<'a, F, E>(
to_expectation: F,
) -> impl Parser<'a, Loc<Spaced<'a, ExposedName<'a>>>, E>