checkpoint

This commit is contained in:
Folkert 2021-02-25 21:06:30 +01:00
parent 0e8d3123ea
commit 93ee552003
2 changed files with 156 additions and 107 deletions

View file

@ -406,6 +406,7 @@ pub enum ERecord<'a> {
Field(Row, Col),
Colon(Row, Col),
QuestionMark(Row, Col),
Bar(Row, Col),
Ampersand(Row, Col),
@ -1992,112 +1993,6 @@ macro_rules! between {
};
}
#[macro_export]
macro_rules! record_field {
($val_parser:expr, $min_indent:expr) => {
move |arena: &'a bumpalo::Bump,
state: $crate::parser::State<'a>|
-> $crate::parser::ParseResult<'a, $crate::ast::AssignedField<'a, _>, _> {
use $crate::ast::AssignedField::*;
use $crate::blankspace::{space0, space0_before};
use $crate::ident::lowercase_ident;
use $crate::parser::ascii_char;
use $crate::parser::Either::*;
// You must have a field name, e.g. "email"
let (progress, loc_label, state) = loc!(lowercase_ident()).parse(arena, state)?;
debug_assert_eq!(progress, MadeProgress);
let (_, spaces, state) = space0($min_indent).parse(arena, state)?;
// Having a value is optional; both `{ email }` and `{ email: blah }` work.
// (This is true in both literals and types.)
let (_, opt_loc_val, state) = $crate::parser::optional(either!(
skip_first!(ascii_char(b':'), space0_before($val_parser, $min_indent)),
skip_first!(ascii_char(b'?'), space0_before($val_parser, $min_indent))
))
.parse(arena, state)?;
let answer = match opt_loc_val {
Some(either) => match either {
First(loc_val) => RequiredValue(loc_label, spaces, arena.alloc(loc_val)),
Second(loc_val) => OptionalValue(loc_label, spaces, arena.alloc(loc_val)),
},
// If no value was provided, record it as a Var.
// Canonicalize will know what to do with a Var later.
None => {
if !spaces.is_empty() {
SpaceAfter(arena.alloc(LabelOnly(loc_label)), spaces)
} else {
LabelOnly(loc_label)
}
}
};
Ok((MadeProgress, answer, state))
}
};
}
#[macro_export]
macro_rules! record_without_update {
($val_parser:expr, $min_indent:expr) => {
collection_trailing_sep!(
ascii_char(b'{'),
loc!(record_field!($val_parser, $min_indent)),
ascii_char(b','),
ascii_char(b'}'),
$min_indent
)
};
}
#[macro_export]
macro_rules! record {
($val_parser:expr, $min_indent:expr) => {
skip_first!(
$crate::parser::ascii_char(b'{'),
and!(
// You can optionally have an identifier followed by an '&' to
// make this a record update, e.g. { Foo.user & username: "blah" }.
$crate::parser::optional(skip_second!(
$crate::blankspace::space0_around(
// We wrap the ident in an Expr here,
// so that we have a Spaceable value to work with,
// and then in canonicalization verify that it's an Expr::Var
// (and not e.g. an `Expr::Access`) and extract its string.
loc!(map_with_arena!(
$crate::expr::ident(),
$crate::expr::ident_to_expr
)),
$min_indent
),
$crate::parser::ascii_char(b'&')
)),
loc!(skip_first!(
// We specifically allow space characters inside here, so that
// `{ }` can be successfully parsed as an empty record, and then
// changed by the formatter back into `{}`.
zero_or_more!($crate::parser::ascii_char(b' ')),
skip_second!(
and!(
$crate::parser::trailing_sep_by0(
$crate::parser::ascii_char(b','),
$crate::blankspace::space0_around(
loc!(record_field!($val_parser, $min_indent)),
$min_indent
),
),
$crate::blankspace::space0($min_indent)
),
$crate::parser::ascii_char(b'}')
)
))
)
)
};
}
/// For some reason, some usages won't compile unless they use this instead of the macro version
#[inline(always)]
pub fn and<'a, P1, P2, A, B, E>(p1: P1, p2: P2) -> impl Parser<'a, (A, B), E>