mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Parse platform headers
This commit is contained in:
parent
a31ed6943f
commit
dfa61b4c18
7 changed files with 240 additions and 23 deletions
|
@ -1,34 +1,41 @@
|
|||
use crate::ast::{
|
||||
AppHeader, Attempting, CommentOrNewline, Def, ExposesEntry, ImportsEntry, InterfaceHeader,
|
||||
Module,
|
||||
AppHeader, Attempting, CommentOrNewline, Def, EffectsEntry, ExposesEntry, ImportsEntry,
|
||||
InterfaceHeader, Module, PlatformHeader,
|
||||
};
|
||||
use crate::blankspace::{space0_around, space1};
|
||||
use crate::expr::def;
|
||||
use crate::header::ModuleName;
|
||||
use crate::header::{ModuleName, PackageName};
|
||||
use crate::ident::unqualified_ident;
|
||||
use crate::parser::{
|
||||
self, ascii_char, ascii_string, loc, optional, peek_utf8_char, peek_utf8_char_at, unexpected,
|
||||
Parser, State,
|
||||
unexpected_eof, ParseResult, Parser, State,
|
||||
};
|
||||
use crate::type_annotation;
|
||||
use bumpalo::collections::{String, Vec};
|
||||
use bumpalo::Bump;
|
||||
use roc_region::all::Located;
|
||||
|
||||
pub fn header<'a>() -> impl Parser<'a, Module<'a>> {
|
||||
one_of!(interface_module(), app_module())
|
||||
one_of!(interface_module(), app_module(), platform_module())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn interface_module<'a>() -> impl Parser<'a, Module<'a>> {
|
||||
fn app_module<'a>() -> impl Parser<'a, Module<'a>> {
|
||||
map!(app_header(), |header| { Module::App { header } })
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn platform_module<'a>() -> impl Parser<'a, Module<'a>> {
|
||||
map!(platform_header(), |header| { Module::Platform { header } })
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn interface_module<'a>() -> impl Parser<'a, Module<'a>> {
|
||||
map!(interface_header(), |header| {
|
||||
Module::Interface { header }
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn app_module<'a>() -> impl Parser<'a, Module<'a>> {
|
||||
map!(app_header(), |header| { Module::App { header } })
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>> {
|
||||
parser::map(
|
||||
|
@ -40,7 +47,7 @@ pub fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>> {
|
|||
and!(exposes(), imports())
|
||||
),
|
||||
|(
|
||||
(after_interface, name),
|
||||
(after_interface_keyword, name),
|
||||
(
|
||||
((before_exposes, after_exposes), exposes),
|
||||
((before_imports, after_imports), imports),
|
||||
|
@ -50,7 +57,7 @@ pub fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>> {
|
|||
name,
|
||||
exposes,
|
||||
imports,
|
||||
after_interface,
|
||||
after_interface_keyword,
|
||||
before_exposes,
|
||||
after_exposes,
|
||||
before_imports,
|
||||
|
@ -60,6 +67,46 @@ pub fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>> {
|
|||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>> {
|
||||
// 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.
|
||||
|
||||
map!(
|
||||
and!(
|
||||
move |arena, state| parse_package_part(arena, state),
|
||||
skip_first!(ascii_char('/'), move |arena, state| parse_package_part(
|
||||
arena, state
|
||||
))
|
||||
),
|
||||
|(account, pkg)| { PackageName { account, pkg } }
|
||||
)
|
||||
}
|
||||
|
||||
pub fn parse_package_part<'a>(arena: &'a Bump, mut state: State<'a>) -> ParseResult<'a, &'a str> {
|
||||
let mut part_buf = String::new_in(arena); // The current "part" (parts are dot-separated.)
|
||||
|
||||
while !state.bytes.is_empty() {
|
||||
match peek_utf8_char(&state) {
|
||||
Ok((ch, bytes_parsed)) => {
|
||||
if ch == '-' || ch.is_ascii_alphanumeric() {
|
||||
part_buf.push(ch);
|
||||
|
||||
state = state.advance_without_indenting(bytes_parsed)?;
|
||||
} else {
|
||||
return Ok((part_buf.into_bump_str(), state));
|
||||
}
|
||||
}
|
||||
Err(reason) => return state.fail(reason),
|
||||
}
|
||||
}
|
||||
|
||||
Err(unexpected_eof(0, state.attempting, state))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>> {
|
||||
move |arena, mut state: State<'a>| {
|
||||
|
@ -135,7 +182,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>> {
|
|||
and!(provides(), imports())
|
||||
),
|
||||
|(
|
||||
(after_interface, name),
|
||||
(after_app_keyword, name),
|
||||
(
|
||||
((before_provides, after_provides), provides),
|
||||
((before_imports, after_imports), imports),
|
||||
|
@ -145,7 +192,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>> {
|
|||
name,
|
||||
provides,
|
||||
imports,
|
||||
after_interface,
|
||||
after_app_keyword,
|
||||
before_provides,
|
||||
after_provides,
|
||||
before_imports,
|
||||
|
@ -155,6 +202,49 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>> {
|
|||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>> {
|
||||
parser::map(
|
||||
and!(
|
||||
skip_first!(
|
||||
ascii_string("platform"),
|
||||
and!(space1(1), loc!(package_name()))
|
||||
),
|
||||
and!(provides(), and!(requires(), and!(imports(), effects())))
|
||||
),
|
||||
|(
|
||||
(after_platform_keyword, name),
|
||||
(
|
||||
((before_provides, after_provides), provides),
|
||||
(
|
||||
((before_requires, after_requires), requires),
|
||||
(
|
||||
((before_imports, after_imports), imports),
|
||||
((before_effects, after_effects), effects),
|
||||
),
|
||||
),
|
||||
),
|
||||
)| {
|
||||
PlatformHeader {
|
||||
name,
|
||||
provides,
|
||||
requires,
|
||||
imports,
|
||||
effects,
|
||||
after_platform_keyword,
|
||||
before_provides,
|
||||
after_provides,
|
||||
before_requires,
|
||||
after_requires,
|
||||
before_imports,
|
||||
after_imports,
|
||||
before_effects,
|
||||
after_effects,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn module_defs<'a>() -> impl Parser<'a, Vec<'a, Located<Def<'a>>>> {
|
||||
zero_or_more!(space0_around(loc(def(0)), 0))
|
||||
|
@ -180,6 +270,26 @@ fn provides<'a>() -> impl Parser<
|
|||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires<'a>() -> impl Parser<
|
||||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<ExposesEntry<'a>>>,
|
||||
),
|
||||
> {
|
||||
and!(
|
||||
and!(skip_second!(space1(1), ascii_string("requires")), space1(1)),
|
||||
collection!(
|
||||
ascii_char('['),
|
||||
loc!(exposes_entry()),
|
||||
ascii_char(','),
|
||||
ascii_char(']'),
|
||||
1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes<'a>() -> impl Parser<
|
||||
'a,
|
||||
|
@ -220,6 +330,37 @@ fn imports<'a>() -> impl Parser<
|
|||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn effects<'a>() -> impl Parser<
|
||||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<EffectsEntry<'a>>>,
|
||||
),
|
||||
> {
|
||||
and!(
|
||||
and!(skip_second!(space1(1), ascii_string("effects")), space1(1)),
|
||||
collection!(
|
||||
ascii_char('{'),
|
||||
loc!(effects_entry()),
|
||||
ascii_char(','),
|
||||
ascii_char('}'),
|
||||
1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn effects_entry<'a>() -> impl Parser<'a, EffectsEntry<'a>> {
|
||||
// e.g.
|
||||
//
|
||||
// printLine : Str -> Effect {}
|
||||
map!(
|
||||
and!(loc(unqualified_ident()), type_annotation::located(0)),
|
||||
|(ident, ann)| { EffectsEntry::Effect { ident, ann } }
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn exposes_entry<'a>() -> impl Parser<'a, ExposesEntry<'a>> {
|
||||
map!(unqualified_ident(), ExposesEntry::Ident)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue