mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
Use and! over and()
This commit is contained in:
parent
76b815ab77
commit
e850703ca9
5 changed files with 127 additions and 111 deletions
|
@ -3,9 +3,23 @@ use bumpalo::collections::vec::Vec;
|
|||
use bumpalo::Bump;
|
||||
use parse::ast::CommentOrNewline::{self, *};
|
||||
use parse::ast::Spaceable;
|
||||
use parse::parser::{and, map_with_arena, unexpected, unexpected_eof, Parser, State};
|
||||
use parse::parser::{map_with_arena, unexpected, unexpected_eof, Parser, State};
|
||||
use region::Located;
|
||||
|
||||
/// For some reason, some functions need to use this instead of using the and! macro directly.
|
||||
#[inline(always)]
|
||||
pub fn and<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, (A, B)>
|
||||
where
|
||||
P1: Parser<'a, A>,
|
||||
P2: Parser<'a, B>,
|
||||
P1: 'a,
|
||||
P2: 'a,
|
||||
A: 'a,
|
||||
B: 'a,
|
||||
{
|
||||
and!(p1, p2)
|
||||
}
|
||||
|
||||
/// Parses the given expression with 0 or more (spaces/comments/newlines) before and/or after it.
|
||||
/// Returns a Located<Expr> where the location is around the Expr, ignoring the spaces.
|
||||
/// If any newlines or comments were found, the Expr will be wrapped in a SpaceBefore and/or
|
||||
|
@ -20,7 +34,7 @@ where
|
|||
{
|
||||
map_with_arena(
|
||||
and(space0(min_indent), and(parser, space0(min_indent))),
|
||||
|arena, (spaces_before, (loc_val, spaces_after))| {
|
||||
move |arena, (spaces_before, (loc_val, spaces_after))| {
|
||||
if spaces_before.is_empty() {
|
||||
if spaces_after.is_empty() {
|
||||
loc_val
|
||||
|
@ -97,7 +111,7 @@ where
|
|||
P: 'a,
|
||||
{
|
||||
map_with_arena(
|
||||
and(space0(min_indent), parser),
|
||||
and!(space0(min_indent), parser),
|
||||
|arena, (space_list, loc_expr)| {
|
||||
if space_list.is_empty() {
|
||||
loc_expr
|
||||
|
@ -121,7 +135,7 @@ where
|
|||
P: 'a,
|
||||
{
|
||||
map_with_arena(
|
||||
and(space1(min_indent), parser),
|
||||
and!(space1(min_indent), parser),
|
||||
|arena, (space_list, loc_expr)| {
|
||||
if space_list.is_empty() {
|
||||
loc_expr
|
||||
|
@ -145,7 +159,7 @@ where
|
|||
P: 'a,
|
||||
{
|
||||
map_with_arena(
|
||||
and(parser, space0(min_indent)),
|
||||
and!(parser, space0(min_indent)),
|
||||
|arena, (loc_expr, space_list)| {
|
||||
if space_list.is_empty() {
|
||||
loc_expr
|
||||
|
@ -169,7 +183,7 @@ where
|
|||
P: 'a,
|
||||
{
|
||||
map_with_arena(
|
||||
and(parser, space1(min_indent)),
|
||||
and!(parser, space1(min_indent)),
|
||||
|arena, (loc_expr, space_list)| {
|
||||
if space_list.is_empty() {
|
||||
loc_expr
|
||||
|
|
106
src/parse/mod.rs
106
src/parse/mod.rs
|
@ -1,3 +1,5 @@
|
|||
#[macro_use]
|
||||
pub mod parser;
|
||||
pub mod ast;
|
||||
pub mod blankspace;
|
||||
pub mod collection;
|
||||
|
@ -5,8 +7,6 @@ pub mod ident;
|
|||
pub mod keyword;
|
||||
pub mod module;
|
||||
pub mod number_literal;
|
||||
#[macro_use]
|
||||
pub mod parser;
|
||||
pub mod problems;
|
||||
pub mod record;
|
||||
pub mod string_literal;
|
||||
|
@ -28,10 +28,10 @@ use parse::collection::collection;
|
|||
use parse::ident::{ident, unqualified_ident, variant_or_ident, Ident};
|
||||
use parse::number_literal::number_literal;
|
||||
use parse::parser::{
|
||||
allocated, and, attempt, between, char, either, map, map_with_arena, not, not_followed_by,
|
||||
one_of10, one_of17, one_of2, one_of3, one_of5, one_of6, one_or_more, optional, skip_first,
|
||||
skip_second, string, then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason,
|
||||
ParseResult, Parser, State,
|
||||
allocated, attempt, between, char, either, map, map_with_arena, not, not_followed_by, one_of10,
|
||||
one_of17, one_of2, one_of3, one_of5, one_of6, one_or_more, optional, skip_first, skip_second,
|
||||
string, then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason, ParseResult,
|
||||
Parser, State,
|
||||
};
|
||||
use parse::record::record;
|
||||
use region::{Located, Region};
|
||||
|
@ -42,14 +42,14 @@ pub fn module<'a>() -> impl Parser<'a, Module<'a>> {
|
|||
|
||||
#[inline(always)]
|
||||
fn interface_module<'a>() -> impl Parser<'a, Module<'a>> {
|
||||
map(and(interface_header(), module_defs()), |(header, defs)| {
|
||||
map(and!(interface_header(), module_defs()), |(header, defs)| {
|
||||
Module::Interface { header, defs }
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn app_module<'a>() -> impl Parser<'a, Module<'a>> {
|
||||
map(and(app_header(), module_defs()), |(header, defs)| {
|
||||
map(and!(app_header(), module_defs()), |(header, defs)| {
|
||||
Module::App { header, defs }
|
||||
})
|
||||
}
|
||||
|
@ -57,9 +57,9 @@ fn app_module<'a>() -> impl Parser<'a, Module<'a>> {
|
|||
#[inline(always)]
|
||||
fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>> {
|
||||
map(
|
||||
and(
|
||||
skip_first(string("interface"), and(space1(1), loc!(ident()))),
|
||||
and(mod_header_list("exposes"), mod_header_list("imports")),
|
||||
and!(
|
||||
skip_first(string("interface"), and!(space1(1), loc!(ident()))),
|
||||
and!(mod_header_list("exposes"), mod_header_list("imports"))
|
||||
),
|
||||
|(
|
||||
(after_interface, loc_name_ident),
|
||||
|
@ -117,9 +117,9 @@ fn mod_header_list<'a>(
|
|||
Vec<'a, Located<HeaderEntry<'a>>>,
|
||||
),
|
||||
> {
|
||||
and(
|
||||
and(skip_second(space1(1), string(kw)), space1(1)),
|
||||
collection(char('['), loc!(mod_header_entry()), char(','), char(']'), 1),
|
||||
and!(
|
||||
and!(skip_second(space1(1), string(kw)), space1(1)),
|
||||
collection(char('['), loc!(mod_header_entry()), char(','), char(']'), 1)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,7 @@ fn mod_header_entry<'a>() -> impl Parser<'a, HeaderEntry<'a>> {
|
|||
one_of2(
|
||||
map(unqualified_ident(), |ident| HeaderEntry::Val(ident)),
|
||||
map(
|
||||
and(unqualified_variant(), optional(string("..."))),
|
||||
and!(unqualified_variant(), optional(string("..."))),
|
||||
|(ident, opt_ellipsis)| match opt_ellipsis {
|
||||
None => HeaderEntry::TypeOnly(ident),
|
||||
Some(()) => HeaderEntry::TypeAndVariants(ident),
|
||||
|
@ -170,18 +170,18 @@ fn loc_parse_expr_body_without_operators<'a>(
|
|||
pub fn unary_op<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||
one_of2(
|
||||
map_with_arena(
|
||||
and(
|
||||
and!(
|
||||
loc!(char('!')),
|
||||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||
loc!(move |arena, state| parse_expr(min_indent, arena, state))
|
||||
),
|
||||
|arena, (loc_op, loc_expr)| {
|
||||
Expr::UnaryOp(arena.alloc(loc_expr), loc_op.map(|_| UnaryOp::Not))
|
||||
},
|
||||
),
|
||||
map_with_arena(
|
||||
and(
|
||||
and!(
|
||||
loc!(char('-')),
|
||||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||
loc!(move |arena, state| parse_expr(min_indent, arena, state))
|
||||
),
|
||||
|arena, (loc_op, loc_expr)| {
|
||||
Expr::UnaryOp(arena.alloc(loc_expr), loc_op.map(|_| UnaryOp::Negate))
|
||||
|
@ -192,7 +192,7 @@ pub fn unary_op<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
|||
|
||||
fn parse_expr<'a>(min_indent: u16, arena: &'a Bump, state: State<'a>) -> ParseResult<'a, Expr<'a>> {
|
||||
let expr_parser = map_with_arena(
|
||||
and(
|
||||
and!(
|
||||
// First parse the body without operators, then try to parse possible operators after.
|
||||
move |arena, state| loc_parse_expr_body_without_operators(min_indent, arena, state),
|
||||
// Parse the operator, with optional spaces before it.
|
||||
|
@ -200,15 +200,15 @@ fn parse_expr<'a>(min_indent: u16, arena: &'a Bump, state: State<'a>) -> ParseRe
|
|||
// Since spaces can only wrap an Expr, not an BinOp, we have to first
|
||||
// parse the spaces and then attach them retroactively to the expression
|
||||
// preceding the operator (the one we parsed before considering operators).
|
||||
optional(and(
|
||||
and(space0(min_indent), loc!(binop())),
|
||||
optional(and!(
|
||||
and!(space0(min_indent), loc!(binop())),
|
||||
// The spaces *after* the operator can be attached directly to
|
||||
// the expression following the operator.
|
||||
space0_before(
|
||||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||
min_indent,
|
||||
),
|
||||
)),
|
||||
)
|
||||
))
|
||||
),
|
||||
|arena, (loc_expr1, opt_operator)| match opt_operator {
|
||||
Some(((spaces_before_op, loc_op), loc_expr2)) => {
|
||||
|
@ -233,7 +233,7 @@ fn parse_expr<'a>(min_indent: u16, arena: &'a Bump, state: State<'a>) -> ParseRe
|
|||
|
||||
pub fn loc_parenthetical_expr<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>> {
|
||||
then(
|
||||
loc!(and(
|
||||
loc!(and!(
|
||||
between(
|
||||
char('('),
|
||||
space0_around(
|
||||
|
@ -257,9 +257,9 @@ pub fn loc_parenthetical_expr<'a>(min_indent: u16) -> impl Parser<'a, Located<Ex
|
|||
// e.g. in `((foo bar) baz.blah)` the `.blah` will be consumed by the `baz` parser
|
||||
either(
|
||||
one_or_more(skip_first(char('.'), unqualified_ident())),
|
||||
and(space0(min_indent), equals_with_indent()),
|
||||
and!(space0(min_indent), equals_with_indent()),
|
||||
),
|
||||
)),
|
||||
))
|
||||
)),
|
||||
move |arena, state, loc_expr_with_extras| {
|
||||
// We parse the parenthetical expression *and* the arguments after it
|
||||
|
@ -428,7 +428,7 @@ fn expr_to_pattern<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<'a>,
|
|||
/// It would be too weird to parse; imagine `(UserId userId) : ...` above `(UserId userId) = ...`
|
||||
pub fn loc_parenthetical_def<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>> {
|
||||
move |arena, state| {
|
||||
let (loc_tuple, state) = loc!(and(
|
||||
let (loc_tuple, state) = loc!(and!(
|
||||
space0_after(
|
||||
between(
|
||||
char('('),
|
||||
|
@ -437,7 +437,7 @@ pub fn loc_parenthetical_def<'a>(min_indent: u16) -> impl Parser<'a, Located<Exp
|
|||
),
|
||||
min_indent,
|
||||
),
|
||||
equals_with_indent(),
|
||||
equals_with_indent()
|
||||
))
|
||||
.parse(arena, state)?;
|
||||
|
||||
|
@ -475,7 +475,7 @@ pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
|
|||
one_of2(
|
||||
// Constant or annotation
|
||||
map_with_arena(
|
||||
and(
|
||||
and!(
|
||||
// A pattern followed by '=' or ':'
|
||||
space0_after(loc_closure_param(min_indent), min_indent),
|
||||
either(
|
||||
|
@ -496,7 +496,7 @@ pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
|
|||
// The type itself must be indented more than the pattern and ':'
|
||||
space0_before(type_annotation::located(indented_more), indented_more),
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
|arena, (loc_pattern, expr_or_ann)| match expr_or_ann {
|
||||
Either::First(loc_expr) => Def::Body(loc_pattern, arena.alloc(loc_expr)),
|
||||
|
@ -505,7 +505,7 @@ pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
|
|||
),
|
||||
// Type alias or custom type (uppercase ident followed by `:` or `:=` and type annotation)
|
||||
map(
|
||||
and(
|
||||
and!(
|
||||
skip_second(
|
||||
// TODO FIXME this may need special logic to parse the first part of the type,
|
||||
// then parse the rest with increased indentation. The current implementation
|
||||
|
@ -536,7 +536,7 @@ pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
|
|||
),
|
||||
// Alias
|
||||
space0_before(type_annotation::located(min_indent), min_indent),
|
||||
),
|
||||
)
|
||||
),
|
||||
|(loc_type_name, rest)| match rest {
|
||||
Either::First(loc_ann) => Def::CustomType(loc_type_name, loc_ann),
|
||||
|
@ -573,7 +573,7 @@ fn parse_def_expr<'a>(
|
|||
then(
|
||||
attempt(
|
||||
Attempting::Def,
|
||||
and(
|
||||
and!(
|
||||
// Parse the body of the first def. It doesn't need any spaces
|
||||
// around it parsed, because both the subsquent defs and the
|
||||
// final body will have space1_before on them.
|
||||
|
@ -581,7 +581,7 @@ fn parse_def_expr<'a>(
|
|||
// It should be indented more than the original, and it will
|
||||
// end when outdented again.
|
||||
loc!(move |arena, state| parse_expr(indented_more, arena, state)),
|
||||
and(
|
||||
and!(
|
||||
// Optionally parse additional defs.
|
||||
zero_or_more(allocated(space1_before(
|
||||
loc!(def(original_indent)),
|
||||
|
@ -592,8 +592,8 @@ fn parse_def_expr<'a>(
|
|||
space1_before(
|
||||
loc!(move |arena, state| parse_expr(original_indent, arena, state)),
|
||||
original_indent,
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
move |arena, state, (loc_first_body, (mut defs, loc_ret))| {
|
||||
|
@ -671,7 +671,7 @@ fn closure<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
|||
char('\\'),
|
||||
// Once we see the '\', we're committed to parsing this as a closure.
|
||||
// It may turn out to be malformed, but it is definitely a closure.
|
||||
optional(and(
|
||||
optional(and!(
|
||||
// Parse the params
|
||||
attempt(
|
||||
Attempting::ClosureParams,
|
||||
|
@ -694,7 +694,7 @@ fn closure<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
|||
min_indent,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
)),
|
||||
),
|
||||
|arena, opt_contents| match opt_contents {
|
||||
|
@ -786,7 +786,7 @@ fn ident_pattern<'a>() -> impl Parser<'a, Pattern<'a>> {
|
|||
|
||||
pub fn case_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||
then(
|
||||
and(
|
||||
and!(
|
||||
case_with_indent(),
|
||||
attempt(
|
||||
Attempting::CaseCondition,
|
||||
|
@ -797,7 +797,7 @@ pub fn case_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
|||
),
|
||||
string(keyword::WHEN),
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
move |arena, state, (case_indent, loc_condition)| {
|
||||
if case_indent < min_indent {
|
||||
|
@ -854,7 +854,7 @@ pub fn case_branches<'a>(
|
|||
// Record this as the first branch, then optionally parse additional branches.
|
||||
branches.push(arena.alloc((loc_first_pattern, loc_first_expr)));
|
||||
|
||||
let branch_parser = and(
|
||||
let branch_parser = and!(
|
||||
then(
|
||||
space1_around(loc!(pattern(min_indent)), min_indent),
|
||||
move |_arena, state, loc_pattern| {
|
||||
|
@ -873,7 +873,7 @@ pub fn case_branches<'a>(
|
|||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||
min_indent,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
loop {
|
||||
|
@ -897,7 +897,7 @@ pub fn case_branches<'a>(
|
|||
|
||||
pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||
map_with_arena(
|
||||
and(
|
||||
and!(
|
||||
skip_first(
|
||||
string(keyword::IF),
|
||||
space1_around(
|
||||
|
@ -905,7 +905,7 @@ pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
|||
min_indent,
|
||||
),
|
||||
),
|
||||
and(
|
||||
and!(
|
||||
skip_first(
|
||||
string(keyword::THEN),
|
||||
space1_around(
|
||||
|
@ -919,8 +919,8 @@ pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
|||
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
|
||||
min_indent,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
),
|
||||
|arena, (condition, (then_branch, else_branch))| {
|
||||
Expr::If(arena.alloc((condition, then_branch, else_branch)))
|
||||
|
@ -946,7 +946,7 @@ fn unary_negate_function_arg<'a>(min_indent: u16) -> impl Parser<'a, Located<Exp
|
|||
then(
|
||||
// Spaces, then '-', then *not* more spaces.
|
||||
not_followed_by(
|
||||
and(space1(min_indent), loc!(char('-'))),
|
||||
and!(space1(min_indent), loc!(char('-'))),
|
||||
one_of3(char(' '), char('#'), char('\n')),
|
||||
),
|
||||
move |arena, state, (spaces, loc_minus_char)| {
|
||||
|
@ -1009,7 +1009,7 @@ fn loc_function_args<'a>(min_indent: u16) -> impl Parser<'a, Vec<'a, Located<Exp
|
|||
/// 5. A reserved keyword (e.g. `if ` or `case `), meaning we should do something else.
|
||||
pub fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||
then(
|
||||
and(
|
||||
and!(
|
||||
loc!(ident()),
|
||||
optional(either(
|
||||
// There may optionally be function args after this ident
|
||||
|
@ -1017,8 +1017,8 @@ pub fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
|||
// If there aren't any args, there may be a '=' or ':' after it.
|
||||
// (It's a syntax error to write e.g. `foo bar =` - so if there
|
||||
// were any args, there is definitely no need to parse '=' or ':'!)
|
||||
and(space0(min_indent), either(equals_with_indent(), char(':'))),
|
||||
)),
|
||||
and!(space0(min_indent), either(equals_with_indent(), char(':'))),
|
||||
))
|
||||
),
|
||||
move |arena, state, (loc_ident, opt_extras)| {
|
||||
// This appears to be a var, keyword, or function application.
|
||||
|
@ -1179,12 +1179,12 @@ pub fn list_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
|||
// Parser<'a, Vec<'a, Located<AssignedField<'a, S>>>>
|
||||
pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
|
||||
then(
|
||||
and(
|
||||
and!(
|
||||
attempt(
|
||||
Attempting::Record,
|
||||
loc!(record(loc!(expr(min_indent)), min_indent)),
|
||||
),
|
||||
optional(and(space0(min_indent), equals_with_indent())),
|
||||
optional(and!(space0(min_indent), equals_with_indent()))
|
||||
),
|
||||
move |arena, state, (loc_assigned_fields, opt_def)| match opt_def {
|
||||
None => {
|
||||
|
|
|
@ -574,39 +574,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn and_impl<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, (A, B)>
|
||||
where
|
||||
P1: Parser<'a, A>,
|
||||
P2: Parser<'a, B>,
|
||||
{
|
||||
move |arena: &'a Bump, state: State<'a>| {
|
||||
// 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((out1, state)) => match p2.parse(arena, state) {
|
||||
Ok((out2, state)) => Ok(((out1, out2), state)),
|
||||
Err((fail, _)) => Err((
|
||||
Fail {
|
||||
attempting: original_state.attempting,
|
||||
..fail
|
||||
},
|
||||
original_state,
|
||||
)),
|
||||
},
|
||||
Err((fail, state)) => Err((
|
||||
Fail {
|
||||
attempting: original_state.attempting,
|
||||
..fail
|
||||
},
|
||||
state,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn either_impl<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, Either<A, B>>
|
||||
where
|
||||
|
@ -1270,18 +1237,6 @@ where
|
|||
BoxedParser::new(map_impl(parser, transform))
|
||||
}
|
||||
|
||||
pub fn and<'a, P1, P2, A, B>(p1: P1, p2: P2) -> BoxedParser<'a, (A, B)>
|
||||
where
|
||||
P1: Parser<'a, A>,
|
||||
P2: Parser<'a, B>,
|
||||
P1: 'a,
|
||||
P2: 'a,
|
||||
A: 'a,
|
||||
B: 'a,
|
||||
{
|
||||
BoxedParser::new(and_impl(p1, p2))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn map_with_arena_impl<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
|
||||
where
|
||||
|
@ -1347,7 +1302,7 @@ where
|
|||
#[macro_export]
|
||||
macro_rules! loc {
|
||||
($parser:expr) => {
|
||||
move |arena, state: State<'a>| {
|
||||
move |arena, state: $crate::parse::parser::State<'a>| {
|
||||
use $crate::region::{Located, Region};
|
||||
|
||||
let start_col = state.column;
|
||||
|
@ -1371,3 +1326,36 @@ macro_rules! loc {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! and {
|
||||
($p1:expr, $p2:expr) => {
|
||||
move |arena: &'a bumpalo::Bump, state: $crate::parse::parser::State<'a>| {
|
||||
use $crate::parse::parser::Fail;
|
||||
|
||||
// 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((out1, state)) => match $p2.parse(arena, state) {
|
||||
Ok((out2, state)) => Ok(((out1, out2), state)),
|
||||
Err((fail, _)) => Err((
|
||||
Fail {
|
||||
attempting: original_state.attempting,
|
||||
..fail
|
||||
},
|
||||
original_state,
|
||||
)),
|
||||
},
|
||||
Err((fail, state)) => Err((
|
||||
Fail {
|
||||
attempting: original_state.attempting,
|
||||
..fail
|
||||
},
|
||||
state,
|
||||
)),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use parse::ast::Spaceable;
|
|||
use parse::blankspace::{space0, space0_before};
|
||||
use parse::collection::collection;
|
||||
use parse::ident::unqualified_ident;
|
||||
use parse::parser::{and, char, map_with_arena, optional, skip_first, Parser, State};
|
||||
use parse::parser::{char, map_with_arena, optional, skip_first, Parser};
|
||||
use region::Located;
|
||||
|
||||
/// Parse a record - generally one of these two:
|
||||
|
@ -39,6 +39,20 @@ where
|
|||
loc!(parser)
|
||||
}
|
||||
|
||||
/// For some reason, record_field() needs to use this instead of using the and! macro directly.
|
||||
#[inline(always)]
|
||||
pub fn and<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, (A, B)>
|
||||
where
|
||||
P1: Parser<'a, A>,
|
||||
P2: Parser<'a, B>,
|
||||
P1: 'a,
|
||||
P2: 'a,
|
||||
A: 'a,
|
||||
B: 'a,
|
||||
{
|
||||
and!(p1, p2)
|
||||
}
|
||||
|
||||
fn record_field<'a, P, S>(val_parser: P, min_indent: u16) -> impl Parser<'a, AssignedField<'a, S>>
|
||||
where
|
||||
P: Parser<'a, Located<S>>,
|
||||
|
|
|
@ -5,7 +5,7 @@ use collections::arena_join;
|
|||
use parse::ast::{Attempting, TypeAnnotation};
|
||||
use parse::blankspace::{space0_around, space1_before};
|
||||
use parse::parser::{
|
||||
and, between, char, map, map_with_arena, one_of5, optional, skip_first, string, unexpected,
|
||||
between, char, map, map_with_arena, one_of5, optional, skip_first, string, unexpected,
|
||||
unexpected_eof, zero_or_more, ParseResult, Parser, State,
|
||||
};
|
||||
use parse::record::record;
|
||||
|
@ -41,7 +41,7 @@ fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>> {
|
|||
use parse::type_annotation::TypeAnnotation::*;
|
||||
|
||||
map_with_arena(
|
||||
and(
|
||||
and!(
|
||||
record(
|
||||
move |arena, state| located(min_indent).parse(arena, state),
|
||||
min_indent,
|
||||
|
@ -50,7 +50,7 @@ fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>> {
|
|||
// This could be a record fragment, e.g. `{ name: String }...r`
|
||||
string("..."),
|
||||
move |arena, state| located(min_indent).parse(arena, state),
|
||||
)),
|
||||
))
|
||||
),
|
||||
|arena, (rec, opt_bound_var)| match opt_bound_var {
|
||||
None => Record(rec),
|
||||
|
@ -61,14 +61,14 @@ fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>> {
|
|||
|
||||
fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>> {
|
||||
map(
|
||||
and(
|
||||
and!(
|
||||
parse_concrete_type,
|
||||
// Optionally parse space-separated arguments for the constructor,
|
||||
// e.g. `Str Float` in `Map Str Float`
|
||||
zero_or_more(space1_before(
|
||||
move |arena, state| located(min_indent).parse(arena, state),
|
||||
min_indent,
|
||||
)),
|
||||
))
|
||||
),
|
||||
|(ctor, args)| {
|
||||
match &ctor {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue