mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-20 23:37:56 +03:00
Merge pull request #1197 from rtfeldman/parse-platform-rigids
Parse platform rigids
This commit is contained in:
commit
79b5af951b
@ -1,5 +1,5 @@
|
||||
platform examples/multi-module
|
||||
requires { main : Str }
|
||||
requires {}{ main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
|
@ -1,5 +1,5 @@
|
||||
platform examples/multi-dep-thunk
|
||||
requires { main : Str }
|
||||
requires {}{ main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
|
@ -1146,7 +1146,7 @@ impl<'a> LoadStart<'a> {
|
||||
let (root_id, root_msg) = {
|
||||
let root_start_time = SystemTime::now();
|
||||
|
||||
load_filename(
|
||||
let res_loaded = load_filename(
|
||||
arena,
|
||||
filename,
|
||||
true,
|
||||
@ -1154,7 +1154,26 @@ impl<'a> LoadStart<'a> {
|
||||
Arc::clone(&arc_modules),
|
||||
Arc::clone(&ident_ids_by_module),
|
||||
root_start_time,
|
||||
)?
|
||||
);
|
||||
|
||||
match res_loaded {
|
||||
Ok(good) => good,
|
||||
|
||||
Err(LoadingProblem::ParsingFailed(problem)) => {
|
||||
let module_ids = Arc::try_unwrap(arc_modules)
|
||||
.unwrap_or_else(|_| {
|
||||
panic!("There were still outstanding Arc references to module_ids")
|
||||
})
|
||||
.into_inner()
|
||||
.into_module_ids();
|
||||
|
||||
// if parsing failed, this module did not add any identifiers
|
||||
let root_exposed_ident_ids = IdentIds::exposed_builtins(0);
|
||||
let buf = to_parse_problem_report(problem, module_ids, root_exposed_ident_ids);
|
||||
return Err(LoadingProblem::FormattedReport(buf));
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(LoadStart {
|
||||
@ -1535,14 +1554,41 @@ where
|
||||
// This is where most of the main thread's work gets done.
|
||||
// Everything up to this point has been setting up the threading
|
||||
// system which lets this logic work efficiently.
|
||||
state = update(
|
||||
let constrained_ident_ids = state.constrained_ident_ids.clone();
|
||||
let arc_modules = state.arc_modules.clone();
|
||||
|
||||
let res_state = update(
|
||||
state,
|
||||
msg,
|
||||
msg_tx.clone(),
|
||||
&injector,
|
||||
worker_listeners,
|
||||
arena,
|
||||
)?;
|
||||
);
|
||||
|
||||
match res_state {
|
||||
Ok(new_state) => {
|
||||
state = new_state;
|
||||
}
|
||||
Err(LoadingProblem::ParsingFailed(problem)) => {
|
||||
shut_down_worker_threads!();
|
||||
|
||||
let module_ids = Arc::try_unwrap(arc_modules)
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(r"There were still outstanding Arc references to module_ids")
|
||||
})
|
||||
.into_inner()
|
||||
.into_module_ids();
|
||||
|
||||
let buf = to_parse_problem_report(
|
||||
problem,
|
||||
module_ids,
|
||||
constrained_ident_ids,
|
||||
);
|
||||
return Err(LoadingProblem::FormattedReport(buf));
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3224,7 +3270,7 @@ fn fabricate_pkg_config_module<'a>(
|
||||
app_module_id,
|
||||
packages: &[],
|
||||
provides,
|
||||
requires: header.requires.clone().into_bump_slice(),
|
||||
requires: arena.alloc([header.requires.signature.clone()]),
|
||||
imports: header.imports.clone().into_bump_slice(),
|
||||
};
|
||||
|
||||
|
@ -124,10 +124,34 @@ pub struct PackageHeader<'a> {
|
||||
pub after_imports: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum PlatformRigid<'a> {
|
||||
Entry { rigid: &'a str, alias: &'a str },
|
||||
|
||||
// Spaces
|
||||
SpaceBefore(&'a PlatformRigid<'a>, &'a [CommentOrNewline<'a>]),
|
||||
SpaceAfter(&'a PlatformRigid<'a>, &'a [CommentOrNewline<'a>]),
|
||||
}
|
||||
|
||||
impl<'a> Spaceable<'a> for PlatformRigid<'a> {
|
||||
fn before(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
PlatformRigid::SpaceBefore(self, spaces)
|
||||
}
|
||||
fn after(&'a self, spaces: &'a [CommentOrNewline<'a>]) -> Self {
|
||||
PlatformRigid::SpaceAfter(self, spaces)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PlatformRequires<'a> {
|
||||
pub rigids: Vec<'a, Loc<PlatformRigid<'a>>>,
|
||||
pub signature: Loc<TypedIdent<'a>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PlatformHeader<'a> {
|
||||
pub name: Loc<PackageName<'a>>,
|
||||
pub requires: Vec<'a, Loc<TypedIdent<'a>>>,
|
||||
pub requires: PlatformRequires<'a>,
|
||||
pub exposes: Vec<'a, Loc<ExposesEntry<'a, ModuleName<'a>>>>,
|
||||
pub packages: Vec<'a, Loc<PackageEntry<'a>>>,
|
||||
pub imports: Vec<'a, Loc<ImportsEntry<'a>>>,
|
||||
|
@ -1,13 +1,14 @@
|
||||
use crate::ast::{CommentOrNewline, Def, Module};
|
||||
use crate::blankspace::{space0_before_e, space0_e};
|
||||
use crate::blankspace::{space0_around_ee, space0_before_e, space0_e};
|
||||
use crate::header::{
|
||||
package_entry, package_name, package_or_path, AppHeader, Effects, ExposesEntry, ImportsEntry,
|
||||
InterfaceHeader, ModuleName, PackageEntry, PlatformHeader, To, TypedIdent,
|
||||
InterfaceHeader, ModuleName, PackageEntry, PlatformHeader, PlatformRequires, PlatformRigid, To,
|
||||
TypedIdent,
|
||||
};
|
||||
use crate::ident::{lowercase_ident, unqualified_ident, uppercase_ident};
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
backtrackable, specialize, word1, Col, EEffects, EExposes, EHeader, EImports, EPackages,
|
||||
backtrackable, specialize, word1, word2, Col, EEffects, EExposes, EHeader, EImports, EPackages,
|
||||
EProvides, ERequires, ETypedIdent, Parser, Row, State, SyntaxError,
|
||||
};
|
||||
use crate::string_literal;
|
||||
@ -406,11 +407,11 @@ fn requires<'a>() -> impl Parser<
|
||||
'a,
|
||||
(
|
||||
(&'a [CommentOrNewline<'a>], &'a [CommentOrNewline<'a>]),
|
||||
Vec<'a, Located<TypedIdent<'a>>>,
|
||||
PlatformRequires<'a>,
|
||||
),
|
||||
ERequires<'a>,
|
||||
> {
|
||||
let min_indent = 1;
|
||||
let min_indent = 0;
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
@ -420,14 +421,63 @@ fn requires<'a>() -> impl Parser<
|
||||
ERequires::IndentRequires,
|
||||
ERequires::IndentListStart
|
||||
),
|
||||
collection_e!(
|
||||
word1(b'{', ERequires::ListStart),
|
||||
specialize(ERequires::TypedIdent, loc!(typed_ident())),
|
||||
word1(b',', ERequires::ListEnd),
|
||||
word1(b'}', ERequires::ListEnd),
|
||||
min_indent,
|
||||
ERequires::Space,
|
||||
ERequires::IndentListEnd
|
||||
platform_requires()
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a>> {
|
||||
map!(
|
||||
and!(
|
||||
skip_second!(
|
||||
requires_rigids(0),
|
||||
space0_e(0, ERequires::Space, ERequires::ListStart)
|
||||
),
|
||||
requires_typed_ident()
|
||||
),
|
||||
|(rigids, signature)| { PlatformRequires { rigids, signature } }
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires_rigids<'a>(
|
||||
min_indent: u16,
|
||||
) -> impl Parser<'a, Vec<'a, Located<PlatformRigid<'a>>>, ERequires<'a>> {
|
||||
collection_e!(
|
||||
word1(b'{', ERequires::ListStart),
|
||||
specialize(|_, r, c| ERequires::Rigid(r, c), loc!(requires_rigid())),
|
||||
word1(b',', ERequires::ListEnd),
|
||||
word1(b'}', ERequires::ListEnd),
|
||||
min_indent,
|
||||
ERequires::Space,
|
||||
ERequires::IndentListEnd
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires_rigid<'a>() -> impl Parser<'a, PlatformRigid<'a>, ()> {
|
||||
map!(
|
||||
and!(
|
||||
lowercase_ident(),
|
||||
skip_first!(word2(b'=', b'>', |_, _| ()), uppercase_ident())
|
||||
),
|
||||
|(rigid, alias)| PlatformRigid::Entry { rigid, alias }
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn requires_typed_ident<'a>() -> impl Parser<'a, Located<TypedIdent<'a>>, ERequires<'a>> {
|
||||
skip_first!(
|
||||
word1(b'{', ERequires::ListStart),
|
||||
skip_second!(
|
||||
space0_around_ee(
|
||||
specialize(ERequires::TypedIdent, loc!(typed_ident()),),
|
||||
0,
|
||||
ERequires::Space,
|
||||
ERequires::ListStart,
|
||||
ERequires::ListEnd
|
||||
),
|
||||
word1(b'}', ERequires::ListStart)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -248,6 +248,7 @@ pub enum ERequires<'a> {
|
||||
ListStart(Row, Col),
|
||||
ListEnd(Row, Col),
|
||||
TypedIdent(ETypedIdent<'a>, Row, Col),
|
||||
Rigid(Row, Col),
|
||||
Space(BadInputError, Row, Col),
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,8 @@ mod test_parse {
|
||||
use roc_parse::ast::{self, Def, EscapedChar, Spaceable, TypeAnnotation, WhenBranch};
|
||||
use roc_parse::header::{
|
||||
AppHeader, Effects, ExposesEntry, ImportsEntry, InterfaceHeader, ModuleName, PackageEntry,
|
||||
PackageName, PackageOrPath, PlatformHeader, To,
|
||||
PackageName, PackageOrPath, PlatformHeader, PlatformRequires, PlatformRigid, To,
|
||||
TypedIdent,
|
||||
};
|
||||
use roc_parse::module::module_defs;
|
||||
use roc_parse::parser::{Parser, State, SyntaxError};
|
||||
@ -3128,10 +3129,35 @@ mod test_parse {
|
||||
spaces_after_effects_keyword: &[],
|
||||
spaces_after_type_name: &[],
|
||||
};
|
||||
|
||||
let requires = {
|
||||
let region1 = Region::new(0, 0, 38, 47);
|
||||
let region2 = Region::new(0, 0, 45, 47);
|
||||
|
||||
PlatformRequires {
|
||||
rigids: Vec::new_in(&arena),
|
||||
signature: Located::at(
|
||||
region1,
|
||||
TypedIdent::Entry {
|
||||
ident: Located::new(0, 0, 38, 42, "main"),
|
||||
spaces_before_colon: &[],
|
||||
ann: Located::at(
|
||||
region2,
|
||||
TypeAnnotation::Record {
|
||||
fields: &[],
|
||||
ext: None,
|
||||
final_comments: &[],
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
let header = PlatformHeader {
|
||||
before_header: &[],
|
||||
name: Located::new(0, 0, 9, 23, pkg_name),
|
||||
requires: Vec::new_in(&arena),
|
||||
requires,
|
||||
exposes: Vec::new_in(&arena),
|
||||
packages: Vec::new_in(&arena),
|
||||
imports: Vec::new_in(&arena),
|
||||
@ -3152,7 +3178,7 @@ mod test_parse {
|
||||
|
||||
let expected = roc_parse::ast::Module::Platform { header };
|
||||
|
||||
let src = "platform rtfeldman/blah requires {} exposes [] packages {} imports [] provides [] effects fx.Blah {}";
|
||||
let src = "platform rtfeldman/blah requires {} { main : {} } exposes [] packages {} imports [] provides [] effects fx.Blah {}";
|
||||
let actual = roc_parse::module::parse_header(&arena, State::new(src.as_bytes()))
|
||||
.map(|tuple| tuple.0);
|
||||
|
||||
@ -3188,10 +3214,36 @@ mod test_parse {
|
||||
spaces_after_effects_keyword: &[],
|
||||
spaces_after_type_name: &[],
|
||||
};
|
||||
|
||||
let requires = {
|
||||
let region1 = Region::new(1, 1, 30, 39);
|
||||
let region2 = Region::new(1, 1, 37, 39);
|
||||
let region3 = Region::new(1, 1, 14, 26);
|
||||
|
||||
PlatformRequires {
|
||||
rigids: bumpalo::vec![ in &arena; Located::at(region3, PlatformRigid::Entry { alias: "Model", rigid: "model" }) ],
|
||||
signature: Located::at(
|
||||
region1,
|
||||
TypedIdent::Entry {
|
||||
ident: Located::new(1, 1, 30, 34, "main"),
|
||||
spaces_before_colon: &[],
|
||||
ann: Located::at(
|
||||
region2,
|
||||
TypeAnnotation::Record {
|
||||
fields: &[],
|
||||
ext: None,
|
||||
final_comments: &[],
|
||||
},
|
||||
),
|
||||
},
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
let header = PlatformHeader {
|
||||
before_header: &[],
|
||||
name: Located::new(0, 0, 9, 19, pkg_name),
|
||||
requires: Vec::new_in(&arena),
|
||||
requires,
|
||||
exposes: Vec::new_in(&arena),
|
||||
packages,
|
||||
imports,
|
||||
@ -3215,7 +3267,7 @@ mod test_parse {
|
||||
let src = indoc!(
|
||||
r#"
|
||||
platform foo/barbaz
|
||||
requires {}
|
||||
requires {model=>Model} { main : {} }
|
||||
exposes []
|
||||
packages { foo: "./foo" }
|
||||
imports []
|
||||
|
@ -3238,6 +3238,31 @@ fn to_requires_report<'a>(
|
||||
|
||||
ERequires::Space(error, row, col) => to_space_report(alloc, filename, &error, row, col),
|
||||
|
||||
ERequires::ListStart(row, col) => {
|
||||
dbg!(row, col);
|
||||
let surroundings = Region::from_rows_cols(start_row, start_col, row, col);
|
||||
let region = Region::from_row_col(row, col);
|
||||
|
||||
let doc = alloc.stack(vec![
|
||||
alloc.reflow(r"I am partway through parsing a header, but I got stuck here:"),
|
||||
alloc.region_with_subregion(surroundings, region),
|
||||
alloc.concat(vec![
|
||||
alloc.reflow("I am expecting the "),
|
||||
alloc.keyword("requires"),
|
||||
alloc.reflow(" keyword next, like "),
|
||||
]),
|
||||
alloc
|
||||
.parser_suggestion("requires { main : Task I64 Str }")
|
||||
.indent(4),
|
||||
]);
|
||||
|
||||
Report {
|
||||
filename,
|
||||
doc,
|
||||
title: "MISSING REQUIRES".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
_ => todo!("unhandled parse error {:?}", parse_problem),
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
platform folkertdev/foo
|
||||
requires { main : Effect {} }
|
||||
requires {model=>Model, msg=>Msg} {main : Effect {}}
|
||||
exposes []
|
||||
packages {}
|
||||
imports [ Task ]
|
||||
|
@ -1,5 +1,5 @@
|
||||
platform rtfeldman/roc-cli
|
||||
requires { main : Task.Task {} * } # TODO FIXME
|
||||
requires {}{ main : Task.Task {} * } # TODO FIXME
|
||||
exposes [] # TODO FIXME actually expose modules
|
||||
packages {}
|
||||
imports [ Task ] # TODO FIXME Task.{ Task }
|
||||
|
@ -1,5 +1,5 @@
|
||||
platform examples/hello-world
|
||||
requires { main : Str }
|
||||
requires {}{ main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
|
@ -1,5 +1,5 @@
|
||||
platform examples/quicksort
|
||||
requires { quicksort : List I64 -> List I64 }
|
||||
requires {}{ quicksort : List I64 -> List I64 }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
|
@ -1,5 +1,5 @@
|
||||
platform folkertdev/foo
|
||||
requires { main : Task {} [] }
|
||||
requires {}{ main : Task {} [] }
|
||||
exposes []
|
||||
packages {}
|
||||
imports [ Task ]
|
||||
|
@ -1,10 +1,10 @@
|
||||
platform folkertdev/foo
|
||||
requires { main : {} }
|
||||
requires {}{foo:Str}
|
||||
exposes []
|
||||
packages {}
|
||||
imports [Cmd]
|
||||
provides [ mainForHost ]
|
||||
effects Effect
|
||||
effects fx.Effect
|
||||
{
|
||||
putChar : I64 -> Effect {},
|
||||
putLine : Str -> Effect {},
|
||||
|
Loading…
Reference in New Issue
Block a user