Use and! over and()

This commit is contained in:
Richard Feldman 2019-11-20 06:23:21 -05:00
parent 76b815ab77
commit e850703ca9
5 changed files with 127 additions and 111 deletions

View file

@ -3,9 +3,23 @@ use bumpalo::collections::vec::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use parse::ast::CommentOrNewline::{self, *}; use parse::ast::CommentOrNewline::{self, *};
use parse::ast::Spaceable; 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; 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. /// 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. /// 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 /// 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( map_with_arena(
and(space0(min_indent), and(parser, space0(min_indent))), 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_before.is_empty() {
if spaces_after.is_empty() { if spaces_after.is_empty() {
loc_val loc_val
@ -97,7 +111,7 @@ where
P: 'a, P: 'a,
{ {
map_with_arena( map_with_arena(
and(space0(min_indent), parser), and!(space0(min_indent), parser),
|arena, (space_list, loc_expr)| { |arena, (space_list, loc_expr)| {
if space_list.is_empty() { if space_list.is_empty() {
loc_expr loc_expr
@ -121,7 +135,7 @@ where
P: 'a, P: 'a,
{ {
map_with_arena( map_with_arena(
and(space1(min_indent), parser), and!(space1(min_indent), parser),
|arena, (space_list, loc_expr)| { |arena, (space_list, loc_expr)| {
if space_list.is_empty() { if space_list.is_empty() {
loc_expr loc_expr
@ -145,7 +159,7 @@ where
P: 'a, P: 'a,
{ {
map_with_arena( map_with_arena(
and(parser, space0(min_indent)), and!(parser, space0(min_indent)),
|arena, (loc_expr, space_list)| { |arena, (loc_expr, space_list)| {
if space_list.is_empty() { if space_list.is_empty() {
loc_expr loc_expr
@ -169,7 +183,7 @@ where
P: 'a, P: 'a,
{ {
map_with_arena( map_with_arena(
and(parser, space1(min_indent)), and!(parser, space1(min_indent)),
|arena, (loc_expr, space_list)| { |arena, (loc_expr, space_list)| {
if space_list.is_empty() { if space_list.is_empty() {
loc_expr loc_expr

View file

@ -1,3 +1,5 @@
#[macro_use]
pub mod parser;
pub mod ast; pub mod ast;
pub mod blankspace; pub mod blankspace;
pub mod collection; pub mod collection;
@ -5,8 +7,6 @@ pub mod ident;
pub mod keyword; pub mod keyword;
pub mod module; pub mod module;
pub mod number_literal; pub mod number_literal;
#[macro_use]
pub mod parser;
pub mod problems; pub mod problems;
pub mod record; pub mod record;
pub mod string_literal; pub mod string_literal;
@ -28,10 +28,10 @@ use parse::collection::collection;
use parse::ident::{ident, unqualified_ident, variant_or_ident, Ident}; use parse::ident::{ident, unqualified_ident, variant_or_ident, Ident};
use parse::number_literal::number_literal; use parse::number_literal::number_literal;
use parse::parser::{ use parse::parser::{
allocated, and, attempt, between, char, either, map, map_with_arena, not, not_followed_by, allocated, attempt, between, char, either, map, map_with_arena, not, not_followed_by, one_of10,
one_of10, one_of17, one_of2, one_of3, one_of5, one_of6, one_or_more, optional, skip_first, one_of17, one_of2, one_of3, one_of5, one_of6, one_or_more, optional, skip_first, skip_second,
skip_second, string, then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason, string, then, unexpected, unexpected_eof, zero_or_more, Either, Fail, FailReason, ParseResult,
ParseResult, Parser, State, Parser, State,
}; };
use parse::record::record; use parse::record::record;
use region::{Located, Region}; use region::{Located, Region};
@ -42,14 +42,14 @@ pub fn module<'a>() -> impl Parser<'a, Module<'a>> {
#[inline(always)] #[inline(always)]
fn interface_module<'a>() -> impl Parser<'a, Module<'a>> { 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 } Module::Interface { header, defs }
}) })
} }
#[inline(always)] #[inline(always)]
fn app_module<'a>() -> impl Parser<'a, Module<'a>> { 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 } Module::App { header, defs }
}) })
} }
@ -57,9 +57,9 @@ fn app_module<'a>() -> impl Parser<'a, Module<'a>> {
#[inline(always)] #[inline(always)]
fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>> { fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>> {
map( map(
and( and!(
skip_first(string("interface"), and(space1(1), loc!(ident()))), skip_first(string("interface"), and!(space1(1), loc!(ident()))),
and(mod_header_list("exposes"), mod_header_list("imports")), and!(mod_header_list("exposes"), mod_header_list("imports"))
), ),
|( |(
(after_interface, loc_name_ident), (after_interface, loc_name_ident),
@ -117,9 +117,9 @@ fn mod_header_list<'a>(
Vec<'a, Located<HeaderEntry<'a>>>, Vec<'a, Located<HeaderEntry<'a>>>,
), ),
> { > {
and( and!(
and(skip_second(space1(1), string(kw)), space1(1)), and!(skip_second(space1(1), string(kw)), space1(1)),
collection(char('['), loc!(mod_header_entry()), char(','), char(']'), 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( one_of2(
map(unqualified_ident(), |ident| HeaderEntry::Val(ident)), map(unqualified_ident(), |ident| HeaderEntry::Val(ident)),
map( map(
and(unqualified_variant(), optional(string("..."))), and!(unqualified_variant(), optional(string("..."))),
|(ident, opt_ellipsis)| match opt_ellipsis { |(ident, opt_ellipsis)| match opt_ellipsis {
None => HeaderEntry::TypeOnly(ident), None => HeaderEntry::TypeOnly(ident),
Some(()) => HeaderEntry::TypeAndVariants(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>> { pub fn unary_op<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
one_of2( one_of2(
map_with_arena( map_with_arena(
and( and!(
loc!(char('!')), 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)| { |arena, (loc_op, loc_expr)| {
Expr::UnaryOp(arena.alloc(loc_expr), loc_op.map(|_| UnaryOp::Not)) Expr::UnaryOp(arena.alloc(loc_expr), loc_op.map(|_| UnaryOp::Not))
}, },
), ),
map_with_arena( map_with_arena(
and( and!(
loc!(char('-')), 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)| { |arena, (loc_op, loc_expr)| {
Expr::UnaryOp(arena.alloc(loc_expr), loc_op.map(|_| UnaryOp::Negate)) 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>> { fn parse_expr<'a>(min_indent: u16, arena: &'a Bump, state: State<'a>) -> ParseResult<'a, Expr<'a>> {
let expr_parser = map_with_arena( let expr_parser = map_with_arena(
and( and!(
// First parse the body without operators, then try to parse possible operators after. // 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), move |arena, state| loc_parse_expr_body_without_operators(min_indent, arena, state),
// Parse the operator, with optional spaces before it. // 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 // 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 // parse the spaces and then attach them retroactively to the expression
// preceding the operator (the one we parsed before considering operators). // preceding the operator (the one we parsed before considering operators).
optional(and( optional(and!(
and(space0(min_indent), loc!(binop())), and!(space0(min_indent), loc!(binop())),
// The spaces *after* the operator can be attached directly to // The spaces *after* the operator can be attached directly to
// the expression following the operator. // the expression following the operator.
space0_before( space0_before(
loc!(move |arena, state| parse_expr(min_indent, arena, state)), loc!(move |arena, state| parse_expr(min_indent, arena, state)),
min_indent, min_indent,
), )
)), ))
), ),
|arena, (loc_expr1, opt_operator)| match opt_operator { |arena, (loc_expr1, opt_operator)| match opt_operator {
Some(((spaces_before_op, loc_op), loc_expr2)) => { 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>>> { pub fn loc_parenthetical_expr<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>> {
then( then(
loc!(and( loc!(and!(
between( between(
char('('), char('('),
space0_around( 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 // e.g. in `((foo bar) baz.blah)` the `.blah` will be consumed by the `baz` parser
either( either(
one_or_more(skip_first(char('.'), unqualified_ident())), 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| { move |arena, state, loc_expr_with_extras| {
// We parse the parenthetical expression *and* the arguments after it // 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) = ...` /// 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>>> { pub fn loc_parenthetical_def<'a>(min_indent: u16) -> impl Parser<'a, Located<Expr<'a>>> {
move |arena, state| { move |arena, state| {
let (loc_tuple, state) = loc!(and( let (loc_tuple, state) = loc!(and!(
space0_after( space0_after(
between( between(
char('('), char('('),
@ -437,7 +437,7 @@ pub fn loc_parenthetical_def<'a>(min_indent: u16) -> impl Parser<'a, Located<Exp
), ),
min_indent, min_indent,
), ),
equals_with_indent(), equals_with_indent()
)) ))
.parse(arena, state)?; .parse(arena, state)?;
@ -475,7 +475,7 @@ pub fn def<'a>(min_indent: u16) -> impl Parser<'a, Def<'a>> {
one_of2( one_of2(
// Constant or annotation // Constant or annotation
map_with_arena( map_with_arena(
and( and!(
// A pattern followed by '=' or ':' // A pattern followed by '=' or ':'
space0_after(loc_closure_param(min_indent), min_indent), space0_after(loc_closure_param(min_indent), min_indent),
either( 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 ':' // The type itself must be indented more than the pattern and ':'
space0_before(type_annotation::located(indented_more), indented_more), space0_before(type_annotation::located(indented_more), indented_more),
), ),
), )
), ),
|arena, (loc_pattern, expr_or_ann)| match expr_or_ann { |arena, (loc_pattern, expr_or_ann)| match expr_or_ann {
Either::First(loc_expr) => Def::Body(loc_pattern, arena.alloc(loc_expr)), 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) // Type alias or custom type (uppercase ident followed by `:` or `:=` and type annotation)
map( map(
and( and!(
skip_second( skip_second(
// TODO FIXME this may need special logic to parse the first part of the type, // 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 // 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 // Alias
space0_before(type_annotation::located(min_indent), min_indent), space0_before(type_annotation::located(min_indent), min_indent),
), )
), ),
|(loc_type_name, rest)| match rest { |(loc_type_name, rest)| match rest {
Either::First(loc_ann) => Def::CustomType(loc_type_name, loc_ann), Either::First(loc_ann) => Def::CustomType(loc_type_name, loc_ann),
@ -573,7 +573,7 @@ fn parse_def_expr<'a>(
then( then(
attempt( attempt(
Attempting::Def, Attempting::Def,
and( and!(
// Parse the body of the first def. It doesn't need any spaces // Parse the body of the first def. It doesn't need any spaces
// around it parsed, because both the subsquent defs and the // around it parsed, because both the subsquent defs and the
// final body will have space1_before on them. // 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 // It should be indented more than the original, and it will
// end when outdented again. // end when outdented again.
loc!(move |arena, state| parse_expr(indented_more, arena, state)), loc!(move |arena, state| parse_expr(indented_more, arena, state)),
and( and!(
// Optionally parse additional defs. // Optionally parse additional defs.
zero_or_more(allocated(space1_before( zero_or_more(allocated(space1_before(
loc!(def(original_indent)), loc!(def(original_indent)),
@ -592,8 +592,8 @@ fn parse_def_expr<'a>(
space1_before( space1_before(
loc!(move |arena, state| parse_expr(original_indent, arena, state)), loc!(move |arena, state| parse_expr(original_indent, arena, state)),
original_indent, original_indent,
), )
), )
), ),
), ),
move |arena, state, (loc_first_body, (mut defs, loc_ret))| { 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('\\'), char('\\'),
// Once we see the '\', we're committed to parsing this as a closure. // 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. // It may turn out to be malformed, but it is definitely a closure.
optional(and( optional(and!(
// Parse the params // Parse the params
attempt( attempt(
Attempting::ClosureParams, Attempting::ClosureParams,
@ -694,7 +694,7 @@ fn closure<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
min_indent, min_indent,
), ),
), ),
), )
)), )),
), ),
|arena, opt_contents| match opt_contents { |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>> { pub fn case_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
then( then(
and( and!(
case_with_indent(), case_with_indent(),
attempt( attempt(
Attempting::CaseCondition, Attempting::CaseCondition,
@ -797,7 +797,7 @@ pub fn case_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
), ),
string(keyword::WHEN), string(keyword::WHEN),
), ),
), )
), ),
move |arena, state, (case_indent, loc_condition)| { move |arena, state, (case_indent, loc_condition)| {
if case_indent < min_indent { 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. // Record this as the first branch, then optionally parse additional branches.
branches.push(arena.alloc((loc_first_pattern, loc_first_expr))); branches.push(arena.alloc((loc_first_pattern, loc_first_expr)));
let branch_parser = and( let branch_parser = and!(
then( then(
space1_around(loc!(pattern(min_indent)), min_indent), space1_around(loc!(pattern(min_indent)), min_indent),
move |_arena, state, loc_pattern| { move |_arena, state, loc_pattern| {
@ -873,7 +873,7 @@ pub fn case_branches<'a>(
loc!(move |arena, state| parse_expr(min_indent, arena, state)), loc!(move |arena, state| parse_expr(min_indent, arena, state)),
min_indent, min_indent,
), ),
), )
); );
loop { loop {
@ -897,7 +897,7 @@ pub fn case_branches<'a>(
pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> { pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
map_with_arena( map_with_arena(
and( and!(
skip_first( skip_first(
string(keyword::IF), string(keyword::IF),
space1_around( space1_around(
@ -905,7 +905,7 @@ pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
min_indent, min_indent,
), ),
), ),
and( and!(
skip_first( skip_first(
string(keyword::THEN), string(keyword::THEN),
space1_around( 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)), loc!(move |arena, state| parse_expr(min_indent, arena, state)),
min_indent, min_indent,
), ),
), )
), )
), ),
|arena, (condition, (then_branch, else_branch))| { |arena, (condition, (then_branch, else_branch))| {
Expr::If(arena.alloc((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( then(
// Spaces, then '-', then *not* more spaces. // Spaces, then '-', then *not* more spaces.
not_followed_by( not_followed_by(
and(space1(min_indent), loc!(char('-'))), and!(space1(min_indent), loc!(char('-'))),
one_of3(char(' '), char('#'), char('\n')), one_of3(char(' '), char('#'), char('\n')),
), ),
move |arena, state, (spaces, loc_minus_char)| { 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. /// 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>> { pub fn ident_etc<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
then( then(
and( and!(
loc!(ident()), loc!(ident()),
optional(either( optional(either(
// There may optionally be function args after this ident // 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. // 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 // (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 ':'!) // 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)| { move |arena, state, (loc_ident, opt_extras)| {
// This appears to be a var, keyword, or function application. // 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>>>> // Parser<'a, Vec<'a, Located<AssignedField<'a, S>>>>
pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> { pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
then( then(
and( and!(
attempt( attempt(
Attempting::Record, Attempting::Record,
loc!(record(loc!(expr(min_indent)), min_indent)), 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 { move |arena, state, (loc_assigned_fields, opt_def)| match opt_def {
None => { None => {

View file

@ -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)] #[inline(always)]
pub fn either_impl<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, Either<A, B>> pub fn either_impl<'a, P1, P2, A, B>(p1: P1, p2: P2) -> impl Parser<'a, Either<A, B>>
where where
@ -1270,18 +1237,6 @@ where
BoxedParser::new(map_impl(parser, transform)) 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)] #[inline(always)]
fn map_with_arena_impl<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After> fn map_with_arena_impl<'a, P, F, Before, After>(parser: P, transform: F) -> impl Parser<'a, After>
where where
@ -1347,7 +1302,7 @@ where
#[macro_export] #[macro_export]
macro_rules! loc { macro_rules! loc {
($parser:expr) => { ($parser:expr) => {
move |arena, state: State<'a>| { move |arena, state: $crate::parse::parser::State<'a>| {
use $crate::region::{Located, Region}; use $crate::region::{Located, Region};
let start_col = state.column; 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,
)),
}
}
};
}

View file

@ -4,7 +4,7 @@ use parse::ast::Spaceable;
use parse::blankspace::{space0, space0_before}; use parse::blankspace::{space0, space0_before};
use parse::collection::collection; use parse::collection::collection;
use parse::ident::unqualified_ident; 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; use region::Located;
/// Parse a record - generally one of these two: /// Parse a record - generally one of these two:
@ -39,6 +39,20 @@ where
loc!(parser) 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>> fn record_field<'a, P, S>(val_parser: P, min_indent: u16) -> impl Parser<'a, AssignedField<'a, S>>
where where
P: Parser<'a, Located<S>>, P: Parser<'a, Located<S>>,

View file

@ -5,7 +5,7 @@ use collections::arena_join;
use parse::ast::{Attempting, TypeAnnotation}; use parse::ast::{Attempting, TypeAnnotation};
use parse::blankspace::{space0_around, space1_before}; use parse::blankspace::{space0_around, space1_before};
use parse::parser::{ 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, unexpected_eof, zero_or_more, ParseResult, Parser, State,
}; };
use parse::record::record; 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::*; use parse::type_annotation::TypeAnnotation::*;
map_with_arena( map_with_arena(
and( and!(
record( record(
move |arena, state| located(min_indent).parse(arena, state), move |arena, state| located(min_indent).parse(arena, state),
min_indent, 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` // This could be a record fragment, e.g. `{ name: String }...r`
string("..."), string("..."),
move |arena, state| located(min_indent).parse(arena, state), move |arena, state| located(min_indent).parse(arena, state),
)), ))
), ),
|arena, (rec, opt_bound_var)| match opt_bound_var { |arena, (rec, opt_bound_var)| match opt_bound_var {
None => Record(rec), 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>> { fn applied_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>> {
map( map(
and( and!(
parse_concrete_type, parse_concrete_type,
// Optionally parse space-separated arguments for the constructor, // Optionally parse space-separated arguments for the constructor,
// e.g. `Str Float` in `Map Str Float` // e.g. `Str Float` in `Map Str Float`
zero_or_more(space1_before( zero_or_more(space1_before(
move |arena, state| located(min_indent).parse(arena, state), move |arena, state| located(min_indent).parse(arena, state),
min_indent, min_indent,
)), ))
), ),
|(ctor, args)| { |(ctor, args)| {
match &ctor { match &ctor {