mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21: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 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
|
||||||
|
|
106
src/parse/mod.rs
106
src/parse/mod.rs
|
@ -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 => {
|
||||||
|
|
|
@ -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,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -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>>,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue