mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
Refactor Parser trait to pass min_indent
This removes the need to explicitly pass thru min_indent when using the parser combinators. My ultimate goal here is to evolve the current parser closer toward a purely combinator-based parser, at which point we can more easily transition smoothly to a formal(ish) grammar, or expand the meanings of combinators to include things like: * Incremental (re)parsing * Unified parsing and formatting code * Better error recovery * Using the main parser directly for syntax highlighting
This commit is contained in:
parent
ae1a9e4dd6
commit
07be8ec000
18 changed files with 704 additions and 844 deletions
|
@ -157,7 +157,9 @@ fn parse_all<'a>(arena: &'a Bump, src: &'a str) -> Result<Ast<'a>, SyntaxError<'
|
|||
let (module, state) = module::parse_header(arena, State::new(src.as_bytes()))
|
||||
.map_err(|e| SyntaxError::Header(e.problem))?;
|
||||
|
||||
let (_, defs, _) = module_defs().parse(arena, state).map_err(|(_, e, _)| e)?;
|
||||
let (_, defs, _) = module_defs()
|
||||
.parse(arena, state, 0)
|
||||
.map_err(|(_, e, _)| e)?;
|
||||
|
||||
Ok(Ast { module, defs })
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ mod test_fmt {
|
|||
) {
|
||||
fmt_module(buf, module);
|
||||
|
||||
match module_defs().parse(arena, state) {
|
||||
match module_defs().parse(arena, state, 0) {
|
||||
Ok((_, loc_defs, _)) => {
|
||||
fmt_defs(buf, &loc_defs, 0);
|
||||
}
|
||||
|
|
|
@ -4824,7 +4824,7 @@ fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, Loadi
|
|||
let parse_start = Instant::now();
|
||||
let source = header.parse_state.original_bytes();
|
||||
let parse_state = header.parse_state;
|
||||
let parsed_defs = match module_defs().parse(arena, parse_state) {
|
||||
let parsed_defs = match module_defs().parse(arena, parse_state, 0) {
|
||||
Ok((_, success, _state)) => success,
|
||||
Err((_, fail, state)) => {
|
||||
return Err(LoadingProblem::ParsingFailed(
|
||||
|
|
|
@ -23,8 +23,9 @@ pub fn criterion_benchmark(c: &mut Criterion) {
|
|||
let (_actual, state) =
|
||||
module::parse_header(&arena, State::new(src.as_bytes())).unwrap();
|
||||
|
||||
let min_indent = 0;
|
||||
let res = module_defs()
|
||||
.parse(&arena, state)
|
||||
.parse(&arena, state, min_indent)
|
||||
.map(|tuple| tuple.1)
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ use roc_region::all::Position;
|
|||
|
||||
pub fn space0_around_ee<'a, P, S, E>(
|
||||
parser: P,
|
||||
min_indent: u32,
|
||||
indent_before_problem: fn(Position) -> E,
|
||||
indent_after_problem: fn(Position) -> E,
|
||||
) -> impl Parser<'a, Loc<S>, E>
|
||||
|
@ -23,8 +22,8 @@ where
|
|||
{
|
||||
parser::map_with_arena(
|
||||
and(
|
||||
space0_e(min_indent, indent_before_problem),
|
||||
and(parser, space0_e(min_indent, indent_after_problem)),
|
||||
space0_e(indent_before_problem),
|
||||
and(parser, space0_e(indent_after_problem)),
|
||||
),
|
||||
spaces_around_help,
|
||||
)
|
||||
|
@ -32,7 +31,6 @@ where
|
|||
|
||||
pub fn space0_before_optional_after<'a, P, S, E>(
|
||||
parser: P,
|
||||
min_indent: u32,
|
||||
indent_before_problem: fn(Position) -> E,
|
||||
indent_after_problem: fn(Position) -> E,
|
||||
) -> impl Parser<'a, Loc<S>, E>
|
||||
|
@ -45,11 +43,11 @@ where
|
|||
{
|
||||
parser::map_with_arena(
|
||||
and(
|
||||
space0_e(min_indent, indent_before_problem),
|
||||
space0_e(indent_before_problem),
|
||||
and(
|
||||
parser,
|
||||
one_of![
|
||||
backtrackable(space0_e(min_indent, indent_after_problem)),
|
||||
backtrackable(space0_e(indent_after_problem)),
|
||||
succeed!(&[] as &[_]),
|
||||
],
|
||||
),
|
||||
|
@ -96,7 +94,6 @@ where
|
|||
|
||||
pub fn space0_before_e<'a, P, S, E>(
|
||||
parser: P,
|
||||
min_indent: u32,
|
||||
indent_problem: fn(Position) -> E,
|
||||
) -> impl Parser<'a, Loc<S>, E>
|
||||
where
|
||||
|
@ -107,7 +104,7 @@ where
|
|||
E: 'a + SpaceProblem,
|
||||
{
|
||||
parser::map_with_arena(
|
||||
and!(space0_e(min_indent, indent_problem), parser),
|
||||
and!(space0_e(indent_problem), parser),
|
||||
|arena: &'a Bump, (space_list, loc_expr): (&'a [CommentOrNewline<'a>], Loc<S>)| {
|
||||
if space_list.is_empty() {
|
||||
loc_expr
|
||||
|
@ -122,7 +119,6 @@ where
|
|||
|
||||
pub fn space0_after_e<'a, P, S, E>(
|
||||
parser: P,
|
||||
min_indent: u32,
|
||||
indent_problem: fn(Position) -> E,
|
||||
) -> impl Parser<'a, Loc<S>, E>
|
||||
where
|
||||
|
@ -133,7 +129,7 @@ where
|
|||
E: 'a + SpaceProblem,
|
||||
{
|
||||
parser::map_with_arena(
|
||||
and!(parser, space0_e(min_indent, indent_problem)),
|
||||
and!(parser, space0_e(indent_problem)),
|
||||
|arena: &'a Bump, (loc_expr, space_list): (Loc<S>, &'a [CommentOrNewline<'a>])| {
|
||||
if space_list.is_empty() {
|
||||
loc_expr
|
||||
|
@ -146,14 +142,11 @@ where
|
|||
)
|
||||
}
|
||||
|
||||
pub fn check_indent<'a, E>(
|
||||
min_indent: u32,
|
||||
indent_problem: fn(Position) -> E,
|
||||
) -> impl Parser<'a, (), E>
|
||||
pub fn check_indent<'a, E>(indent_problem: fn(Position) -> E) -> impl Parser<'a, (), E>
|
||||
where
|
||||
E: 'a,
|
||||
{
|
||||
move |_, state: State<'a>| {
|
||||
move |_, state: State<'a>, min_indent: u32| {
|
||||
if state.column() >= min_indent {
|
||||
Ok((NoProgress, (), state))
|
||||
} else {
|
||||
|
@ -163,24 +156,22 @@ where
|
|||
}
|
||||
|
||||
pub fn space0_e<'a, E>(
|
||||
min_indent: u32,
|
||||
indent_problem: fn(Position) -> E,
|
||||
) -> impl Parser<'a, &'a [CommentOrNewline<'a>], E>
|
||||
where
|
||||
E: 'a + SpaceProblem,
|
||||
{
|
||||
spaces_help_help(min_indent, indent_problem)
|
||||
spaces_help_help(indent_problem)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn spaces_help_help<'a, E>(
|
||||
min_indent: u32,
|
||||
indent_problem: fn(Position) -> E,
|
||||
) -> impl Parser<'a, &'a [CommentOrNewline<'a>], E>
|
||||
where
|
||||
E: 'a + SpaceProblem,
|
||||
{
|
||||
move |arena, state: State<'a>| match fast_eat_spaces(&state) {
|
||||
move |arena, state: State<'a>, min_indent: u32| match fast_eat_spaces(&state) {
|
||||
FastSpaceState::HasTab(position) => Err((
|
||||
MadeProgress,
|
||||
E::space_problem(BadInputError::HasTab, position),
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -270,24 +270,23 @@ pub struct PackageEntry<'a> {
|
|||
}
|
||||
|
||||
pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPackageEntry<'a>> {
|
||||
move |arena, state| {
|
||||
move |arena, state, min_indent| {
|
||||
// You may optionally have a package shorthand,
|
||||
// e.g. "uc" in `uc: roc/unicode 1.0.0`
|
||||
//
|
||||
// (Indirect dependencies don't have a shorthand.)
|
||||
let min_indent = 1;
|
||||
|
||||
let (_, opt_shorthand, state) = maybe!(and!(
|
||||
skip_second!(
|
||||
specialize(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()),
|
||||
word1(b':', EPackageEntry::Colon)
|
||||
),
|
||||
space0_e(min_indent, EPackageEntry::IndentPackage)
|
||||
space0_e(EPackageEntry::IndentPackage)
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, package_or_path, state) =
|
||||
loc!(specialize(EPackageEntry::BadPackage, package_name())).parse(arena, state)?;
|
||||
loc!(specialize(EPackageEntry::BadPackage, package_name()))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let entry = match opt_shorthand {
|
||||
Some((shorthand, spaces_after_shorthand)) => PackageEntry {
|
||||
|
@ -307,10 +306,10 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac
|
|||
}
|
||||
|
||||
pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
let pos = state.pos();
|
||||
specialize(EPackageName::BadPath, string_literal::parse())
|
||||
.parse(arena, state)
|
||||
.parse(arena, state, min_indent)
|
||||
.and_then(|(progress, text, next_state)| match text {
|
||||
StrLiteral::PlainLine(text) => Ok((progress, PackageName(text), next_state)),
|
||||
StrLiteral::Line(_) => Err((progress, EPackageName::Escapes(pos), next_state)),
|
||||
|
|
|
@ -84,7 +84,7 @@ impl<'a> Ident<'a> {
|
|||
/// * A record field, e.g. "email" in `.email` or in `email:`
|
||||
/// * A named pattern match, e.g. "foo" in `foo =` or `foo ->` or `\foo ->`
|
||||
pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
|
||||
move |_, state: State<'a>| match chomp_lowercase_part(state.bytes()) {
|
||||
move |_, state: State<'a>, _min_indent: u32| match chomp_lowercase_part(state.bytes()) {
|
||||
Err(progress) => Err((progress, (), state)),
|
||||
Ok(ident) => {
|
||||
if crate::keyword::KEYWORDS.iter().any(|kw| &ident == kw) {
|
||||
|
@ -98,7 +98,9 @@ pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
|
|||
}
|
||||
|
||||
pub fn tag_name<'a>() -> impl Parser<'a, &'a str, ()> {
|
||||
move |arena, state: State<'a>| uppercase_ident().parse(arena, state)
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
uppercase_ident().parse(arena, state, min_indent)
|
||||
}
|
||||
}
|
||||
|
||||
/// This could be:
|
||||
|
@ -107,7 +109,7 @@ pub fn tag_name<'a>() -> impl Parser<'a, &'a str, ()> {
|
|||
/// * A type name
|
||||
/// * A tag
|
||||
pub fn uppercase<'a>() -> impl Parser<'a, UppercaseIdent<'a>, ()> {
|
||||
move |_, state: State<'a>| match chomp_uppercase_part(state.bytes()) {
|
||||
move |_, state: State<'a>, _min_indent: u32| match chomp_uppercase_part(state.bytes()) {
|
||||
Err(progress) => Err((progress, (), state)),
|
||||
Ok(ident) => {
|
||||
let width = ident.len();
|
||||
|
@ -122,7 +124,7 @@ pub fn uppercase<'a>() -> impl Parser<'a, UppercaseIdent<'a>, ()> {
|
|||
/// * A type name
|
||||
/// * A tag
|
||||
pub fn uppercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
|
||||
move |_, state: State<'a>| match chomp_uppercase_part(state.bytes()) {
|
||||
move |_, state: State<'a>, _min_indent: u32| match chomp_uppercase_part(state.bytes()) {
|
||||
Err(progress) => Err((progress, (), state)),
|
||||
Ok(ident) => {
|
||||
let width = ident.len();
|
||||
|
@ -132,7 +134,10 @@ pub fn uppercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
|
|||
}
|
||||
|
||||
pub fn unqualified_ident<'a>() -> impl Parser<'a, &'a str, ()> {
|
||||
move |_, state: State<'a>| match chomp_part(|c| c.is_alphabetic(), state.bytes()) {
|
||||
move |_, state: State<'a>, _min_indent: u32| match chomp_part(
|
||||
|c| c.is_alphabetic(),
|
||||
state.bytes(),
|
||||
) {
|
||||
Err(progress) => Err((progress, (), state)),
|
||||
Ok(ident) => {
|
||||
if crate::keyword::KEYWORDS.iter().any(|kw| &ident == kw) {
|
||||
|
@ -151,7 +156,11 @@ macro_rules! advance_state {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn parse_ident<'a>(arena: &'a Bump, state: State<'a>) -> ParseResult<'a, Ident<'a>, EExpr<'a>> {
|
||||
pub fn parse_ident<'a>(
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
_min_indent: u32,
|
||||
) -> ParseResult<'a, Ident<'a>, EExpr<'a>> {
|
||||
let initial = state.clone();
|
||||
|
||||
match parse_ident_help(arena, state) {
|
||||
|
@ -456,7 +465,7 @@ fn chomp_module_chain(buffer: &[u8]) -> Result<u32, Progress> {
|
|||
}
|
||||
|
||||
pub fn concrete_type<'a>() -> impl Parser<'a, (&'a str, &'a str), ()> {
|
||||
move |_, state: State<'a>| match chomp_concrete_type(state.bytes()) {
|
||||
move |_, state: State<'a>, _min_indent: u32| match chomp_concrete_type(state.bytes()) {
|
||||
Err(progress) => Err((progress, (), state)),
|
||||
Ok((module_name, type_name, width)) => {
|
||||
Ok((MadeProgress, (module_name, type_name), state.advance(width)))
|
||||
|
|
|
@ -7,9 +7,9 @@ use crate::header::{
|
|||
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent};
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{
|
||||
backtrackable, optional, specialize, specialize_region, word1, EExposes, EGenerates,
|
||||
EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser,
|
||||
SourceError, SpaceProblem, SyntaxError,
|
||||
backtrackable, increment_min_indent, optional, reset_min_indent, specialize, specialize_region,
|
||||
word1, EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides,
|
||||
ERequires, ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
|
||||
};
|
||||
use crate::state::State;
|
||||
use crate::string_literal;
|
||||
|
@ -17,7 +17,7 @@ use crate::type_annotation;
|
|||
use roc_region::all::{Loc, Position};
|
||||
|
||||
fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|
||||
|_arena, state: State<'a>| {
|
||||
|_arena, state: State<'a>, _min_indent: u32| {
|
||||
if state.has_reached_end() {
|
||||
Ok((NoProgress, (), state))
|
||||
} else {
|
||||
|
@ -28,11 +28,10 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn module_defs<'a>() -> impl Parser<'a, Defs<'a>, SyntaxError<'a>> {
|
||||
let min_indent = 0;
|
||||
skip_second!(
|
||||
specialize_region(
|
||||
|e, r| SyntaxError::Expr(e, r.start()),
|
||||
crate::expr::toplevel_defs(min_indent),
|
||||
crate::expr::toplevel_defs(),
|
||||
),
|
||||
end_of_file()
|
||||
)
|
||||
|
@ -42,7 +41,8 @@ pub fn parse_header<'a>(
|
|||
arena: &'a bumpalo::Bump,
|
||||
state: State<'a>,
|
||||
) -> Result<(Module<'a>, State<'a>), SourceError<'a, EHeader<'a>>> {
|
||||
match header().parse(arena, state) {
|
||||
let min_indent = 0;
|
||||
match header().parse(arena, state, min_indent) {
|
||||
Ok((_, module, state)) => Ok((module, state)),
|
||||
Err((_, fail, state)) => Err(SourceError::new(fail, &state)),
|
||||
}
|
||||
|
@ -55,10 +55,13 @@ fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
|||
|
||||
map!(
|
||||
and!(
|
||||
space0_e(0, EHeader::IndentStart),
|
||||
space0_e(EHeader::IndentStart),
|
||||
one_of![
|
||||
map!(
|
||||
skip_first!(keyword_e("interface", EHeader::Start), interface_header()),
|
||||
skip_first!(
|
||||
keyword_e("interface", EHeader::Start),
|
||||
increment_min_indent(interface_header())
|
||||
),
|
||||
|mut header: InterfaceHeader<'a>| -> Clos<'a> {
|
||||
Box::new(|spaces| {
|
||||
header.before_header = spaces;
|
||||
|
@ -67,7 +70,10 @@ fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
|||
}
|
||||
),
|
||||
map!(
|
||||
skip_first!(keyword_e("app", EHeader::Start), app_header()),
|
||||
skip_first!(
|
||||
keyword_e("app", EHeader::Start),
|
||||
increment_min_indent(app_header())
|
||||
),
|
||||
|mut header: AppHeader<'a>| -> Clos<'a> {
|
||||
Box::new(|spaces| {
|
||||
header.before_header = spaces;
|
||||
|
@ -76,7 +82,10 @@ fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
|||
}
|
||||
),
|
||||
map!(
|
||||
skip_first!(keyword_e("platform", EHeader::Start), platform_header()),
|
||||
skip_first!(
|
||||
keyword_e("platform", EHeader::Start),
|
||||
increment_min_indent(platform_header())
|
||||
),
|
||||
|mut header: PlatformHeader<'a>| -> Clos<'a> {
|
||||
Box::new(|spaces| {
|
||||
header.before_header = spaces;
|
||||
|
@ -85,7 +94,10 @@ fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
|||
}
|
||||
),
|
||||
map!(
|
||||
skip_first!(keyword_e("hosted", EHeader::Start), hosted_header()),
|
||||
skip_first!(
|
||||
keyword_e("hosted", EHeader::Start),
|
||||
increment_min_indent(hosted_header())
|
||||
),
|
||||
|mut header: HostedHeader<'a>| -> Clos<'a> {
|
||||
Box::new(|spaces| {
|
||||
header.before_header = spaces;
|
||||
|
@ -101,17 +113,16 @@ fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
|||
|
||||
#[inline(always)]
|
||||
fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>, EHeader<'a>> {
|
||||
|arena, state| {
|
||||
let min_indent = 1;
|
||||
|
||||
|arena, state, min_indent: u32| {
|
||||
let (_, after_interface_keyword, state) =
|
||||
space0_e(min_indent, EHeader::IndentStart).parse(arena, state)?;
|
||||
let (_, name, state) = loc!(module_name_help(EHeader::ModuleName)).parse(arena, state)?;
|
||||
space0_e(EHeader::IndentStart).parse(arena, state, min_indent)?;
|
||||
let (_, name, state) =
|
||||
loc!(module_name_help(EHeader::ModuleName)).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, ((before_exposes, after_exposes), exposes), state) =
|
||||
specialize(EHeader::Exposes, exposes_values()).parse(arena, state)?;
|
||||
specialize(EHeader::Exposes, exposes_values()).parse(arena, state, min_indent)?;
|
||||
let (_, ((before_imports, after_imports), imports), state) =
|
||||
specialize(EHeader::Imports, imports()).parse(arena, state)?;
|
||||
specialize(EHeader::Imports, imports()).parse(arena, state, min_indent)?;
|
||||
|
||||
let header = InterfaceHeader {
|
||||
name,
|
||||
|
@ -131,21 +142,20 @@ 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;
|
||||
|
||||
|arena, state, min_indent: u32| {
|
||||
let (_, after_hosted_keyword, state) =
|
||||
space0_e(min_indent, EHeader::IndentStart).parse(arena, state)?;
|
||||
let (_, name, state) = loc!(module_name_help(EHeader::ModuleName)).parse(arena, state)?;
|
||||
space0_e(EHeader::IndentStart).parse(arena, state, min_indent)?;
|
||||
let (_, name, state) =
|
||||
loc!(module_name_help(EHeader::ModuleName)).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, ((before_exposes, after_exposes), exposes), state) =
|
||||
specialize(EHeader::Exposes, exposes_values()).parse(arena, state)?;
|
||||
specialize(EHeader::Exposes, exposes_values()).parse(arena, state, min_indent)?;
|
||||
let (_, ((before_imports, after_imports), imports), state) =
|
||||
specialize(EHeader::Imports, imports()).parse(arena, state)?;
|
||||
specialize(EHeader::Imports, imports()).parse(arena, state, min_indent)?;
|
||||
let (_, ((before_generates, after_generates), generates), state) =
|
||||
specialize(EHeader::Generates, generates()).parse(arena, state)?;
|
||||
specialize(EHeader::Generates, generates()).parse(arena, state, min_indent)?;
|
||||
let (_, ((before_with, after_with), generates_with), state) =
|
||||
specialize(EHeader::GeneratesWith, generates_with()).parse(arena, state)?;
|
||||
specialize(EHeader::GeneratesWith, generates_with()).parse(arena, state, min_indent)?;
|
||||
|
||||
let header = HostedHeader {
|
||||
name,
|
||||
|
@ -217,7 +227,7 @@ fn chomp_module_name(buffer: &[u8]) -> Result<&str, Progress> {
|
|||
|
||||
#[inline(always)]
|
||||
fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>, ()> {
|
||||
|_, mut state: State<'a>| match chomp_module_name(state.bytes()) {
|
||||
|_, mut state: State<'a>, _min_indent: u32| match chomp_module_name(state.bytes()) {
|
||||
Ok(name) => {
|
||||
let width = name.len();
|
||||
state = state.advance(width);
|
||||
|
@ -230,23 +240,21 @@ fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>, ()> {
|
|||
|
||||
#[inline(always)]
|
||||
fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
||||
|arena, state| {
|
||||
let min_indent = 1;
|
||||
|
||||
|arena, state, min_indent: u32| {
|
||||
let (_, after_app_keyword, state) =
|
||||
space0_e(min_indent, EHeader::IndentStart).parse(arena, state)?;
|
||||
space0_e(EHeader::IndentStart).parse(arena, state, min_indent)?;
|
||||
let (_, name, state) = loc!(crate::parser::specialize(
|
||||
EHeader::AppName,
|
||||
string_literal::parse()
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, opt_pkgs, state) =
|
||||
maybe!(specialize(EHeader::Packages, packages())).parse(arena, state)?;
|
||||
maybe!(specialize(EHeader::Packages, packages())).parse(arena, state, min_indent)?;
|
||||
let (_, opt_imports, state) =
|
||||
maybe!(specialize(EHeader::Imports, imports())).parse(arena, state)?;
|
||||
maybe!(specialize(EHeader::Imports, imports())).parse(arena, state, min_indent)?;
|
||||
let (_, provides, state) =
|
||||
specialize(EHeader::Provides, provides_to()).parse(arena, state)?;
|
||||
specialize(EHeader::Provides, provides_to()).parse(arena, state, min_indent)?;
|
||||
|
||||
let (before_packages, after_packages, packages) = match opt_pkgs {
|
||||
Some(pkgs) => {
|
||||
|
@ -297,27 +305,26 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
|||
|
||||
#[inline(always)]
|
||||
fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
||||
|arena, state| {
|
||||
let min_indent = 1;
|
||||
|
||||
|arena, state, min_indent: u32| {
|
||||
let (_, after_platform_keyword, state) =
|
||||
space0_e(min_indent, EHeader::IndentStart).parse(arena, state)?;
|
||||
let (_, name, state) =
|
||||
loc!(specialize(EHeader::PlatformName, package_name())).parse(arena, state)?;
|
||||
space0_e(EHeader::IndentStart).parse(arena, state, min_indent)?;
|
||||
let (_, name, state) = loc!(specialize(EHeader::PlatformName, package_name()))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, ((before_requires, after_requires), requires), state) =
|
||||
specialize(EHeader::Requires, requires()).parse(arena, state)?;
|
||||
specialize(EHeader::Requires, requires()).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, ((before_exposes, after_exposes), exposes), state) =
|
||||
specialize(EHeader::Exposes, exposes_modules()).parse(arena, state)?;
|
||||
specialize(EHeader::Exposes, exposes_modules()).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, packages, state) = specialize(EHeader::Packages, packages()).parse(arena, state)?;
|
||||
let (_, packages, state) =
|
||||
specialize(EHeader::Packages, packages()).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, ((before_imports, after_imports), imports), state) =
|
||||
specialize(EHeader::Imports, imports()).parse(arena, state)?;
|
||||
specialize(EHeader::Imports, imports()).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, ((before_provides, after_provides), (provides, _provides_type)), state) =
|
||||
specialize(EHeader::Provides, provides_without_to()).parse(arena, state)?;
|
||||
specialize(EHeader::Provides, provides_without_to()).parse(arena, state, min_indent)?;
|
||||
|
||||
let header = PlatformHeader {
|
||||
name,
|
||||
|
@ -368,14 +375,11 @@ fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
|
|||
|
||||
#[inline(always)]
|
||||
fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> {
|
||||
let min_indent = 1;
|
||||
|
||||
map!(
|
||||
and!(
|
||||
provides_without_to(),
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
"to",
|
||||
EProvides::To,
|
||||
EProvides::IndentTo,
|
||||
|
@ -413,10 +417,8 @@ fn provides_without_to<'a>() -> impl Parser<
|
|||
),
|
||||
EProvides<'a>,
|
||||
> {
|
||||
let min_indent = 1;
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
"provides",
|
||||
EProvides::Provides,
|
||||
EProvides::IndentProvides,
|
||||
|
@ -428,7 +430,6 @@ fn provides_without_to<'a>() -> impl Parser<
|
|||
exposes_entry(EProvides::Identifier),
|
||||
word1(b',', EProvides::ListEnd),
|
||||
word1(b']', EProvides::ListEnd),
|
||||
min_indent,
|
||||
EProvides::Open,
|
||||
EProvides::IndentListEnd,
|
||||
Spaced::SpaceBefore
|
||||
|
@ -442,8 +443,6 @@ fn provides_without_to<'a>() -> impl Parser<
|
|||
#[inline(always)]
|
||||
fn provides_types<'a>(
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, EProvides<'a>> {
|
||||
let min_indent = 1;
|
||||
|
||||
skip_first!(
|
||||
// We only support spaces here, not newlines, because this is not intended
|
||||
// to be the design forever. Someday it will hopefully work like Elm,
|
||||
|
@ -461,7 +460,6 @@ fn provides_types<'a>(
|
|||
provides_type_entry(EProvides::Identifier),
|
||||
word1(b',', EProvides::ListEnd),
|
||||
word1(b'}', EProvides::ListEnd),
|
||||
min_indent,
|
||||
EProvides::Open,
|
||||
EProvides::IndentListEnd,
|
||||
Spaced::SpaceBefore
|
||||
|
@ -506,10 +504,8 @@ fn requires<'a>() -> impl Parser<
|
|||
),
|
||||
ERequires<'a>,
|
||||
> {
|
||||
let min_indent = 0;
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
"requires",
|
||||
ERequires::Requires,
|
||||
ERequires::IndentRequires,
|
||||
|
@ -523,7 +519,7 @@ fn requires<'a>() -> impl Parser<
|
|||
fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a>> {
|
||||
map!(
|
||||
and!(
|
||||
skip_second!(requires_rigids(0), space0_e(0, ERequires::ListStart)),
|
||||
skip_second!(requires_rigids(), space0_e(ERequires::ListStart)),
|
||||
requires_typed_ident()
|
||||
),
|
||||
|(rigids, signature)| { PlatformRequires { rigids, signature } }
|
||||
|
@ -532,7 +528,6 @@ fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a
|
|||
|
||||
#[inline(always)]
|
||||
fn requires_rigids<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, ERequires<'a>> {
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'{', ERequires::ListStart),
|
||||
|
@ -542,7 +537,6 @@ fn requires_rigids<'a>(
|
|||
),
|
||||
word1(b',', ERequires::ListEnd),
|
||||
word1(b'}', ERequires::ListEnd),
|
||||
min_indent,
|
||||
ERequires::Open,
|
||||
ERequires::IndentListEnd,
|
||||
Spaced::SpaceBefore
|
||||
|
@ -554,12 +548,11 @@ fn requires_typed_ident<'a>() -> impl Parser<'a, Loc<Spaced<'a, TypedIdent<'a>>>
|
|||
skip_first!(
|
||||
word1(b'{', ERequires::ListStart),
|
||||
skip_second!(
|
||||
space0_around_ee(
|
||||
reset_min_indent(space0_around_ee(
|
||||
specialize(ERequires::TypedIdent, loc!(typed_ident()),),
|
||||
0,
|
||||
ERequires::ListStart,
|
||||
ERequires::ListEnd
|
||||
),
|
||||
)),
|
||||
word1(b'}', ERequires::ListStart)
|
||||
)
|
||||
)
|
||||
|
@ -574,11 +567,8 @@ fn exposes_values<'a>() -> impl Parser<
|
|||
),
|
||||
EExposes,
|
||||
> {
|
||||
let min_indent = 1;
|
||||
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
"exposes",
|
||||
EExposes::Exposes,
|
||||
EExposes::IndentExposes,
|
||||
|
@ -589,7 +579,6 @@ fn exposes_values<'a>() -> impl Parser<
|
|||
exposes_entry(EExposes::Identifier),
|
||||
word1(b',', EExposes::ListEnd),
|
||||
word1(b']', EExposes::ListEnd),
|
||||
min_indent,
|
||||
EExposes::Open,
|
||||
EExposes::IndentListEnd,
|
||||
Spaced::SpaceBefore
|
||||
|
@ -598,7 +587,6 @@ fn exposes_values<'a>() -> impl Parser<
|
|||
}
|
||||
|
||||
fn spaces_around_keyword<'a, E>(
|
||||
min_indent: u32,
|
||||
keyword: &'static str,
|
||||
expectation: fn(Position) -> E,
|
||||
indent_problem1: fn(Position) -> E,
|
||||
|
@ -609,10 +597,10 @@ where
|
|||
{
|
||||
and!(
|
||||
skip_second!(
|
||||
backtrackable(space0_e(min_indent, indent_problem1)),
|
||||
backtrackable(space0_e(indent_problem1)),
|
||||
crate::parser::keyword_e(keyword, expectation)
|
||||
),
|
||||
space0_e(min_indent, indent_problem2)
|
||||
space0_e(indent_problem2)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -625,11 +613,8 @@ fn exposes_modules<'a>() -> impl Parser<
|
|||
),
|
||||
EExposes,
|
||||
> {
|
||||
let min_indent = 1;
|
||||
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
"exposes",
|
||||
EExposes::Exposes,
|
||||
EExposes::IndentExposes,
|
||||
|
@ -640,7 +625,6 @@ fn exposes_modules<'a>() -> impl Parser<
|
|||
exposes_module(EExposes::Identifier),
|
||||
word1(b',', EExposes::ListEnd),
|
||||
word1(b']', EExposes::ListEnd),
|
||||
min_indent,
|
||||
EExposes::Open,
|
||||
EExposes::IndentListEnd,
|
||||
Spaced::SpaceBefore
|
||||
|
@ -671,12 +655,9 @@ struct Packages<'a> {
|
|||
|
||||
#[inline(always)]
|
||||
fn packages<'a>() -> impl Parser<'a, Packages<'a>, EPackages<'a>> {
|
||||
let min_indent = 1;
|
||||
|
||||
map!(
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
"packages",
|
||||
EPackages::Packages,
|
||||
EPackages::IndentPackages,
|
||||
|
@ -687,7 +668,6 @@ fn packages<'a>() -> impl Parser<'a, Packages<'a>, EPackages<'a>> {
|
|||
specialize(EPackages::PackageEntry, loc!(package_entry())),
|
||||
word1(b',', EPackages::ListEnd),
|
||||
word1(b'}', EPackages::ListEnd),
|
||||
min_indent,
|
||||
EPackages::Open,
|
||||
EPackages::IndentListEnd,
|
||||
Spaced::SpaceBefore
|
||||
|
@ -715,11 +695,8 @@ fn generates<'a>() -> impl Parser<
|
|||
),
|
||||
EGenerates,
|
||||
> {
|
||||
let min_indent = 1;
|
||||
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
"generates",
|
||||
EGenerates::Generates,
|
||||
EGenerates::IndentGenerates,
|
||||
|
@ -738,11 +715,8 @@ fn generates_with<'a>() -> impl Parser<
|
|||
),
|
||||
EGeneratesWith,
|
||||
> {
|
||||
let min_indent = 1;
|
||||
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
"with",
|
||||
EGeneratesWith::With,
|
||||
EGeneratesWith::IndentWith,
|
||||
|
@ -753,7 +727,6 @@ fn generates_with<'a>() -> impl Parser<
|
|||
exposes_entry(EGeneratesWith::Identifier),
|
||||
word1(b',', EGeneratesWith::ListEnd),
|
||||
word1(b']', EGeneratesWith::ListEnd),
|
||||
min_indent,
|
||||
EGeneratesWith::Open,
|
||||
EGeneratesWith::IndentListEnd,
|
||||
Spaced::SpaceBefore
|
||||
|
@ -770,11 +743,8 @@ fn imports<'a>() -> impl Parser<
|
|||
),
|
||||
EImports,
|
||||
> {
|
||||
let min_indent = 1;
|
||||
|
||||
and!(
|
||||
spaces_around_keyword(
|
||||
min_indent,
|
||||
"imports",
|
||||
EImports::Imports,
|
||||
EImports::IndentImports,
|
||||
|
@ -785,7 +755,6 @@ fn imports<'a>() -> impl Parser<
|
|||
loc!(imports_entry()),
|
||||
word1(b',', EImports::ListEnd),
|
||||
word1(b']', EImports::ListEnd),
|
||||
min_indent,
|
||||
EImports::Open,
|
||||
EImports::IndentListEnd,
|
||||
Spaced::SpaceBefore
|
||||
|
@ -798,8 +767,6 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
|
|||
// e.g.
|
||||
//
|
||||
// printLine : Str -> Effect {}
|
||||
let min_indent = 0;
|
||||
|
||||
map!(
|
||||
and!(
|
||||
and!(
|
||||
|
@ -807,16 +774,15 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
|
|||
|_, pos| ETypedIdent::Identifier(pos),
|
||||
lowercase_ident()
|
||||
)),
|
||||
space0_e(min_indent, ETypedIdent::IndentHasType)
|
||||
space0_e(ETypedIdent::IndentHasType)
|
||||
),
|
||||
skip_first!(
|
||||
word1(b':', ETypedIdent::HasType),
|
||||
space0_before_e(
|
||||
specialize(
|
||||
ETypedIdent::Type,
|
||||
type_annotation::located(min_indent, true)
|
||||
reset_min_indent(type_annotation::located(true))
|
||||
),
|
||||
min_indent,
|
||||
ETypedIdent::IndentType,
|
||||
)
|
||||
)
|
||||
|
@ -846,8 +812,6 @@ where
|
|||
|
||||
#[inline(always)]
|
||||
fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports> {
|
||||
let min_indent = 1;
|
||||
|
||||
type Temp<'a> = (
|
||||
(Option<&'a str>, ModuleName<'a>),
|
||||
Option<Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>>,
|
||||
|
@ -872,7 +836,6 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports
|
|||
exposes_entry(EImports::Identifier),
|
||||
word1(b',', EImports::SetEnd),
|
||||
word1(b'}', EImports::SetEnd),
|
||||
min_indent,
|
||||
EImports::Open,
|
||||
EImports::IndentSetEnd,
|
||||
Spaced::SpaceBefore
|
||||
|
|
|
@ -13,7 +13,7 @@ pub enum NumLiteral<'a> {
|
|||
}
|
||||
|
||||
pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber> {
|
||||
move |_arena, state: State<'a>| {
|
||||
move |_arena, state: State<'a>, _min_indent: u32| {
|
||||
match state.bytes().first() {
|
||||
Some(first_byte) if (*first_byte as char).is_ascii_digit() => {
|
||||
parse_number_base(false, state.bytes(), state)
|
||||
|
@ -27,7 +27,7 @@ pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber>
|
|||
}
|
||||
|
||||
pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber> {
|
||||
move |_arena, state: State<'a>| {
|
||||
move |_arena, state: State<'a>, _min_indent: u32| {
|
||||
match state.bytes().first() {
|
||||
Some(first_byte) if *first_byte == b'-' => {
|
||||
// drop the minus
|
||||
|
|
|
@ -729,7 +729,12 @@ pub struct FileError<'a, T> {
|
|||
}
|
||||
|
||||
pub trait Parser<'a, Output, Error> {
|
||||
fn parse(&self, _: &'a Bump, _: State<'a>) -> ParseResult<'a, Output, Error>;
|
||||
fn parse(
|
||||
&self,
|
||||
alloc: &'a Bump,
|
||||
state: State<'a>,
|
||||
min_indent: u32,
|
||||
) -> ParseResult<'a, Output, Error>;
|
||||
|
||||
#[cfg(not(feature = "parse_debug_trace"))]
|
||||
fn trace(self, _message: &'static str) -> Self
|
||||
|
@ -759,10 +764,15 @@ pub trait Parser<'a, Output, Error> {
|
|||
impl<'a, F, Output, Error> Parser<'a, Output, Error> for F
|
||||
where
|
||||
Error: 'a,
|
||||
F: Fn(&'a Bump, State<'a>) -> ParseResult<'a, Output, Error>,
|
||||
F: Fn(&'a Bump, State<'a>, u32) -> ParseResult<'a, Output, Error>,
|
||||
{
|
||||
fn parse(&self, arena: &'a Bump, state: State<'a>) -> ParseResult<'a, Output, Error> {
|
||||
self(arena, state)
|
||||
fn parse(
|
||||
&self,
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
min_indent: u32,
|
||||
) -> ParseResult<'a, Output, Error> {
|
||||
self(arena, state, min_indent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -800,7 +810,7 @@ where
|
|||
);
|
||||
|
||||
INDENT.with(|i| *i.borrow_mut() += 1);
|
||||
let res = self.parser.parse(arena, state);
|
||||
let res = self.parser.parse(arena, state, min_indent);
|
||||
INDENT.with(|i| *i.borrow_mut() = cur_indent);
|
||||
|
||||
let (progress, value, state) = match &res {
|
||||
|
@ -827,8 +837,8 @@ where
|
|||
P: Parser<'a, Val, Error>,
|
||||
Val: 'a,
|
||||
{
|
||||
move |arena, state: State<'a>| {
|
||||
let (progress, answer, state) = parser.parse(arena, state)?;
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
let (progress, answer, state) = parser.parse(arena, state, min_indent)?;
|
||||
|
||||
Ok((progress, &*arena.alloc(answer), state))
|
||||
}
|
||||
|
@ -844,11 +854,11 @@ where
|
|||
F: Fn(Progress, Before) -> P2,
|
||||
Error: 'a,
|
||||
{
|
||||
move |arena, state| {
|
||||
move |arena, state, min_indent| {
|
||||
parser
|
||||
.parse(arena, state)
|
||||
.parse(arena, state, min_indent)
|
||||
.and_then(|(progress, output, next_state)| {
|
||||
transform(progress, output).parse(arena, next_state)
|
||||
transform(progress, output).parse(arena, next_state, min_indent)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -858,13 +868,13 @@ where
|
|||
P1: Parser<'a, Before, E>,
|
||||
After: 'a,
|
||||
E: 'a,
|
||||
F: Fn(&'a Bump, State<'a>, Progress, Before) -> ParseResult<'a, After, E>,
|
||||
F: Fn(&'a Bump, State<'a>, Progress, Before, u32) -> ParseResult<'a, After, E>,
|
||||
{
|
||||
move |arena, state| {
|
||||
move |arena, state, min_indent| {
|
||||
parser
|
||||
.parse(arena, state)
|
||||
.parse(arena, state, min_indent)
|
||||
.and_then(|(progress, output, next_state)| {
|
||||
transform(arena, next_state, progress, output)
|
||||
transform(arena, next_state, progress, output, min_indent)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -874,7 +884,7 @@ where
|
|||
ToError: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
move |_, mut state: State<'a>| {
|
||||
move |_, mut state: State<'a>, _min_indent| {
|
||||
let width = keyword.len();
|
||||
|
||||
if !state.bytes().starts_with(keyword.as_bytes()) {
|
||||
|
@ -908,10 +918,10 @@ where
|
|||
P: Parser<'a, Val, Error>,
|
||||
Error: 'a,
|
||||
{
|
||||
move |arena, state: State<'a>| {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
let start_bytes_len = state.bytes().len();
|
||||
|
||||
match parser.parse(arena, state) {
|
||||
match parser.parse(arena, state, min_indent) {
|
||||
Ok((elem_progress, first_output, next_state)) => {
|
||||
// in practice, we want elements to make progress
|
||||
debug_assert_eq!(elem_progress, MadeProgress);
|
||||
|
@ -922,10 +932,10 @@ where
|
|||
buf.push(first_output);
|
||||
|
||||
loop {
|
||||
match delimiter.parse(arena, state) {
|
||||
match delimiter.parse(arena, state, min_indent) {
|
||||
Ok((_, (), next_state)) => {
|
||||
// If the delimiter passed, check the element parser.
|
||||
match parser.parse(arena, next_state) {
|
||||
match parser.parse(arena, next_state, min_indent) {
|
||||
Ok((element_progress, next_output, next_state)) => {
|
||||
// in practice, we want elements to make progress
|
||||
debug_assert_eq!(element_progress, MadeProgress);
|
||||
|
@ -971,10 +981,10 @@ where
|
|||
P: Parser<'a, Val, Error>,
|
||||
Error: 'a,
|
||||
{
|
||||
move |arena, state: State<'a>| {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
let start_bytes_len = state.bytes().len();
|
||||
|
||||
match parser.parse(arena, state) {
|
||||
match parser.parse(arena, state, min_indent) {
|
||||
Ok((progress, first_output, next_state)) => {
|
||||
// in practice, we want elements to make progress
|
||||
debug_assert_eq!(progress, MadeProgress);
|
||||
|
@ -984,10 +994,10 @@ where
|
|||
buf.push(first_output);
|
||||
|
||||
loop {
|
||||
match delimiter.parse(arena, state) {
|
||||
match delimiter.parse(arena, state, min_indent) {
|
||||
Ok((_, (), next_state)) => {
|
||||
// If the delimiter passed, check the element parser.
|
||||
match parser.parse(arena, next_state) {
|
||||
match parser.parse(arena, next_state, min_indent) {
|
||||
Ok((element_progress, next_output, next_state)) => {
|
||||
// in practice, we want elements to make progress
|
||||
debug_assert_eq!(element_progress, MadeProgress);
|
||||
|
@ -1032,10 +1042,10 @@ where
|
|||
P: Parser<'a, Val, Error>,
|
||||
Error: 'a,
|
||||
{
|
||||
move |arena, state: State<'a>| {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
let start_bytes_len = state.bytes().len();
|
||||
|
||||
match parser.parse(arena, state) {
|
||||
match parser.parse(arena, state, min_indent) {
|
||||
Ok((progress, first_output, next_state)) => {
|
||||
debug_assert_eq!(progress, MadeProgress);
|
||||
let mut state = next_state;
|
||||
|
@ -1044,10 +1054,10 @@ where
|
|||
buf.push(first_output);
|
||||
|
||||
loop {
|
||||
match delimiter.parse(arena, state) {
|
||||
match delimiter.parse(arena, state, min_indent) {
|
||||
Ok((_, (), next_state)) => {
|
||||
// If the delimiter passed, check the element parser.
|
||||
match parser.parse(arena, next_state) {
|
||||
match parser.parse(arena, next_state, min_indent) {
|
||||
Ok((_, next_output, next_state)) => {
|
||||
state = next_state;
|
||||
buf.push(next_output);
|
||||
|
@ -1093,10 +1103,10 @@ where
|
|||
V: Fn(Position) -> Error,
|
||||
Error: 'a,
|
||||
{
|
||||
move |arena, state: State<'a>| {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
let start_bytes_len = state.bytes().len();
|
||||
|
||||
match parser.parse(arena, state) {
|
||||
match parser.parse(arena, state, min_indent) {
|
||||
Ok((progress, first_output, next_state)) => {
|
||||
debug_assert_eq!(progress, MadeProgress);
|
||||
let mut state = next_state;
|
||||
|
@ -1105,10 +1115,10 @@ where
|
|||
buf.push(first_output);
|
||||
|
||||
loop {
|
||||
match delimiter.parse(arena, state) {
|
||||
match delimiter.parse(arena, state, min_indent) {
|
||||
Ok((_, (), next_state)) => {
|
||||
// If the delimiter passed, check the element parser.
|
||||
match parser.parse(arena, next_state) {
|
||||
match parser.parse(arena, next_state, min_indent) {
|
||||
Ok((_, next_output, next_state)) => {
|
||||
state = next_state;
|
||||
buf.push(next_output);
|
||||
|
@ -1165,12 +1175,12 @@ where
|
|||
P: Parser<'a, T, E>,
|
||||
E: 'a,
|
||||
{
|
||||
move |arena: &'a Bump, state: State<'a>| {
|
||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
// We have to clone this because if the optional parser fails,
|
||||
// we need to revert back to the original state.
|
||||
let original_state = state.clone();
|
||||
|
||||
match parser.parse(arena, state) {
|
||||
match parser.parse(arena, state, min_indent) {
|
||||
Ok((progress, out1, state)) => Ok((progress, Some(out1), state)),
|
||||
Err((_, _, _)) => {
|
||||
// NOTE this will backtrack
|
||||
|
@ -1189,12 +1199,12 @@ where
|
|||
#[macro_export]
|
||||
macro_rules! loc {
|
||||
($parser:expr) => {
|
||||
move |arena, state: $crate::state::State<'a>| {
|
||||
move |arena, state: $crate::state::State<'a>, min_indent: u32| {
|
||||
use roc_region::all::{Loc, Region};
|
||||
|
||||
let start = state.pos();
|
||||
|
||||
match $parser.parse(arena, state) {
|
||||
match $parser.parse(arena, state, min_indent) {
|
||||
Ok((progress, value, state)) => {
|
||||
let end = state.pos();
|
||||
let region = Region::new(start, end);
|
||||
|
@ -1211,11 +1221,11 @@ macro_rules! loc {
|
|||
#[macro_export]
|
||||
macro_rules! skip_first {
|
||||
($p1:expr, $p2:expr) => {
|
||||
move |arena, state: $crate::state::State<'a>| {
|
||||
move |arena, state: $crate::state::State<'a>, min_indent: u32| {
|
||||
let original_state = state.clone();
|
||||
|
||||
match $p1.parse(arena, state) {
|
||||
Ok((p1, _, state)) => match $p2.parse(arena, state) {
|
||||
match $p1.parse(arena, state, min_indent) {
|
||||
Ok((p1, _, state)) => match $p2.parse(arena, state, min_indent) {
|
||||
Ok((p2, out2, state)) => Ok((p1.or(p2), out2, state)),
|
||||
Err((p2, fail, _)) => Err((p1.or(p2), fail, original_state)),
|
||||
},
|
||||
|
@ -1230,11 +1240,11 @@ macro_rules! skip_first {
|
|||
#[macro_export]
|
||||
macro_rules! skip_second {
|
||||
($p1:expr, $p2:expr) => {
|
||||
move |arena, state: $crate::state::State<'a>| {
|
||||
move |arena, state: $crate::state::State<'a>, min_indent: u32| {
|
||||
let original_state = state.clone();
|
||||
|
||||
match $p1.parse(arena, state) {
|
||||
Ok((p1, out1, state)) => match $p2.parse(arena, state) {
|
||||
match $p1.parse(arena, state, min_indent) {
|
||||
Ok((p1, out1, state)) => match $p2.parse(arena, state, min_indent) {
|
||||
Ok((p2, _, state)) => Ok((p1.or(p2), out1, state)),
|
||||
Err((p2, fail, _)) => Err((p1.or(p2), fail, original_state)),
|
||||
},
|
||||
|
@ -1279,12 +1289,12 @@ macro_rules! collection {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! collection_trailing_sep_e {
|
||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $open_problem:expr, $indent_problem:expr, $space_before:expr) => {
|
||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $open_problem:expr, $indent_problem:expr, $space_before:expr) => {
|
||||
skip_first!(
|
||||
$opening_brace,
|
||||
|arena, state| {
|
||||
let (_, spaces, state) = space0_e($min_indent, $indent_problem)
|
||||
.parse(arena, state)?;
|
||||
|arena, state, min_indent| {
|
||||
let (_, spaces, state) = space0_e($indent_problem)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, (mut parsed_elems, mut final_comments), state) =
|
||||
and!(
|
||||
|
@ -1292,23 +1302,18 @@ macro_rules! collection_trailing_sep_e {
|
|||
$delimiter,
|
||||
$crate::blankspace::space0_before_optional_after(
|
||||
$elem,
|
||||
$min_indent,
|
||||
$indent_problem,
|
||||
$indent_problem
|
||||
)
|
||||
),
|
||||
$crate::blankspace::space0_e(
|
||||
// we use min_indent=0 because we want to parse incorrectly indented closing braces
|
||||
// and later fix these up in the formatter.
|
||||
0 /* min_indent */,
|
||||
$indent_problem)
|
||||
).parse(arena, state)?;
|
||||
$crate::parser::reset_min_indent($crate::blankspace::space0_e($indent_problem))
|
||||
).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_,_, state) =
|
||||
if parsed_elems.is_empty() {
|
||||
one_of_with_error![$open_problem; $closing_brace].parse(arena, state)?
|
||||
one_of_with_error![$open_problem; $closing_brace].parse(arena, state, min_indent)?
|
||||
} else {
|
||||
$closing_brace.parse(arena, state)?
|
||||
$closing_brace.parse(arena, state, min_indent)?
|
||||
};
|
||||
|
||||
if !spaces.is_empty() {
|
||||
|
@ -1334,22 +1339,33 @@ macro_rules! collection_trailing_sep_e {
|
|||
#[macro_export]
|
||||
macro_rules! succeed {
|
||||
($value:expr) => {
|
||||
move |_arena: &'a bumpalo::Bump, state: $crate::state::State<'a>| {
|
||||
move |_arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, _min_indent: u32| {
|
||||
Ok((NoProgress, $value, state))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fail<'a, T, E, F>(f: F) -> impl Parser<'a, T, E>
|
||||
where
|
||||
T: 'a,
|
||||
E: 'a,
|
||||
F: Fn(Position) -> E,
|
||||
{
|
||||
move |_arena: &'a bumpalo::Bump, state: State<'a>, _min_indent: u32| {
|
||||
Err((NoProgress, f(state.pos()), state))
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! and {
|
||||
($p1:expr, $p2:expr) => {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>| {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| {
|
||||
// We have to clone this because if the first parser passes and then
|
||||
// the second one fails, we need to revert back to the original state.
|
||||
let original_state = state.clone();
|
||||
|
||||
match $p1.parse(arena, state) {
|
||||
Ok((p1, out1, state)) => match $p2.parse(arena, state) {
|
||||
match $p1.parse(arena, state, min_indent) {
|
||||
Ok((p1, out1, state)) => match $p2.parse(arena, state, min_indent) {
|
||||
Ok((p2, out2, state)) => Ok((p1.or(p2), (out1, out2), state)),
|
||||
Err((p2, fail, _)) => Err((p1.or(p2), fail, original_state)),
|
||||
},
|
||||
|
@ -1362,12 +1378,12 @@ macro_rules! and {
|
|||
#[macro_export]
|
||||
macro_rules! one_of {
|
||||
($p1:expr, $p2:expr) => {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>| {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| {
|
||||
|
||||
match $p1.parse(arena, state) {
|
||||
match $p1.parse(arena, state, min_indent) {
|
||||
valid @ Ok(_) => valid,
|
||||
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
|
||||
Err((NoProgress, _, state)) => $p2.parse( arena, state),
|
||||
Err((NoProgress, _, state)) => $p2.parse(arena, state, min_indent),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1383,8 +1399,8 @@ macro_rules! one_of {
|
|||
#[macro_export]
|
||||
macro_rules! maybe {
|
||||
($p1:expr) => {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>| match $p1
|
||||
.parse(arena, state)
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| match $p1
|
||||
.parse(arena, state, min_indent)
|
||||
{
|
||||
Ok((progress, value, state)) => Ok((progress, Some(value), state)),
|
||||
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
|
||||
|
@ -1396,9 +1412,9 @@ macro_rules! maybe {
|
|||
#[macro_export]
|
||||
macro_rules! one_of_with_error {
|
||||
($toerror:expr; $p1:expr) => {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>| {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| {
|
||||
|
||||
match $p1.parse(arena, state) {
|
||||
match $p1.parse(arena, state, min_indent) {
|
||||
valid @ Ok(_) => valid,
|
||||
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state )),
|
||||
Err((NoProgress, _, state)) => Err((MadeProgress, $toerror(state.pos()), state)),
|
||||
|
@ -1411,13 +1427,44 @@ macro_rules! one_of_with_error {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn reset_min_indent<'a, P, T, X: 'a>(parser: P) -> impl Parser<'a, T, X>
|
||||
where
|
||||
P: Parser<'a, T, X>,
|
||||
{
|
||||
move |arena, state, _min_indent| parser.parse(arena, state, 0)
|
||||
}
|
||||
|
||||
pub fn set_min_indent<'a, P, T, X: 'a>(min_indent: u32, parser: P) -> impl Parser<'a, T, X>
|
||||
where
|
||||
P: Parser<'a, T, X>,
|
||||
{
|
||||
move |arena, state, _m| parser.parse(arena, state, min_indent)
|
||||
}
|
||||
|
||||
pub fn increment_min_indent<'a, P, T, X: 'a>(parser: P) -> impl Parser<'a, T, X>
|
||||
where
|
||||
P: Parser<'a, T, X>,
|
||||
{
|
||||
move |arena, state, min_indent| parser.parse(arena, state, min_indent + 1)
|
||||
}
|
||||
|
||||
pub fn absolute_column_min_indent<'a, P, T, X: 'a>(parser: P) -> impl Parser<'a, T, X>
|
||||
where
|
||||
P: Parser<'a, T, X>,
|
||||
{
|
||||
move |arena, state: State<'a>, _min_indent| {
|
||||
let min_indent = state.column() + 1;
|
||||
parser.parse(arena, state, min_indent)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn specialize<'a, F, P, T, X, Y>(map_error: F, parser: P) -> impl Parser<'a, T, Y>
|
||||
where
|
||||
F: Fn(X, Position) -> Y,
|
||||
P: Parser<'a, T, X>,
|
||||
Y: 'a,
|
||||
{
|
||||
move |a, s| match parser.parse(a, s) {
|
||||
move |a, s, min_indent| match parser.parse(a, s, min_indent) {
|
||||
Ok(t) => Ok(t),
|
||||
Err((p, error, s)) => Err((p, map_error(error, s.pos()), s)),
|
||||
}
|
||||
|
@ -1430,9 +1477,9 @@ where
|
|||
P: Parser<'a, T, X>,
|
||||
Y: 'a,
|
||||
{
|
||||
move |a, s: State<'a>| {
|
||||
move |a, s: State<'a>, min_indent: u32| {
|
||||
let start = s.pos();
|
||||
match parser.parse(a, s) {
|
||||
match parser.parse(a, s, min_indent) {
|
||||
Ok(t) => Ok(t),
|
||||
Err((p, error, s)) => Err((p, map_error(error, Region::new(start, s.pos())), s)),
|
||||
}
|
||||
|
@ -1446,7 +1493,7 @@ where
|
|||
Y: 'a,
|
||||
X: 'a,
|
||||
{
|
||||
move |a, s| match parser.parse(a, s) {
|
||||
move |a, s, min_indent| match parser.parse(a, s, min_indent) {
|
||||
Ok(t) => Ok(t),
|
||||
Err((p, error, s)) => Err((p, map_error(a.alloc(error), s.pos()), s)),
|
||||
}
|
||||
|
@ -1459,7 +1506,7 @@ where
|
|||
{
|
||||
debug_assert_ne!(word, b'\n');
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>| match state.bytes().first() {
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| match state.bytes().first() {
|
||||
Some(x) if *x == word => {
|
||||
let state = state.advance(1);
|
||||
Ok((MadeProgress, (), state))
|
||||
|
@ -1503,7 +1550,7 @@ where
|
|||
|
||||
let needle = [word_1, word_2];
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>| {
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| {
|
||||
if state.bytes().starts_with(&needle) {
|
||||
let state = state.advance(2);
|
||||
Ok((MadeProgress, (), state))
|
||||
|
@ -1529,7 +1576,7 @@ where
|
|||
|
||||
let needle = [word_1, word_2, word_3];
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>| {
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| {
|
||||
if state.bytes().starts_with(&needle) {
|
||||
let state = state.advance(3);
|
||||
Ok((MadeProgress, (), state))
|
||||
|
@ -1552,9 +1599,9 @@ macro_rules! word1_check_indent {
|
|||
#[macro_export]
|
||||
macro_rules! map {
|
||||
($parser:expr, $transform:expr) => {
|
||||
move |arena, state| {
|
||||
move |arena, state, min_indent| {
|
||||
$parser
|
||||
.parse(arena, state)
|
||||
.parse(arena, state, min_indent)
|
||||
.map(|(progress, output, next_state)| (progress, $transform(output), next_state))
|
||||
}
|
||||
};
|
||||
|
@ -1563,9 +1610,9 @@ macro_rules! map {
|
|||
#[macro_export]
|
||||
macro_rules! map_with_arena {
|
||||
($parser:expr, $transform:expr) => {
|
||||
move |arena, state| {
|
||||
move |arena, state, min_indent| {
|
||||
$parser
|
||||
.parse(arena, state)
|
||||
.parse(arena, state, min_indent)
|
||||
.map(|(progress, output, next_state)| {
|
||||
(progress, $transform(arena, output), next_state)
|
||||
})
|
||||
|
@ -1576,12 +1623,12 @@ macro_rules! map_with_arena {
|
|||
#[macro_export]
|
||||
macro_rules! zero_or_more {
|
||||
($parser:expr) => {
|
||||
move |arena, state: State<'a>| {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
use bumpalo::collections::Vec;
|
||||
|
||||
let start_bytes_len = state.bytes().len();
|
||||
|
||||
match $parser.parse(arena, state) {
|
||||
match $parser.parse(arena, state, min_indent) {
|
||||
Ok((_, first_output, next_state)) => {
|
||||
let mut state = next_state;
|
||||
let mut buf = Vec::with_capacity_in(1, arena);
|
||||
|
@ -1589,7 +1636,7 @@ macro_rules! zero_or_more {
|
|||
buf.push(first_output);
|
||||
|
||||
loop {
|
||||
match $parser.parse(arena, state) {
|
||||
match $parser.parse(arena, state, min_indent) {
|
||||
Ok((_, next_output, next_state)) => {
|
||||
state = next_state;
|
||||
buf.push(next_output);
|
||||
|
@ -1632,10 +1679,10 @@ macro_rules! zero_or_more {
|
|||
#[macro_export]
|
||||
macro_rules! one_or_more {
|
||||
($parser:expr, $to_error:expr) => {
|
||||
move |arena, state: State<'a>| {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
use bumpalo::collections::Vec;
|
||||
|
||||
match $parser.parse(arena, state) {
|
||||
match $parser.parse(arena, state, min_indent) {
|
||||
Ok((_, first_output, next_state)) => {
|
||||
let mut state = next_state;
|
||||
let mut buf = Vec::with_capacity_in(1, arena);
|
||||
|
@ -1643,7 +1690,7 @@ macro_rules! one_or_more {
|
|||
buf.push(first_output);
|
||||
|
||||
loop {
|
||||
match $parser.parse(arena, state) {
|
||||
match $parser.parse(arena, state, min_indent) {
|
||||
Ok((_, next_output, next_state)) => {
|
||||
state = next_state;
|
||||
buf.push(next_output);
|
||||
|
@ -1668,20 +1715,22 @@ macro_rules! one_or_more {
|
|||
#[macro_export]
|
||||
macro_rules! debug {
|
||||
($parser:expr) => {
|
||||
move |arena, state: $crate::state::State<'a>| dbg!($parser.parse(arena, state))
|
||||
move |arena, state: $crate::state::State<'a>, min_indent: u32| {
|
||||
dbg!($parser.parse(arena, state, min_indent))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! either {
|
||||
($p1:expr, $p2:expr) => {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>| match $p1
|
||||
.parse(arena, state)
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| match $p1
|
||||
.parse(arena, state, min_indent)
|
||||
{
|
||||
Ok((progress, output, state)) => {
|
||||
Ok((progress, $crate::parser::Either::First(output), state))
|
||||
}
|
||||
Err((NoProgress, _, state)) => match $p2.parse(arena, state) {
|
||||
Err((NoProgress, _, state)) => match $p2.parse(arena, state, min_indent) {
|
||||
Ok((progress, output, state)) => {
|
||||
Ok((progress, $crate::parser::Either::Second(output), state))
|
||||
}
|
||||
|
@ -1749,10 +1798,10 @@ where
|
|||
P: Parser<'a, Val, Error>,
|
||||
Error: 'a,
|
||||
{
|
||||
move |arena: &'a Bump, state: State<'a>| {
|
||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let old_state = state.clone();
|
||||
|
||||
match parser.parse(arena, state) {
|
||||
match parser.parse(arena, state, min_indent) {
|
||||
Ok((_, a, s1)) => Ok((NoProgress, a, s1)),
|
||||
Err((_, f, _)) => Err((NoProgress, f, old_state)),
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ pub enum PatternType {
|
|||
WhenBranch,
|
||||
}
|
||||
|
||||
pub fn loc_closure_param<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
move |arena, state| parse_closure_param(arena, state, min_indent)
|
||||
pub fn loc_closure_param<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
parse_closure_param
|
||||
}
|
||||
|
||||
fn parse_closure_param<'a>(
|
||||
|
@ -35,59 +35,58 @@ fn parse_closure_param<'a>(
|
|||
) -> ParseResult<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
one_of!(
|
||||
// An ident is the most common param, e.g. \foo -> ...
|
||||
loc_ident_pattern_help(min_indent, true),
|
||||
loc_ident_pattern_help(true),
|
||||
// Underscore is also common, e.g. \_ -> ...
|
||||
loc!(underscore_pattern_help()),
|
||||
// You can destructure records in params, e.g. \{ x, y } -> ...
|
||||
loc!(specialize(
|
||||
EPattern::Record,
|
||||
crate::pattern::record_pattern_help(min_indent)
|
||||
crate::pattern::record_pattern_help()
|
||||
)),
|
||||
// If you wrap it in parens, you can match any arbitrary pattern at all.
|
||||
// e.g. \User.UserId userId -> ...
|
||||
specialize(EPattern::PInParens, loc_pattern_in_parens_help(min_indent))
|
||||
specialize(EPattern::PInParens, loc_pattern_in_parens_help())
|
||||
)
|
||||
.parse(arena, state)
|
||||
.parse(arena, state, min_indent)
|
||||
}
|
||||
|
||||
pub fn loc_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
pub fn loc_pattern_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
one_of!(
|
||||
specialize(EPattern::PInParens, loc_pattern_in_parens_help(min_indent)),
|
||||
specialize(EPattern::PInParens, loc_pattern_in_parens_help()),
|
||||
loc!(underscore_pattern_help()),
|
||||
loc_ident_pattern_help(min_indent, true),
|
||||
loc_ident_pattern_help(true),
|
||||
loc!(specialize(
|
||||
EPattern::Record,
|
||||
crate::pattern::record_pattern_help(min_indent)
|
||||
crate::pattern::record_pattern_help()
|
||||
)),
|
||||
loc!(specialize(EPattern::List, list_pattern_help(min_indent))),
|
||||
loc!(specialize(EPattern::List, list_pattern_help())),
|
||||
loc!(number_pattern_help()),
|
||||
loc!(string_pattern_help()),
|
||||
loc!(single_quote_pattern_help()),
|
||||
)
|
||||
}
|
||||
|
||||
fn loc_tag_pattern_args_help<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, Vec<'a, Loc<Pattern<'a>>>, EPattern<'a>> {
|
||||
zero_or_more!(loc_tag_pattern_arg(min_indent, false))
|
||||
fn loc_tag_pattern_args_help<'a>() -> impl Parser<'a, Vec<'a, Loc<Pattern<'a>>>, EPattern<'a>> {
|
||||
zero_or_more!(loc_tag_pattern_arg(false))
|
||||
}
|
||||
|
||||
/// Like `loc_tag_pattern_args_help`, but stops if a "has" keyword is seen (indicating an ability).
|
||||
fn loc_type_def_tag_pattern_args_help<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, Vec<'a, Loc<Pattern<'a>>>, EPattern<'a>> {
|
||||
zero_or_more!(loc_tag_pattern_arg(min_indent, true))
|
||||
zero_or_more!(loc_tag_pattern_arg(true))
|
||||
}
|
||||
|
||||
fn loc_tag_pattern_arg<'a>(
|
||||
min_indent: u32,
|
||||
stop_on_has_kw: bool,
|
||||
) -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
// Don't parse operators, because they have a higher precedence than function application.
|
||||
// If we encounter one, we're done parsing function args!
|
||||
move |arena, original_state: State<'a>| {
|
||||
let (_, spaces, state) = backtrackable(space0_e(min_indent, EPattern::IndentStart))
|
||||
.parse(arena, original_state.clone())?;
|
||||
move |arena, original_state: State<'a>, min_indent| {
|
||||
let (_, spaces, state) = backtrackable(space0_e(EPattern::IndentStart)).parse(
|
||||
arena,
|
||||
original_state.clone(),
|
||||
min_indent,
|
||||
)?;
|
||||
|
||||
let (_, loc_pat, state) = loc_parse_tag_pattern_arg(min_indent, arena, state)?;
|
||||
|
||||
|
@ -113,10 +112,10 @@ fn loc_tag_pattern_arg<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn loc_has_parser<'a>(min_indent: u32) -> impl Parser<'a, Loc<Has<'a>>, EPattern<'a>> {
|
||||
pub fn loc_has_parser<'a>() -> impl Parser<'a, Loc<Has<'a>>, EPattern<'a>> {
|
||||
then(
|
||||
loc_tag_pattern_arg(min_indent, false),
|
||||
|_arena, state, progress, pattern| {
|
||||
loc_tag_pattern_arg(false),
|
||||
|_arena, state, progress, pattern, _min_indent| {
|
||||
if matches!(pattern.value, Pattern::Identifier("has")) {
|
||||
Ok((progress, Loc::at(pattern.region, Has::Has), state))
|
||||
} else {
|
||||
|
@ -132,30 +131,26 @@ fn loc_parse_tag_pattern_arg<'a>(
|
|||
state: State<'a>,
|
||||
) -> ParseResult<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
one_of!(
|
||||
specialize(EPattern::PInParens, loc_pattern_in_parens_help(min_indent)),
|
||||
specialize(EPattern::PInParens, loc_pattern_in_parens_help()),
|
||||
loc!(underscore_pattern_help()),
|
||||
// Make sure `Foo Bar 1` is parsed as `Foo (Bar) 1`, and not `Foo (Bar 1)`
|
||||
loc_ident_pattern_help(min_indent, false),
|
||||
loc_ident_pattern_help(false),
|
||||
loc!(specialize(
|
||||
EPattern::Record,
|
||||
crate::pattern::record_pattern_help(min_indent)
|
||||
crate::pattern::record_pattern_help()
|
||||
)),
|
||||
loc!(string_pattern_help()),
|
||||
loc!(single_quote_pattern_help()),
|
||||
loc!(number_pattern_help())
|
||||
)
|
||||
.parse(arena, state)
|
||||
.parse(arena, state, min_indent)
|
||||
}
|
||||
|
||||
fn loc_pattern_in_parens_help<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, Loc<Pattern<'a>>, PInParens<'a>> {
|
||||
fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PInParens<'a>> {
|
||||
between!(
|
||||
word1(b'(', PInParens::Open),
|
||||
space0_around_ee(
|
||||
move |arena, state| specialize_ref(PInParens::Pattern, loc_pattern_help(min_indent))
|
||||
.parse(arena, state),
|
||||
min_indent,
|
||||
specialize_ref(PInParens::Pattern, loc_pattern_help()),
|
||||
PInParens::IndentOpen,
|
||||
PInParens::IndentEnd,
|
||||
),
|
||||
|
@ -203,19 +198,18 @@ fn single_quote_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>>
|
|||
)
|
||||
}
|
||||
|
||||
fn list_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Pattern<'a>, PList<'a>> {
|
||||
move |arena, state| {
|
||||
fn list_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PList<'a>> {
|
||||
move |arena, state, min_indent| {
|
||||
let (_, pats, state) = collection_trailing_sep_e!(
|
||||
word1(b'[', PList::Open),
|
||||
list_element_pattern(min_indent),
|
||||
list_element_pattern(),
|
||||
word1(b',', PList::End),
|
||||
word1(b']', PList::End),
|
||||
min_indent,
|
||||
PList::Open,
|
||||
PList::IndentEnd,
|
||||
Pattern::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let result = Pattern::List(pats);
|
||||
|
||||
|
@ -223,18 +217,18 @@ fn list_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Pattern<'a>, PList<
|
|||
}
|
||||
}
|
||||
|
||||
fn list_element_pattern<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
|
||||
fn list_element_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
|
||||
one_of!(
|
||||
three_list_rest_pattern_error(),
|
||||
list_rest_pattern(),
|
||||
specialize_ref(PList::Pattern, loc_pattern_help(min_indent)),
|
||||
specialize_ref(PList::Pattern, loc_pattern_help()),
|
||||
)
|
||||
}
|
||||
|
||||
fn three_list_rest_pattern_error<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
|
||||
then(
|
||||
loc!(word3(b'.', b'.', b'.', PList::Rest)),
|
||||
|_arena, state, _progress, word| {
|
||||
|_arena, state, _progress, word, _min_indent| {
|
||||
Err((MadeProgress, PList::Rest(word.region.start()), state))
|
||||
},
|
||||
)
|
||||
|
@ -247,14 +241,13 @@ fn list_rest_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
|
|||
}
|
||||
|
||||
fn loc_ident_pattern_help<'a>(
|
||||
min_indent: u32,
|
||||
can_have_arguments: bool,
|
||||
) -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||
move |arena: &'a Bump, state: State<'a>| {
|
||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let original_state = state.clone();
|
||||
|
||||
let (_, loc_ident, state) =
|
||||
specialize(|_, pos| EPattern::Start(pos), loc!(parse_ident)).parse(arena, state)?;
|
||||
let (_, loc_ident, state) = specialize(|_, pos| EPattern::Start(pos), loc!(parse_ident))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
match loc_ident.value {
|
||||
Ident::Tag(tag) => {
|
||||
|
@ -266,7 +259,7 @@ fn loc_ident_pattern_help<'a>(
|
|||
// Make sure `Foo Bar 1` is parsed as `Foo (Bar) 1`, and not `Foo (Bar 1)`
|
||||
if can_have_arguments {
|
||||
let (_, loc_args, state) =
|
||||
loc_type_def_tag_pattern_args_help(min_indent).parse(arena, state)?;
|
||||
loc_type_def_tag_pattern_args_help().parse(arena, state, min_indent)?;
|
||||
|
||||
if loc_args.is_empty() {
|
||||
Ok((MadeProgress, loc_tag, state))
|
||||
|
@ -293,7 +286,7 @@ fn loc_ident_pattern_help<'a>(
|
|||
// Make sure `@Foo Bar 1` is parsed as `@Foo (Bar) 1`, and not `@Foo (Bar 1)`
|
||||
if can_have_arguments {
|
||||
let (_, loc_args, state) =
|
||||
loc_tag_pattern_args_help(min_indent).parse(arena, state)?;
|
||||
loc_tag_pattern_args_help().parse(arena, state, min_indent)?;
|
||||
|
||||
if loc_args.is_empty() {
|
||||
Ok((MadeProgress, loc_pat, state))
|
||||
|
@ -372,11 +365,12 @@ fn loc_ident_pattern_help<'a>(
|
|||
}
|
||||
|
||||
fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
|
||||
move |arena: &'a Bump, state: State<'a>| {
|
||||
let (_, _, next_state) = word1(b'_', EPattern::Underscore).parse(arena, state)?;
|
||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let (_, _, next_state) =
|
||||
word1(b'_', EPattern::Underscore).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, output, final_state) =
|
||||
optional(lowercase_ident_pattern).parse(arena, next_state)?;
|
||||
optional(lowercase_ident_pattern).parse(arena, next_state, min_indent)?;
|
||||
|
||||
match output {
|
||||
Some(name) => Ok((MadeProgress, Pattern::Underscore(name), final_state)),
|
||||
|
@ -388,26 +382,26 @@ fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
|
|||
fn lowercase_ident_pattern<'a>(
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
min_indent: u32,
|
||||
) -> ParseResult<'a, &'a str, EPattern<'a>> {
|
||||
let pos = state.pos();
|
||||
|
||||
specialize(move |_, _| EPattern::End(pos), lowercase_ident()).parse(arena, state)
|
||||
specialize(move |_, _| EPattern::End(pos), lowercase_ident()).parse(arena, state, min_indent)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn record_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
|
||||
move |arena, state| {
|
||||
fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
|
||||
move |arena, state, min_indent| {
|
||||
let (_, fields, state) = collection_trailing_sep_e!(
|
||||
word1(b'{', PRecord::Open),
|
||||
record_pattern_field(min_indent),
|
||||
record_pattern_field(),
|
||||
word1(b',', PRecord::End),
|
||||
word1(b'}', PRecord::End),
|
||||
min_indent,
|
||||
PRecord::Open,
|
||||
PRecord::IndentEnd,
|
||||
Pattern::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let result = Pattern::RecordDestructure(fields);
|
||||
|
||||
|
@ -415,10 +409,10 @@ fn record_pattern_help<'a>(min_indent: u32) -> impl Parser<'a, Pattern<'a>, PRec
|
|||
}
|
||||
}
|
||||
|
||||
fn record_pattern_field<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>, PRecord<'a>> {
|
||||
fn record_pattern_field<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PRecord<'a>> {
|
||||
use crate::parser::Either::*;
|
||||
|
||||
move |arena, state: State<'a>| {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
// You must have a field name, e.g. "email"
|
||||
// using the initial pos is important for error reporting
|
||||
let pos = state.pos();
|
||||
|
@ -426,10 +420,10 @@ fn record_pattern_field<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>
|
|||
move |_, _| PRecord::Field(pos),
|
||||
lowercase_ident()
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
debug_assert_eq!(progress, MadeProgress);
|
||||
|
||||
let (_, spaces, state) = space0_e(min_indent, PRecord::IndentEnd).parse(arena, state)?;
|
||||
let (_, spaces, state) = space0_e(PRecord::IndentEnd).parse(arena, state, min_indent)?;
|
||||
|
||||
// Having a value is optional; both `{ email }` and `{ email: blah }` work.
|
||||
// (This is true in both literals and types.)
|
||||
|
@ -437,14 +431,13 @@ fn record_pattern_field<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>
|
|||
word1(b':', PRecord::Colon),
|
||||
word1(b'?', PRecord::Optional)
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
match opt_loc_val {
|
||||
Some(First(_)) => {
|
||||
let val_parser = specialize_ref(PRecord::Pattern, loc_pattern_help(min_indent));
|
||||
let (_, loc_val, state) =
|
||||
space0_before_e(val_parser, min_indent, PRecord::IndentColon)
|
||||
.parse(arena, state)?;
|
||||
let val_parser = specialize_ref(PRecord::Pattern, loc_pattern_help());
|
||||
let (_, loc_val, state) = space0_before_e(val_parser, PRecord::IndentColon)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let Loc {
|
||||
value: label,
|
||||
|
@ -468,13 +461,11 @@ fn record_pattern_field<'a>(min_indent: u32) -> impl Parser<'a, Loc<Pattern<'a>>
|
|||
))
|
||||
}
|
||||
Some(Second(_)) => {
|
||||
let val_parser = specialize_ref(PRecord::Expr, move |a, s| {
|
||||
crate::expr::parse_loc_expr_no_multi_backpassing(min_indent, a, s)
|
||||
});
|
||||
let val_parser =
|
||||
specialize_ref(PRecord::Expr, crate::expr::loc_expr_no_multi_backpassing());
|
||||
|
||||
let (_, loc_val, state) =
|
||||
space0_before_e(val_parser, min_indent, PRecord::IndentColon)
|
||||
.parse(arena, state)?;
|
||||
let (_, loc_val, state) = space0_before_e(val_parser, PRecord::IndentColon)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let Loc {
|
||||
value: label,
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use crate::ast::{EscapedChar, StrLiteral, StrSegment};
|
||||
use crate::expr;
|
||||
use crate::parser::Progress::{self, *};
|
||||
use crate::parser::{allocated, loc, specialize_ref, word1, BadInputError, EString, Parser};
|
||||
use crate::parser::{
|
||||
allocated, loc, reset_min_indent, specialize_ref, word1, BadInputError, EString, Parser,
|
||||
};
|
||||
use crate::state::State;
|
||||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::Bump;
|
||||
|
@ -9,7 +11,7 @@ use bumpalo::Bump;
|
|||
/// One or more ASCII hex digits. (Useful when parsing unicode escape codes,
|
||||
/// which must consist entirely of ASCII hex digits.)
|
||||
fn ascii_hex_digits<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
|
||||
move |arena, mut state: State<'a>| {
|
||||
move |arena, mut state: State<'a>, _min_indent: u32| {
|
||||
let mut buf = bumpalo::collections::String::new_in(arena);
|
||||
|
||||
for &byte in state.bytes().iter() {
|
||||
|
@ -30,7 +32,7 @@ fn ascii_hex_digits<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
|
|||
}
|
||||
|
||||
pub fn parse_single_quote<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
|
||||
move |arena: &'a Bump, mut state: State<'a>| {
|
||||
move |arena: &'a Bump, mut state: State<'a>, _min_indent: u32| {
|
||||
if state.consume_mut("\'") {
|
||||
// we will be parsing a single-quote-string
|
||||
} else {
|
||||
|
@ -165,7 +167,7 @@ fn utf8<'a>(
|
|||
pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
|
||||
use StrLiteral::*;
|
||||
|
||||
move |arena: &'a Bump, mut state: State<'a>| {
|
||||
move |arena: &'a Bump, mut state: State<'a>, min_indent: u32| {
|
||||
let is_multiline;
|
||||
|
||||
let indent = state.column();
|
||||
|
@ -368,10 +370,13 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
|
|||
// canonicalization error if that expression variant
|
||||
// is not allowed inside a string interpolation.
|
||||
let (_progress, loc_expr, new_state) = skip_second!(
|
||||
specialize_ref(EString::Format, loc(allocated(expr::expr_help(0)))),
|
||||
specialize_ref(
|
||||
EString::Format,
|
||||
loc(allocated(reset_min_indent(expr::expr_help())))
|
||||
),
|
||||
word1(b')', EString::FormatEnd)
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
// Advance the iterator past the expr we just parsed.
|
||||
for _ in 0..(original_byte_count - new_state.bytes().len()) {
|
||||
|
@ -398,7 +403,7 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
|
|||
loc(ascii_hex_digits()),
|
||||
word1(b')', EString::CodePtEnd)
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
// Advance the iterator past the expr we just parsed.
|
||||
for _ in 0..(original_byte_count - new_state.bytes().len()) {
|
||||
|
|
|
@ -34,7 +34,9 @@ pub fn parse_loc_with<'a>(
|
|||
pub fn parse_defs_with<'a>(arena: &'a Bump, input: &'a str) -> Result<Defs<'a>, SyntaxError<'a>> {
|
||||
let state = State::new(input.trim().as_bytes());
|
||||
|
||||
match module_defs().parse(arena, state) {
|
||||
let min_indent = 0;
|
||||
|
||||
match module_defs().parse(arena, state, min_indent) {
|
||||
Ok(tuple) => Ok(tuple.1),
|
||||
Err(tuple) => Err(tuple.1),
|
||||
}
|
||||
|
|
|
@ -9,54 +9,52 @@ use crate::expr::record_value_field;
|
|||
use crate::ident::lowercase_ident;
|
||||
use crate::keyword;
|
||||
use crate::parser::{
|
||||
allocated, backtrackable, optional, specialize, specialize_ref, word1, word2, word3, EType,
|
||||
ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, ParseResult, Parser,
|
||||
absolute_column_min_indent, increment_min_indent, then, ERecord, ETypeAbilityImpl,
|
||||
};
|
||||
use crate::parser::{
|
||||
allocated, backtrackable, fail, optional, specialize, specialize_ref, word1, word2, word3,
|
||||
EType, ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, Parser,
|
||||
Progress::{self, *},
|
||||
};
|
||||
use crate::parser::{then, ERecord, ETypeAbilityImpl};
|
||||
use crate::state::State;
|
||||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_region::all::{Loc, Position, Region};
|
||||
|
||||
pub fn located<'a>(
|
||||
min_indent: u32,
|
||||
is_trailing_comma_valid: bool,
|
||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||
expression(min_indent, is_trailing_comma_valid, false)
|
||||
expression(is_trailing_comma_valid, false)
|
||||
}
|
||||
|
||||
pub fn located_opaque_signature<'a>(
|
||||
min_indent: u32,
|
||||
is_trailing_comma_valid: bool,
|
||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||
expression(min_indent, is_trailing_comma_valid, true)
|
||||
expression(is_trailing_comma_valid, true)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn tag_union_type<'a>(
|
||||
min_indent: u32,
|
||||
stop_at_surface_has: bool,
|
||||
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> {
|
||||
move |arena, state| {
|
||||
move |arena, state, min_indent| {
|
||||
let (_, tags, state) = collection_trailing_sep_e!(
|
||||
word1(b'[', ETypeTagUnion::Open),
|
||||
loc!(tag_type(min_indent, false)),
|
||||
loc!(tag_type(false)),
|
||||
word1(b',', ETypeTagUnion::End),
|
||||
word1(b']', ETypeTagUnion::End),
|
||||
min_indent,
|
||||
ETypeTagUnion::Open,
|
||||
ETypeTagUnion::IndentEnd,
|
||||
Tag::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
// This could be an open tag union, e.g. `[Foo, Bar]a`
|
||||
let (_, ext, state) = optional(allocated(specialize_ref(
|
||||
ETypeTagUnion::Type,
|
||||
term(min_indent, stop_at_surface_has),
|
||||
term(stop_at_surface_has),
|
||||
)))
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let result = TypeAnnotation::TagUnion { tags, ext };
|
||||
|
||||
|
@ -64,11 +62,11 @@ fn tag_union_type<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn check_type_alias(
|
||||
p: Progress,
|
||||
annot: Loc<TypeAnnotation>,
|
||||
) -> impl Parser<TypeHeader, ETypeInlineAlias> {
|
||||
move |arena, state| match annot.value {
|
||||
fn check_type_alias<'a>(
|
||||
arena: &'a Bump,
|
||||
annot: Loc<TypeAnnotation<'a>>,
|
||||
) -> Result<TypeHeader<'a>, ETypeInlineAlias> {
|
||||
match annot.value {
|
||||
TypeAnnotation::Apply("", tag_name, vars) => {
|
||||
let mut var_names = Vec::new_in(arena);
|
||||
var_names.reserve(vars.len());
|
||||
|
@ -76,11 +74,7 @@ fn check_type_alias(
|
|||
if let TypeAnnotation::BoundVariable(v) = var.value {
|
||||
var_names.push(Loc::at(var.region, Pattern::Identifier(v)));
|
||||
} else {
|
||||
return Err((
|
||||
p,
|
||||
ETypeInlineAlias::ArgumentNotLowercase(var.region.start()),
|
||||
state,
|
||||
));
|
||||
return Err(ETypeInlineAlias::ArgumentNotLowercase(var.region.start()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,64 +87,58 @@ fn check_type_alias(
|
|||
vars: var_names.into_bump_slice(),
|
||||
};
|
||||
|
||||
Ok((p, header, state))
|
||||
Ok(header)
|
||||
}
|
||||
TypeAnnotation::Apply(_, _, _) => {
|
||||
Err((p, ETypeInlineAlias::Qualified(annot.region.start()), state))
|
||||
}
|
||||
_ => Err((p, ETypeInlineAlias::NotAnAlias(annot.region.start()), state)),
|
||||
TypeAnnotation::Apply(_, _, _) => Err(ETypeInlineAlias::Qualified(annot.region.start())),
|
||||
_ => Err(ETypeInlineAlias::NotAnAlias(annot.region.start())),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_type_alias_after_as<'a>(min_indent: u32) -> impl Parser<'a, TypeHeader<'a>, EType<'a>> {
|
||||
move |arena, state| {
|
||||
space0_before_e(term(min_indent, false), min_indent, EType::TAsIndentStart)
|
||||
.parse(arena, state)
|
||||
.and_then(|(p, annot, state)| {
|
||||
specialize(EType::TInlineAlias, check_type_alias(p, annot)).parse(arena, state)
|
||||
})
|
||||
fn parse_type_alias_after_as<'a>() -> impl Parser<'a, TypeHeader<'a>, EType<'a>> {
|
||||
then(
|
||||
space0_before_e(term(false), EType::TAsIndentStart),
|
||||
// TODO: introduce a better combinator for this.
|
||||
// `check_type_alias` doesn't need to modify the state or progress, but it needs to access `state.pos()`
|
||||
|arena, state, progress, output, _min_indent| {
|
||||
let res = check_type_alias(arena, output);
|
||||
|
||||
match res {
|
||||
Ok(header) => Ok((progress, header, state)),
|
||||
Err(err) => Err((progress, EType::TInlineAlias(err, state.pos()), state)),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, EType<'a>> {
|
||||
|_arena, state: State<'a>| Err((NoProgress, EType::TStart(state.pos()), state))
|
||||
}
|
||||
|
||||
fn term<'a>(
|
||||
min_indent: u32,
|
||||
stop_at_surface_has: bool,
|
||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||
fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||
map_with_arena!(
|
||||
and!(
|
||||
one_of!(
|
||||
loc_wildcard(),
|
||||
loc_inferred(),
|
||||
specialize(EType::TInParens, loc_type_in_parens(min_indent)),
|
||||
loc!(specialize(
|
||||
EType::TRecord,
|
||||
record_type(min_indent, stop_at_surface_has)
|
||||
)),
|
||||
specialize(EType::TInParens, loc_type_in_parens()),
|
||||
loc!(specialize(EType::TRecord, record_type(stop_at_surface_has))),
|
||||
loc!(specialize(
|
||||
EType::TTagUnion,
|
||||
tag_union_type(min_indent, stop_at_surface_has)
|
||||
tag_union_type(stop_at_surface_has)
|
||||
)),
|
||||
loc!(applied_type(min_indent, stop_at_surface_has)),
|
||||
loc!(applied_type(stop_at_surface_has)),
|
||||
loc!(parse_type_variable(stop_at_surface_has)),
|
||||
fail_type_start(),
|
||||
fail(EType::TStart),
|
||||
),
|
||||
// Inline alias notation, e.g. [Nil, Cons a (List a)] as List a
|
||||
one_of![
|
||||
map!(
|
||||
and!(
|
||||
skip_second!(
|
||||
backtrackable(space0_e(min_indent, EType::TIndentEnd)),
|
||||
backtrackable(space0_e(EType::TIndentEnd)),
|
||||
crate::parser::keyword_e(keyword::AS, EType::TEnd)
|
||||
),
|
||||
parse_type_alias_after_as(min_indent)
|
||||
parse_type_alias_after_as()
|
||||
),
|
||||
Some
|
||||
),
|
||||
|_, state| Ok((NoProgress, None, state))
|
||||
succeed!(None)
|
||||
]
|
||||
),
|
||||
|arena: &'a Bump,
|
||||
|
@ -187,27 +175,23 @@ fn loc_inferred<'a>() -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
|||
}
|
||||
|
||||
fn loc_applied_arg<'a>(
|
||||
min_indent: u32,
|
||||
stop_at_surface_has: bool,
|
||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||
use crate::ast::Spaceable;
|
||||
|
||||
map_with_arena!(
|
||||
and!(
|
||||
backtrackable(space0_e(min_indent, EType::TIndentStart)),
|
||||
backtrackable(space0_e(EType::TIndentStart)),
|
||||
one_of!(
|
||||
loc_wildcard(),
|
||||
loc_inferred(),
|
||||
specialize(EType::TInParens, loc_type_in_parens(min_indent)),
|
||||
loc!(specialize(
|
||||
EType::TRecord,
|
||||
record_type(min_indent, stop_at_surface_has)
|
||||
)),
|
||||
specialize(EType::TInParens, loc_type_in_parens()),
|
||||
loc!(specialize(EType::TRecord, record_type(stop_at_surface_has))),
|
||||
loc!(specialize(
|
||||
EType::TTagUnion,
|
||||
tag_union_type(min_indent, stop_at_surface_has)
|
||||
tag_union_type(stop_at_surface_has)
|
||||
)),
|
||||
loc!(specialize(EType::TApply, parse_concrete_type)),
|
||||
loc!(specialize(EType::TApply, concrete_type())),
|
||||
loc!(parse_type_variable(stop_at_surface_has))
|
||||
)
|
||||
),
|
||||
|
@ -222,18 +206,11 @@ fn loc_applied_arg<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
fn loc_type_in_parens<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, ETypeInParens<'a>> {
|
||||
fn loc_type_in_parens<'a>() -> impl Parser<'a, Loc<TypeAnnotation<'a>>, ETypeInParens<'a>> {
|
||||
between!(
|
||||
word1(b'(', ETypeInParens::Open),
|
||||
space0_around_ee(
|
||||
move |arena, state| specialize_ref(
|
||||
ETypeInParens::Type,
|
||||
expression(min_indent, true, false)
|
||||
)
|
||||
.parse(arena, state),
|
||||
min_indent,
|
||||
specialize_ref(ETypeInParens::Type, expression(true, false)),
|
||||
ETypeInParens::IndentOpen,
|
||||
ETypeInParens::IndentEnd,
|
||||
),
|
||||
|
@ -242,18 +219,14 @@ fn loc_type_in_parens<'a>(
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn tag_type<'a>(
|
||||
min_indent: u32,
|
||||
stop_at_surface_has: bool,
|
||||
) -> impl Parser<'a, Tag<'a>, ETypeTagUnion<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
let (_, name, state) = loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state)?;
|
||||
fn tag_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Tag<'a>, ETypeTagUnion<'a>> {
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
let (_, name, state) =
|
||||
loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, args, state) = specialize_ref(
|
||||
ETypeTagUnion::Type,
|
||||
loc_applied_args_e(min_indent, stop_at_surface_has),
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
let (_, args, state) =
|
||||
specialize_ref(ETypeTagUnion::Type, loc_applied_args_e(stop_at_surface_has))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let result = Tag::Apply {
|
||||
name,
|
||||
|
@ -269,19 +242,20 @@ where
|
|||
F: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
move |arena, state: State<'a>| match crate::ident::tag_name().parse(arena, state) {
|
||||
move |arena, state: State<'a>, min_indent: u32| match crate::ident::tag_name()
|
||||
.parse(arena, state, min_indent)
|
||||
{
|
||||
Ok(good) => Ok(good),
|
||||
Err((progress, _, state)) => Err((progress, to_problem(state.pos()), state)),
|
||||
}
|
||||
}
|
||||
|
||||
fn record_type_field<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'a>>, ETypeRecord<'a>> {
|
||||
fn record_type_field<'a>() -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'a>>, ETypeRecord<'a>>
|
||||
{
|
||||
use crate::parser::Either::*;
|
||||
use AssignedField::*;
|
||||
|
||||
(move |arena, state: State<'a>| {
|
||||
(move |arena, state: State<'a>, min_indent: u32| {
|
||||
// You must have a field name, e.g. "email"
|
||||
// using the initial pos is important for error reporting
|
||||
let pos = state.pos();
|
||||
|
@ -289,11 +263,11 @@ fn record_type_field<'a>(
|
|||
move |_, _| ETypeRecord::Field(pos),
|
||||
lowercase_ident()
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
debug_assert_eq!(progress, MadeProgress);
|
||||
|
||||
let (_, spaces, state) =
|
||||
space0_e(min_indent, ETypeRecord::IndentEnd).parse(arena, state)?;
|
||||
space0_e(ETypeRecord::IndentEnd).parse(arena, state, min_indent)?;
|
||||
|
||||
// Having a value is optional; both `{ email }` and `{ email: blah }` work.
|
||||
// (This is true in both literals and types.)
|
||||
|
@ -301,15 +275,14 @@ fn record_type_field<'a>(
|
|||
word1(b':', ETypeRecord::Colon),
|
||||
word1(b'?', ETypeRecord::Optional)
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let val_parser = specialize_ref(ETypeRecord::Type, expression(min_indent, true, false));
|
||||
let val_parser = specialize_ref(ETypeRecord::Type, expression(true, false));
|
||||
|
||||
match opt_loc_val {
|
||||
Some(First(_)) => {
|
||||
let (_, loc_val, state) =
|
||||
space0_before_e(val_parser, min_indent, ETypeRecord::IndentColon)
|
||||
.parse(arena, state)?;
|
||||
let (_, loc_val, state) = space0_before_e(val_parser, ETypeRecord::IndentColon)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
Ok((
|
||||
MadeProgress,
|
||||
|
@ -318,9 +291,8 @@ fn record_type_field<'a>(
|
|||
))
|
||||
}
|
||||
Some(Second(_)) => {
|
||||
let (_, loc_val, state) =
|
||||
space0_before_e(val_parser, min_indent, ETypeRecord::IndentOptional)
|
||||
.parse(arena, state)?;
|
||||
let (_, loc_val, state) = space0_before_e(val_parser, ETypeRecord::IndentOptional)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
Ok((
|
||||
MadeProgress,
|
||||
|
@ -346,28 +318,26 @@ fn record_type_field<'a>(
|
|||
|
||||
#[inline(always)]
|
||||
fn record_type<'a>(
|
||||
min_indent: u32,
|
||||
stop_at_surface_has: bool,
|
||||
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> {
|
||||
use crate::type_annotation::TypeAnnotation::*;
|
||||
|
||||
(move |arena, state| {
|
||||
(move |arena, state, min_indent| {
|
||||
let (_, fields, state) = collection_trailing_sep_e!(
|
||||
// word1_check_indent!(b'{', TRecord::Open, min_indent, TRecord::IndentOpen),
|
||||
word1(b'{', ETypeRecord::Open),
|
||||
loc!(record_type_field(min_indent)),
|
||||
loc!(record_type_field()),
|
||||
word1(b',', ETypeRecord::End),
|
||||
// word1_check_indent!(b'}', TRecord::End, min_indent, TRecord::IndentEnd),
|
||||
word1(b'}', ETypeRecord::End),
|
||||
min_indent,
|
||||
ETypeRecord::Open,
|
||||
ETypeRecord::IndentEnd,
|
||||
AssignedField::SpaceBefore
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let field_term = specialize_ref(ETypeRecord::Type, term(min_indent, stop_at_surface_has));
|
||||
let (_, ext, state) = optional(allocated(field_term)).parse(arena, state)?;
|
||||
let field_term = specialize_ref(ETypeRecord::Type, term(stop_at_surface_has));
|
||||
let (_, ext, state) = optional(allocated(field_term)).parse(arena, state, min_indent)?;
|
||||
|
||||
let result = Record { fields, ext };
|
||||
|
||||
|
@ -376,16 +346,13 @@ fn record_type<'a>(
|
|||
.trace("type_annotation:record_type")
|
||||
}
|
||||
|
||||
fn applied_type<'a>(
|
||||
min_indent: u32,
|
||||
stop_at_surface_has: bool,
|
||||
) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
|
||||
fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
|
||||
map!(
|
||||
and!(
|
||||
specialize(EType::TApply, parse_concrete_type),
|
||||
specialize(EType::TApply, concrete_type()),
|
||||
// Optionally parse space-separated arguments for the constructor,
|
||||
// e.g. `Str Float` in `Map Str Float`
|
||||
loc_applied_args_e(min_indent, stop_at_surface_has)
|
||||
loc_applied_args_e(stop_at_surface_has)
|
||||
),
|
||||
|(ctor, args): (TypeAnnotation<'a>, Vec<'a, Loc<TypeAnnotation<'a>>>)| {
|
||||
match &ctor {
|
||||
|
@ -406,29 +373,24 @@ fn applied_type<'a>(
|
|||
}
|
||||
|
||||
fn loc_applied_args_e<'a>(
|
||||
min_indent: u32,
|
||||
stop_at_surface_has: bool,
|
||||
) -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, EType<'a>> {
|
||||
zero_or_more!(loc_applied_arg(min_indent, stop_at_surface_has))
|
||||
zero_or_more!(loc_applied_arg(stop_at_surface_has))
|
||||
}
|
||||
|
||||
// Hash & Eq & ...
|
||||
fn ability_chain<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, EType<'a>> {
|
||||
fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, EType<'a>> {
|
||||
map!(
|
||||
and!(
|
||||
space0_before_optional_after(
|
||||
specialize(EType::TApply, loc!(parse_concrete_type)),
|
||||
min_indent,
|
||||
specialize(EType::TApply, loc!(concrete_type())),
|
||||
EType::TIndentStart,
|
||||
EType::TIndentEnd,
|
||||
),
|
||||
zero_or_more!(skip_first!(
|
||||
word1(b'&', EType::THasClause),
|
||||
space0_before_optional_after(
|
||||
specialize(EType::TApply, loc!(parse_concrete_type)),
|
||||
min_indent,
|
||||
specialize(EType::TApply, loc!(concrete_type())),
|
||||
EType::TIndentStart,
|
||||
EType::TIndentEnd,
|
||||
)
|
||||
|
@ -444,7 +406,7 @@ fn ability_chain<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
fn has_clause<'a>(min_indent: u32) -> impl Parser<'a, Loc<HasClause<'a>>, EType<'a>> {
|
||||
fn has_clause<'a>() -> impl Parser<'a, Loc<HasClause<'a>>, EType<'a>> {
|
||||
map!(
|
||||
// Suppose we are trying to parse "a has Hash"
|
||||
and!(
|
||||
|
@ -454,17 +416,14 @@ fn has_clause<'a>(min_indent: u32) -> impl Parser<'a, Loc<HasClause<'a>>, EType<
|
|||
|_, pos| EType::TBadTypeVariable(pos),
|
||||
loc!(map!(lowercase_ident(), Spaced::Item)),
|
||||
),
|
||||
min_indent,
|
||||
EType::TIndentStart,
|
||||
EType::TIndentEnd
|
||||
),
|
||||
then(
|
||||
skip_first!(
|
||||
// Parse "has"; we don't care about this keyword
|
||||
word3(b'h', b'a', b's', EType::THasClause),
|
||||
// Parse "Hash & ..."; this may be qualified from another module like "Hash.Hash"
|
||||
|arena, state, _progress, _output| {
|
||||
ability_chain(state.column() + 1).parse(arena, state)
|
||||
}
|
||||
absolute_column_min_indent(ability_chain())
|
||||
)
|
||||
),
|
||||
|(var, abilities): (Loc<Spaced<'a, &'a str>>, Vec<'a, Loc<TypeAnnotation<'a>>>)| {
|
||||
|
@ -485,24 +444,18 @@ fn has_clause<'a>(min_indent: u32) -> impl Parser<'a, Loc<HasClause<'a>>, EType<
|
|||
/// Parse a chain of `has` clauses, e.g. " | a has Hash, b has Eq".
|
||||
/// Returns the clauses and spaces before the starting "|", if there were any.
|
||||
fn has_clause_chain<'a>(
|
||||
min_indent: u32,
|
||||
) -> impl Parser<'a, (&'a [CommentOrNewline<'a>], &'a [Loc<HasClause<'a>>]), EType<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
let (_, (spaces_before, ()), state) = and!(
|
||||
space0_e(min_indent, EType::TIndentStart),
|
||||
word1(b'|', EType::TWhereBar)
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
move |arena, state: State<'a>, min_indent: u32| {
|
||||
let (_, (spaces_before, ()), state) =
|
||||
and!(space0_e(EType::TIndentStart), word1(b'|', EType::TWhereBar))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let min_demand_indent = state.column() + 1;
|
||||
// Parse the first clause (there must be one), then the rest
|
||||
let (_, first_clause, state) = has_clause(min_demand_indent).parse(arena, state)?;
|
||||
let (_, first_clause, state) = has_clause().parse(arena, state, min_indent)?;
|
||||
|
||||
let (_, mut clauses, state) = zero_or_more!(skip_first!(
|
||||
word1(b',', EType::THasClause),
|
||||
has_clause(min_demand_indent)
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
let (_, mut clauses, state) =
|
||||
zero_or_more!(skip_first!(word1(b',', EType::THasClause), has_clause()))
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
// Usually the number of clauses shouldn't be too large, so this is okay
|
||||
clauses.insert(0, first_clause);
|
||||
|
@ -516,8 +469,8 @@ fn has_clause_chain<'a>(
|
|||
}
|
||||
|
||||
/// Parse a has-abilities clause, e.g. `has [Eq, Hash]`.
|
||||
pub fn has_abilities<'a>(min_indent: u32) -> impl Parser<'a, Loc<HasAbilities<'a>>, EType<'a>> {
|
||||
skip_first!(
|
||||
pub fn has_abilities<'a>() -> impl Parser<'a, Loc<HasAbilities<'a>>, EType<'a>> {
|
||||
increment_min_indent(skip_first!(
|
||||
// Parse "has"; we don't care about this keyword
|
||||
word3(b'h', b'a', b's', EType::THasClause),
|
||||
// Parse "Hash"; this may be qualified from another module like "Hash.Hash"
|
||||
|
@ -525,39 +478,33 @@ pub fn has_abilities<'a>(min_indent: u32) -> impl Parser<'a, Loc<HasAbilities<'a
|
|||
loc!(map!(
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'[', EType::TStart),
|
||||
loc!(parse_has_ability(min_indent)),
|
||||
loc!(parse_has_ability()),
|
||||
word1(b',', EType::TEnd),
|
||||
word1(b']', EType::TEnd),
|
||||
min_indent + 1,
|
||||
EType::TStart,
|
||||
EType::TIndentEnd,
|
||||
HasAbility::SpaceBefore
|
||||
),
|
||||
HasAbilities::Has
|
||||
)),
|
||||
min_indent + 1,
|
||||
EType::TIndentEnd,
|
||||
)
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_has_ability<'a>(min_indent: u32) -> impl Parser<'a, HasAbility<'a>, EType<'a>> {
|
||||
map!(
|
||||
fn parse_has_ability<'a>() -> impl Parser<'a, HasAbility<'a>, EType<'a>> {
|
||||
increment_min_indent(map!(
|
||||
and!(
|
||||
loc!(specialize(EType::TApply, parse_concrete_type)),
|
||||
loc!(specialize(EType::TApply, concrete_type())),
|
||||
optional(space0_before_e(
|
||||
loc!(map!(
|
||||
specialize(
|
||||
EType::TAbilityImpl,
|
||||
collection_trailing_sep_e!(
|
||||
word1(b'{', ETypeAbilityImpl::Open),
|
||||
specialize(
|
||||
|e: ERecord<'_>, _| e.into(),
|
||||
loc!(record_value_field(min_indent + 1))
|
||||
),
|
||||
specialize(|e: ERecord<'_>, _| e.into(), loc!(record_value_field())),
|
||||
word1(b',', ETypeAbilityImpl::End),
|
||||
word1(b'}', ETypeAbilityImpl::End),
|
||||
min_indent,
|
||||
ETypeAbilityImpl::Open,
|
||||
ETypeAbilityImpl::IndentEnd,
|
||||
AssignedField::SpaceBefore
|
||||
|
@ -565,63 +512,49 @@ fn parse_has_ability<'a>(min_indent: u32) -> impl Parser<'a, HasAbility<'a>, ETy
|
|||
),
|
||||
HasImpls::HasImpls
|
||||
)),
|
||||
min_indent + 1,
|
||||
EType::TIndentEnd
|
||||
))
|
||||
),
|
||||
|(ability, impls): (_, Option<_>)| { HasAbility::HasAbility { ability, impls } }
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
fn expression<'a>(
|
||||
min_indent: u32,
|
||||
is_trailing_comma_valid: bool,
|
||||
stop_at_surface_has: bool,
|
||||
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
||||
(move |arena, state: State<'a>| {
|
||||
let (p1, first, state) = space0_before_e(
|
||||
term(min_indent, stop_at_surface_has),
|
||||
min_indent,
|
||||
EType::TIndentStart,
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
(move |arena, state: State<'a>, min_indent: u32| {
|
||||
let (p1, first, state) = space0_before_e(term(stop_at_surface_has), EType::TIndentStart)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let result = and![
|
||||
zero_or_more!(skip_first!(
|
||||
word1(b',', EType::TFunctionArgument),
|
||||
one_of![
|
||||
space0_around_ee(
|
||||
term(min_indent, stop_at_surface_has),
|
||||
min_indent,
|
||||
term(stop_at_surface_has),
|
||||
EType::TIndentStart,
|
||||
EType::TIndentEnd
|
||||
),
|
||||
|_, state: State<'a>| Err((
|
||||
NoProgress,
|
||||
EType::TFunctionArgument(state.pos()),
|
||||
state
|
||||
))
|
||||
fail(EType::TFunctionArgument)
|
||||
]
|
||||
))
|
||||
.trace("type_annotation:expression:rest_args"),
|
||||
// TODO this space0 is dropped, so newlines just before the function arrow when there
|
||||
// is only one argument are not seen by the formatter. Can we do better?
|
||||
skip_second!(
|
||||
space0_e(min_indent, EType::TIndentStart),
|
||||
space0_e(EType::TIndentStart),
|
||||
word2(b'-', b'>', EType::TStart)
|
||||
)
|
||||
.trace("type_annotation:expression:arrow")
|
||||
]
|
||||
.parse(arena, state.clone());
|
||||
.parse(arena, state.clone(), min_indent);
|
||||
|
||||
let (progress, annot, state) = match result {
|
||||
Ok((p2, (rest, _dropped_spaces), state)) => {
|
||||
let (p3, return_type, state) = space0_before_e(
|
||||
term(min_indent, stop_at_surface_has),
|
||||
min_indent,
|
||||
EType::TIndentStart,
|
||||
)
|
||||
.parse(arena, state)?;
|
||||
let (p3, return_type, state) =
|
||||
space0_before_e(term(stop_at_surface_has), EType::TIndentStart)
|
||||
.parse(arena, state, min_indent)?;
|
||||
|
||||
let region = Region::span_across(&first.region, &return_type.region);
|
||||
|
||||
|
@ -641,11 +574,11 @@ fn expression<'a>(
|
|||
Err(err) => {
|
||||
if !is_trailing_comma_valid {
|
||||
let (_, comma, _) = optional(skip_first!(
|
||||
space0_e(min_indent, EType::TIndentStart),
|
||||
space0_e(EType::TIndentStart),
|
||||
word1(b',', EType::TStart)
|
||||
))
|
||||
.trace("check trailing comma")
|
||||
.parse(arena, state.clone())?;
|
||||
.parse(arena, state.clone(), min_indent)?;
|
||||
|
||||
if comma.is_some() {
|
||||
// If the surrounding scope has declared that a trailing comma is not a valid state
|
||||
|
@ -663,8 +596,7 @@ fn expression<'a>(
|
|||
|
||||
// Finally, try to parse a where clause if there is one.
|
||||
// The where clause must be at least as deep as where the type annotation started.
|
||||
let min_where_clause_indent = min_indent;
|
||||
match has_clause_chain(min_where_clause_indent).parse(arena, state.clone()) {
|
||||
match has_clause_chain().parse(arena, state.clone(), min_indent) {
|
||||
Ok((where_progress, (spaces_before, has_chain), state)) => {
|
||||
use crate::ast::Spaceable;
|
||||
|
||||
|
@ -709,13 +641,11 @@ fn expression<'a>(
|
|||
// /// A bound type variable, e.g. `a` in `(a -> a)`
|
||||
// BoundVariable(&'a str),
|
||||
|
||||
fn parse_concrete_type<'a>(
|
||||
arena: &'a Bump,
|
||||
state: State<'a>,
|
||||
) -> ParseResult<'a, TypeAnnotation<'a>, ETypeApply> {
|
||||
fn concrete_type<'a>() -> impl Parser<'a, TypeAnnotation<'a>, ETypeApply> {
|
||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let initial_bytes = state.bytes();
|
||||
|
||||
match crate::ident::concrete_type().parse(arena, state) {
|
||||
match crate::ident::concrete_type().parse(arena, state, min_indent) {
|
||||
Ok((_, (module_name, type_name), state)) => {
|
||||
let answer = TypeAnnotation::Apply(module_name, type_name, &[]);
|
||||
|
||||
|
@ -735,12 +665,15 @@ fn parse_concrete_type<'a>(
|
|||
Ok((MadeProgress, TypeAnnotation::Malformed(parsed_str), state))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_type_variable<'a>(
|
||||
stop_at_surface_has: bool,
|
||||
) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
|
||||
move |arena, state: State<'a>| match crate::ident::lowercase_ident().parse(arena, state) {
|
||||
move |arena, state: State<'a>, min_indent: u32| match crate::ident::lowercase_ident()
|
||||
.parse(arena, state, min_indent)
|
||||
{
|
||||
Ok((_, name, state)) => {
|
||||
if name == "has" && stop_at_surface_has {
|
||||
Err((NoProgress, EType::TEnd(state.pos()), state))
|
||||
|
|
|
@ -37,7 +37,7 @@ mod test_parse {
|
|||
};
|
||||
(module => $arena:expr, $input:expr) => {
|
||||
module_defs()
|
||||
.parse($arena, State::new($input.as_bytes()))
|
||||
.parse($arena, State::new($input.as_bytes()), 0)
|
||||
.map(|tuple| tuple.1)
|
||||
};
|
||||
}
|
||||
|
@ -802,7 +802,7 @@ mod test_parse {
|
|||
"#
|
||||
);
|
||||
let actual = module_defs()
|
||||
.parse(&arena, State::new(src.as_bytes()))
|
||||
.parse(&arena, State::new(src.as_bytes()), 0)
|
||||
.map(|tuple| tuple.1);
|
||||
|
||||
// It should occur twice in the debug output - once for the pattern,
|
||||
|
@ -828,7 +828,7 @@ mod test_parse {
|
|||
|
||||
let state = State::new(src.as_bytes());
|
||||
let parser = module_defs();
|
||||
let parsed = parser.parse(arena, state);
|
||||
let parsed = parser.parse(arena, state, 0);
|
||||
match parsed {
|
||||
Ok((_, _, _state)) => {
|
||||
// dbg!(_state);
|
||||
|
|
|
@ -870,7 +870,7 @@ fn markdown_to_html(
|
|||
// more memory as we iterate through these.
|
||||
arena.reset();
|
||||
|
||||
match parse_ident(&arena, state) {
|
||||
match parse_ident(&arena, state, 0) {
|
||||
Ok((_, Ident::Access { module_name, parts }, _)) => {
|
||||
let mut iter = parts.iter();
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ impl Validator for InputValidator {
|
|||
let arena = bumpalo::Bump::new();
|
||||
let state = roc_parse::state::State::new(ctx.input().trim().as_bytes());
|
||||
|
||||
match roc_parse::expr::parse_loc_expr(0, &arena, state) {
|
||||
match roc_parse::expr::parse_loc_expr(&arena, state, 0) {
|
||||
// Special case some syntax errors to allow for multi-line inputs
|
||||
Err((_, EExpr::DefMissingFinalExpr(_), _))
|
||||
| Err((_, EExpr::DefMissingFinalExpr2(_, _), _))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue