mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 20:28:02 +00:00
Parse params in module header
module {echo, read} -> [menu] Formatter isn't implemented yet.
This commit is contained in:
parent
010aed88f9
commit
5b1a3c8f03
16 changed files with 145 additions and 32 deletions
|
@ -177,7 +177,7 @@ pub fn fmt_module_header<'a>(buf: &mut Buf, header: &'a ModuleHeader<'a>) {
|
|||
buf.indent(0);
|
||||
buf.push_str("module");
|
||||
|
||||
let indent = fmt_spaces_with_outdent(buf, header.before_exposes, INDENT);
|
||||
let indent = fmt_spaces_with_outdent(buf, header.after_keyword, INDENT);
|
||||
fmt_exposes(buf, header.exposes, indent);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@ use roc_parse::{
|
|||
},
|
||||
header::{
|
||||
AppHeader, ExposedName, HostedHeader, ImportsEntry, KeywordItem, ModuleHeader, ModuleName,
|
||||
PackageEntry, PackageHeader, PackageName, PlatformHeader, PlatformRequires, ProvidesTo, To,
|
||||
TypedIdent,
|
||||
ModuleParams, PackageEntry, PackageHeader, PackageName, PlatformHeader, PlatformRequires,
|
||||
ProvidesTo, To, TypedIdent,
|
||||
},
|
||||
ident::{BadIdent, UppercaseIdent},
|
||||
};
|
||||
|
@ -285,7 +285,8 @@ impl<'a> RemoveSpaces<'a> for Module<'a> {
|
|||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||
let header = match &self.header {
|
||||
Header::Module(header) => Header::Module(ModuleHeader {
|
||||
before_exposes: &[],
|
||||
after_keyword: &[],
|
||||
params: header.params.remove_spaces(arena),
|
||||
exposes: header.exposes.remove_spaces(arena),
|
||||
interface_imports: header.interface_imports.remove_spaces(arena),
|
||||
}),
|
||||
|
@ -330,6 +331,16 @@ impl<'a> RemoveSpaces<'a> for Module<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> RemoveSpaces<'a> for ModuleParams<'a> {
|
||||
fn remove_spaces(&self, arena: &'a Bump) -> Self {
|
||||
ModuleParams {
|
||||
params: self.params.remove_spaces(arena),
|
||||
before_arrow: &[],
|
||||
after_arrow: &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RemoveSpaces<'a> for Region {
|
||||
fn remove_spaces(&self, _arena: &'a Bump) -> Self {
|
||||
Region::zero()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::ast::{
|
||||
Collection, CommentOrNewline, Malformed, Spaced, Spaces, StrLiteral, TypeAnnotation,
|
||||
Collection, CommentOrNewline, Malformed, Pattern, Spaced, Spaces, StrLiteral, TypeAnnotation,
|
||||
};
|
||||
use crate::blankspace::space0_e;
|
||||
use crate::expr::merge_spaces;
|
||||
|
@ -242,13 +242,21 @@ pub struct KeywordItem<'a, K, V> {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ModuleHeader<'a> {
|
||||
pub before_exposes: &'a [CommentOrNewline<'a>],
|
||||
pub after_keyword: &'a [CommentOrNewline<'a>],
|
||||
pub params: Option<ModuleParams<'a>>,
|
||||
pub exposes: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
|
||||
|
||||
// Keeping this so we can format old interface header into module headers
|
||||
pub interface_imports: Option<KeywordItem<'a, ImportsKeyword, ImportsCollection<'a>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ModuleParams<'a> {
|
||||
pub params: Collection<'a, Loc<Pattern<'a>>>,
|
||||
pub before_arrow: &'a [CommentOrNewline<'a>],
|
||||
pub after_arrow: &'a [CommentOrNewline<'a>],
|
||||
}
|
||||
|
||||
pub type ImportsKeywordItem<'a> = KeywordItem<'a, ImportsKeyword, ImportsCollection<'a>>;
|
||||
pub type ImportsCollection<'a> = Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>;
|
||||
|
||||
|
|
|
@ -4,17 +4,18 @@ use crate::expr::merge_spaces;
|
|||
use crate::header::{
|
||||
package_entry, package_name, AppHeader, ExposedName, ExposesKeyword, GeneratesKeyword,
|
||||
HostedHeader, ImportsCollection, ImportsEntry, ImportsKeyword, ImportsKeywordItem, Keyword,
|
||||
KeywordItem, ModuleHeader, ModuleName, PackageEntry, PackageHeader, PackagesKeyword,
|
||||
PlatformHeader, PlatformRequires, ProvidesKeyword, ProvidesTo, RequiresKeyword, To, ToKeyword,
|
||||
TypedIdent, WithKeyword,
|
||||
KeywordItem, ModuleHeader, ModuleName, ModuleParams, PackageEntry, PackageHeader,
|
||||
PackagesKeyword, PlatformHeader, PlatformRequires, ProvidesKeyword, ProvidesTo,
|
||||
RequiresKeyword, To, ToKeyword, TypedIdent, WithKeyword,
|
||||
};
|
||||
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent};
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
backtrackable, byte, increment_min_indent, optional, reset_min_indent, specialize_err,
|
||||
two_bytes, EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides,
|
||||
ERequires, ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
|
||||
two_bytes, EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EParams,
|
||||
EProvides, ERequires, ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
|
||||
};
|
||||
use crate::pattern::record_pattern_fields;
|
||||
use crate::state::State;
|
||||
use crate::string_literal::{self, parse_str_literal};
|
||||
use crate::type_annotation;
|
||||
|
@ -111,13 +112,25 @@ pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
|||
#[inline(always)]
|
||||
fn module_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
|
||||
record!(ModuleHeader {
|
||||
before_exposes: space0_e(EHeader::IndentStart),
|
||||
after_keyword: space0_e(EHeader::IndentStart),
|
||||
params: optional(specialize_err(EHeader::Params, module_params())),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_list()),
|
||||
interface_imports: succeed!(None)
|
||||
})
|
||||
.trace("module_header")
|
||||
}
|
||||
|
||||
fn module_params<'a>() -> impl Parser<'a, ModuleParams<'a>, EParams<'a>> {
|
||||
record!(ModuleParams {
|
||||
params: specialize_err(EParams::Pattern, record_pattern_fields()),
|
||||
before_arrow: skip_second!(
|
||||
space0_e(EParams::BeforeArrow),
|
||||
loc!(two_bytes(b'-', b'>', EParams::Arrow))
|
||||
),
|
||||
after_arrow: space0_e(EParams::AfterArrow),
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! merge_n_spaces {
|
||||
($arena:expr, $($slice:expr),*) => {
|
||||
{
|
||||
|
@ -131,7 +144,7 @@ macro_rules! merge_n_spaces {
|
|||
/// Parse old interface headers so we can format them into module headers
|
||||
#[inline(always)]
|
||||
fn interface_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
|
||||
let before_exposes = map_with_arena!(
|
||||
let after_keyword = map_with_arena!(
|
||||
and!(
|
||||
skip_second!(
|
||||
space0_e(EHeader::IndentStart),
|
||||
|
@ -146,7 +159,8 @@ fn interface_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> {
|
|||
);
|
||||
|
||||
record!(ModuleHeader {
|
||||
before_exposes: before_exposes,
|
||||
after_keyword: after_keyword,
|
||||
params: succeed!(None),
|
||||
exposes: specialize_err(EHeader::Exposes, exposes_list()).trace("exposes_list"),
|
||||
interface_imports: map!(
|
||||
specialize_err(EHeader::Imports, imports()),
|
||||
|
|
|
@ -88,6 +88,7 @@ impl_space_problem! {
|
|||
EHeader<'a>,
|
||||
EIf<'a>,
|
||||
EImport<'a>,
|
||||
EParams<'a>,
|
||||
EImports,
|
||||
EInParens<'a>,
|
||||
EClosure<'a>,
|
||||
|
@ -115,6 +116,7 @@ impl_space_problem! {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EHeader<'a> {
|
||||
Provides(EProvides<'a>, Position),
|
||||
Params(EParams<'a>, Position),
|
||||
Exposes(EExposes, Position),
|
||||
Imports(EImports, Position),
|
||||
Requires(ERequires<'a>, Position),
|
||||
|
@ -149,6 +151,15 @@ pub enum EProvides<'a> {
|
|||
Space(BadInputError, Position),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum EParams<'a> {
|
||||
Pattern(PRecord<'a>, Position),
|
||||
BeforeArrow(Position),
|
||||
Arrow(Position),
|
||||
AfterArrow(Position),
|
||||
Space(BadInputError, Position),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EExposes {
|
||||
Exposes(Position),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ast::{Implements, Pattern, PatternAs, Spaceable};
|
||||
use crate::ast::{Collection, Implements, Pattern, PatternAs, Spaceable};
|
||||
use crate::blankspace::{space0_e, spaces, spaces_before};
|
||||
use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident};
|
||||
use crate::keyword;
|
||||
|
@ -468,15 +468,17 @@ fn lowercase_ident_pattern<'a>() -> impl Parser<'a, &'a str, EPattern<'a>> {
|
|||
|
||||
#[inline(always)]
|
||||
fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
|
||||
map!(
|
||||
collection_trailing_sep_e!(
|
||||
byte(b'{', PRecord::Open),
|
||||
record_pattern_field(),
|
||||
byte(b',', PRecord::End),
|
||||
byte(b'}', PRecord::End),
|
||||
Pattern::SpaceBefore
|
||||
),
|
||||
Pattern::RecordDestructure
|
||||
map!(record_pattern_fields(), Pattern::RecordDestructure)
|
||||
}
|
||||
|
||||
pub fn record_pattern_fields<'a>() -> impl Parser<'a, Collection<'a, Loc<Pattern<'a>>>, PRecord<'a>>
|
||||
{
|
||||
collection_trailing_sep_e!(
|
||||
byte(b'{', PRecord::Open),
|
||||
record_pattern_field(),
|
||||
byte(b',', PRecord::End),
|
||||
byte(b'}', PRecord::End),
|
||||
Pattern::SpaceBefore
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@ Module {
|
|||
comments: [],
|
||||
header: Module(
|
||||
ModuleHeader {
|
||||
before_exposes: [],
|
||||
after_keyword: [],
|
||||
params: None,
|
||||
exposes: [],
|
||||
interface_imports: None,
|
||||
},
|
||||
|
|
|
@ -2,7 +2,8 @@ Module {
|
|||
comments: [],
|
||||
header: Module(
|
||||
ModuleHeader {
|
||||
before_exposes: [],
|
||||
after_keyword: [],
|
||||
params: None,
|
||||
exposes: [
|
||||
@8-9 ExposedName(
|
||||
"a",
|
||||
|
|
|
@ -2,7 +2,8 @@ Module {
|
|||
comments: [],
|
||||
header: Module(
|
||||
ModuleHeader {
|
||||
before_exposes: [],
|
||||
after_keyword: [],
|
||||
params: None,
|
||||
exposes: [],
|
||||
interface_imports: None,
|
||||
},
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
module [menu]
|
|
@ -0,0 +1,28 @@
|
|||
Module {
|
||||
comments: [],
|
||||
header: Module(
|
||||
ModuleHeader {
|
||||
after_keyword: [],
|
||||
params: Some(
|
||||
ModuleParams {
|
||||
params: [
|
||||
@8-12 Identifier {
|
||||
ident: "echo",
|
||||
},
|
||||
@14-18 Identifier {
|
||||
ident: "read",
|
||||
},
|
||||
],
|
||||
before_arrow: [],
|
||||
after_arrow: [],
|
||||
},
|
||||
),
|
||||
exposes: [
|
||||
@26-30 ExposedName(
|
||||
"menu",
|
||||
),
|
||||
],
|
||||
interface_imports: None,
|
||||
},
|
||||
),
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
module {echo, read } -> [menu]
|
|
@ -2,7 +2,8 @@ Module {
|
|||
comments: [],
|
||||
header: Module(
|
||||
ModuleHeader {
|
||||
before_exposes: [],
|
||||
after_keyword: [],
|
||||
params: None,
|
||||
exposes: [
|
||||
@23-26 ExposedName(
|
||||
"Foo",
|
||||
|
|
|
@ -351,6 +351,7 @@ mod test_snapshots {
|
|||
pass/module_def_newline.moduledefs,
|
||||
pass/module_multiline_exposes.header,
|
||||
pass/module_with_newline.header,
|
||||
pass/module_with_params.header,
|
||||
pass/multi_backpassing.expr,
|
||||
pass/multi_backpassing_in_def.moduledefs,
|
||||
pass/multi_backpassing_with_apply.expr,
|
||||
|
|
|
@ -11,8 +11,9 @@ use roc_parse::{
|
|||
WhenBranch,
|
||||
},
|
||||
header::{
|
||||
AppHeader, ExposedName, HostedHeader, ImportsEntry, ModuleHeader, ModuleName, PackageEntry,
|
||||
PackageHeader, PackageName, PlatformHeader, PlatformRequires, ProvidesTo, To, TypedIdent,
|
||||
AppHeader, ExposedName, HostedHeader, ImportsEntry, ModuleHeader, ModuleName, ModuleParams,
|
||||
PackageEntry, PackageHeader, PackageName, PlatformHeader, PlatformRequires, ProvidesTo, To,
|
||||
TypedIdent,
|
||||
},
|
||||
ident::{Accessor, UppercaseIdent},
|
||||
};
|
||||
|
@ -213,12 +214,41 @@ impl IterTokens for Header<'_> {
|
|||
impl IterTokens for ModuleHeader<'_> {
|
||||
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
||||
let Self {
|
||||
before_exposes: _,
|
||||
after_keyword: _,
|
||||
params,
|
||||
exposes,
|
||||
interface_imports: _,
|
||||
} = self;
|
||||
|
||||
exposes.iter_tokens(arena)
|
||||
params
|
||||
.iter_tokens(arena)
|
||||
.into_iter()
|
||||
.chain(exposes.iter_tokens(arena))
|
||||
.collect_in(arena)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IterTokens for Option<T>
|
||||
where
|
||||
T: IterTokens,
|
||||
{
|
||||
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
||||
match self {
|
||||
Some(params) => params.iter_tokens(arena),
|
||||
None => bumpvec![in arena;],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IterTokens for ModuleParams<'_> {
|
||||
fn iter_tokens<'a>(&self, arena: &'a Bump) -> BumpVec<'a, Loc<Token>> {
|
||||
let Self {
|
||||
params,
|
||||
before_arrow: _,
|
||||
after_arrow: _,
|
||||
} = self;
|
||||
|
||||
params.iter_tokens(arena)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3392,6 +3392,8 @@ fn to_header_report<'a>(
|
|||
to_provides_report(alloc, lines, filename, provides, *pos)
|
||||
}
|
||||
|
||||
EHeader::Params(_params, _pos) => todo!(),
|
||||
|
||||
EHeader::Exposes(exposes, pos) => to_exposes_report(alloc, lines, filename, exposes, *pos),
|
||||
|
||||
EHeader::Imports(imports, pos) => to_imports_report(alloc, lines, filename, imports, *pos),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue