refactor(parser): Switch 'map' from free to trait method

This commit is contained in:
Ed Page 2024-07-17 14:50:15 -05:00
parent dadf98e965
commit 15207709a3
4 changed files with 110 additions and 116 deletions

View File

@ -5,7 +5,7 @@ use winnow::Parser;
use winnow::branch::alt;
use winnow::bytes::take_till0;
use winnow::character::digit1;
use winnow::combinator::{cut_err, fail, map, not, opt, peek, value};
use winnow::combinator::{cut_err, fail, not, opt, peek, value};
use winnow::error::{ErrorKind, ParseError as _};
use winnow::multi::{fold_many0, many0, separated0, separated1};
use winnow::sequence::{preceded, terminated};
@ -155,19 +155,16 @@ impl<'a> Expr<'a> {
let range_right =
move |i| (ws(alt(("..=", ".."))), opt(move |i| Self::or(i, level))).parse_next(i);
alt((
map(range_right, |(op, right)| {
range_right.map(|(op, right)| {
WithSpan::new(Self::Range(op, None, right.map(Box::new)), start)
}),
map(
(move |i| Self::or(i, level), opt(range_right)),
|(left, right)| match right {
Some((op, right)) => WithSpan::new(
Self::Range(op, Some(Box::new(left)), right.map(Box::new)),
start,
),
None => left,
},
),
(move |i| Self::or(i, level), opt(range_right)).map(|(left, right)| match right {
Some((op, right)) => WithSpan::new(
Self::Range(op, Some(Box::new(left)), right.map(Box::new)),
start,
),
None => left,
}),
))
.parse_next(i)
}
@ -339,19 +336,22 @@ impl<'a> Expr<'a> {
fn path_var_bool(i: &'a str) -> ParseResult<'a, WithSpan<'a, Self>> {
let start = i;
map(path_or_identifier, |v| match v {
PathOrIdentifier::Path(v) => Self::Path(v),
PathOrIdentifier::Identifier("true") => Self::BoolLit(true),
PathOrIdentifier::Identifier("false") => Self::BoolLit(false),
PathOrIdentifier::Identifier(v) => Self::Var(v),
})
.parse_next(i)
.map(|(i, expr)| (i, WithSpan::new(expr, start)))
path_or_identifier
.map(|v| match v {
PathOrIdentifier::Path(v) => Self::Path(v),
PathOrIdentifier::Identifier("true") => Self::BoolLit(true),
PathOrIdentifier::Identifier("false") => Self::BoolLit(false),
PathOrIdentifier::Identifier(v) => Self::Var(v),
})
.parse_next(i)
.map(|(i, expr)| (i, WithSpan::new(expr, start)))
}
fn str(i: &'a str) -> ParseResult<'a, WithSpan<'a, Self>> {
let start = i;
map(str_lit, |i| WithSpan::new(Self::StrLit(i), start)).parse_next(i)
str_lit
.map(|i| WithSpan::new(Self::StrLit(i), start))
.parse_next(i)
}
fn num(i: &'a str) -> ParseResult<'a, WithSpan<'a, Self>> {
@ -362,7 +362,9 @@ impl<'a> Expr<'a> {
fn char(i: &'a str) -> ParseResult<'a, WithSpan<'a, Self>> {
let start = i;
map(char_lit, |i| WithSpan::new(Self::CharLit(i), start)).parse_next(i)
char_lit
.map(|i| WithSpan::new(Self::CharLit(i), start))
.parse_next(i)
}
#[must_use]
@ -525,7 +527,7 @@ impl<'a> Suffix<'a> {
preceded(
(ws('!'), '('),
cut_err(terminated(
map(nested_parenthesis.recognize(), Self::MacroCall),
nested_parenthesis.recognize().map(Self::MacroCall),
')',
)),
)
@ -533,31 +535,31 @@ impl<'a> Suffix<'a> {
}
fn attr(i: &'a str) -> ParseResult<'a, Self> {
map(
preceded(ws(('.', not('.'))), cut_err(alt((digit1, identifier)))),
Self::Attr,
)
.parse_next(i)
preceded(ws(('.', not('.'))), cut_err(alt((digit1, identifier))))
.map(Self::Attr)
.parse_next(i)
}
fn index(i: &'a str, level: Level) -> ParseResult<'a, Self> {
let (_, level) = level.nest(i)?;
map(
preceded(
ws('['),
cut_err(terminated(ws(move |i| Expr::parse(i, level)), ']')),
),
Self::Index,
preceded(
ws('['),
cut_err(terminated(ws(move |i| Expr::parse(i, level)), ']')),
)
.map(Self::Index)
.parse_next(i)
}
fn call(i: &'a str, level: Level) -> ParseResult<'a, Self> {
let (_, level) = level.nest(i)?;
map(move |i| Expr::arguments(i, level, false), Self::Call).parse_next(i)
(move |i| Expr::arguments(i, level, false))
.map(Self::Call)
.parse_next(i)
}
fn r#try(i: &'a str) -> ParseResult<'a, Self> {
map(preceded(take_till0(not_ws), '?'), |_| Self::Try).parse_next(i)
preceded(take_till0(not_ws), '?')
.map(|_| Self::Try)
.parse_next(i)
}
}

View File

@ -14,7 +14,7 @@ use winnow::Parser;
use winnow::branch::alt;
use winnow::bytes::{any, one_of, tag, take_till0, take_till1, take_while_m_n, take_while1};
use winnow::character::escaped;
use winnow::combinator::{cut_err, fail, map, not, opt, value};
use winnow::combinator::{cut_err, fail, not, opt, value};
use winnow::error::{ErrorKind, FromExternalError};
use winnow::multi::{many0, many1};
use winnow::sequence::{delimited, preceded};
@ -297,7 +297,7 @@ fn skip_till<'a, 'b, O>(
candidate_finder: impl crate::memchr_splitter::Splitter,
end: impl Parser<&'a str, O, ErrorContext<'a>>,
) -> impl Parser<&'a str, (&'a str, O), ErrorContext<'a>> {
let mut next = alt((map(end, Some), map(any, |_| None)));
let mut next = alt((end.map(Some), any.map(|_| None)));
move |start: &'a str| {
let mut i = start;
loop {
@ -562,6 +562,7 @@ fn char_lit(i: &str) -> Result<(&str, CharLit<'_>), ParseErr<'_>> {
}
/// Represents the different kinds of char declarations:
#[derive(Copy, Clone)]
enum Char<'a> {
/// Any character that is not escaped.
Literal,
@ -578,35 +579,29 @@ impl<'a> Char<'a> {
if i.chars().count() == 1 {
return Ok(("", Self::Literal));
}
map(
(
'\\',
alt((
map('n', |_| Self::Escaped),
map('r', |_| Self::Escaped),
map('t', |_| Self::Escaped),
map('\\', |_| Self::Escaped),
map('0', |_| Self::Escaped),
map('\'', |_| Self::Escaped),
// Not useful but supported by rust.
map('"', |_| Self::Escaped),
map(
('x', take_while_m_n(2, 2, |c: char| c.is_ascii_hexdigit())),
|(_, s)| Self::AsciiEscape(s),
),
map(
(
"u{",
take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()),
'}',
),
|(_, s, _)| Self::UnicodeEscape(s),
),
)),
),
|(_, ch)| ch,
(
'\\',
alt((
one_of('n').value(Self::Escaped),
one_of('r').value(Self::Escaped),
one_of('t').value(Self::Escaped),
one_of('\\').value(Self::Escaped),
one_of('0').value(Self::Escaped),
one_of('\'').value(Self::Escaped),
// Not useful but supported by rust.
one_of('"').value(Self::Escaped),
('x', take_while_m_n(2, 2, |c: char| c.is_ascii_hexdigit()))
.map(|(_, s)| Self::AsciiEscape(s)),
(
"u{",
take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()),
'}',
)
.map(|(_, s, _)| Self::UnicodeEscape(s)),
)),
)
.parse_next(i)
.map(|(_, ch)| ch)
.parse_next(i)
}
}

View File

@ -3,7 +3,7 @@ use std::str;
use winnow::Parser;
use winnow::branch::alt;
use winnow::bytes::{any, tag, take_till0};
use winnow::combinator::{cut_err, eof, fail, map, map_opt, not, opt, peek, value};
use winnow::combinator::{cut_err, eof, fail, map_opt, not, opt, peek, value};
use winnow::multi::{many0, separated0, separated1};
use winnow::sequence::{delimited, preceded};
@ -64,8 +64,8 @@ impl<'a> Node<'a> {
fn many(i: &'a str, s: &State<'_>) -> ParseResult<'a, Vec<Self>> {
many0(alt((
map(|i| Lit::parse(i, s), Self::Lit),
map(|i| Comment::parse(i, s), Self::Comment),
(|i| Lit::parse(i, s)).map(Self::Lit),
(|i| Comment::parse(i, s)).map(Self::Comment),
|i| Self::expr(i, s),
|i| Self::parse(i, s),
)))
@ -292,37 +292,35 @@ impl<'a> When<'a> {
#[allow(clippy::self_named_constructors)]
fn when(i: &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
let start = i;
let endwhen = map(
ws((
delimited(
|i| s.tag_block_start(i),
let endwhen = ws((
delimited(
|i| s.tag_block_start(i),
opt(Whitespace::parse),
ws(keyword("endwhen")),
),
cut_node(
Some("match-endwhen"),
(
opt(Whitespace::parse),
ws(keyword("endwhen")),
),
cut_node(
Some("match-endwhen"),
(
opt(Whitespace::parse),
|i| s.tag_block_end(i),
many0(value((), ws(|i| Comment::parse(i, s)))).map(|()| ()),
),
|i| s.tag_block_end(i),
many0(value((), ws(|i| Comment::parse(i, s)))).map(|()| ()),
),
),
))
.with_recognized()
.map(|((pws, _), span)| {
// A comment node is used to pass the whitespace suppressing information to the
// generator. This way we don't have to fix up the next `when` node or the closing
// `endmatch`. Any whitespaces after `endwhen` are to be suppressed. Actually, they
// don't wind up in the AST anyway.
Node::Comment(WithSpan::new(
Comment {
ws: Ws(pws, Some(Whitespace::Suppress)),
content: "",
},
span,
))
.with_recognized(),
|((pws, _), span)| {
// A comment node is used to pass the whitespace suppressing information to the
// generator. This way we don't have to fix up the next `when` node or the closing
// `endmatch`. Any whitespaces after `endwhen` are to be suppressed. Actually, they
// don't wind up in the AST anyway.
Node::Comment(WithSpan::new(
Comment {
ws: Ws(pws, Some(Whitespace::Suppress)),
content: "",
},
span,
))
},
);
});
let mut p = (
|i| s.tag_block_start(i),
opt(Whitespace::parse),
@ -373,7 +371,7 @@ impl<'a> Cond<'a> {
preceded(ws(keyword("else")), opt(|i| CondTest::parse(i, s))),
preceded(
ws(keyword("elif")),
cut_node(Some("if-elif"), map(|i| CondTest::parse_cond(i, s), Some)),
cut_node(Some("if-elif"), (|i| CondTest::parse_cond(i, s)).map(Some)),
),
)),
opt(Whitespace::parse),

View File

@ -1,7 +1,7 @@
use winnow::Parser;
use winnow::branch::alt;
use winnow::bytes::one_of;
use winnow::combinator::{map, map_res, opt};
use winnow::combinator::{map_res, opt};
use winnow::multi::separated1;
use winnow::sequence::preceded;
@ -30,21 +30,20 @@ pub enum Target<'a> {
impl<'a> Target<'a> {
/// Parses multiple targets with `or` separating them
pub(super) fn parse(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
map(
separated1(|i| s.nest(i, |i| Self::parse_one(i, s)), ws("or")).map(|v: Vec<_>| v),
|mut opts| match opts.len() {
separated1(|i| s.nest(i, |i| Self::parse_one(i, s)), ws("or"))
.map(|v: Vec<_>| v)
.map(|mut opts| match opts.len() {
1 => opts.pop().unwrap(),
_ => Self::OrChain(opts),
},
)
.parse_next(i)
})
.parse_next(i)
}
/// Parses a single target without an `or`, unless it is wrapped in parentheses.
fn parse_one(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
let mut opt_opening_paren = map(opt(ws('(')), |o| o.is_some());
let mut opt_opening_brace = map(opt(ws('{')), |o| o.is_some());
let mut opt_opening_bracket = map(opt(ws('[')), |o| o.is_some());
let mut opt_opening_paren = opt(ws('(')).map(|o| o.is_some());
let mut opt_opening_brace = opt(ws('{')).map(|o| o.is_some());
let mut opt_opening_bracket = opt(ws('[')).map(|o| o.is_some());
let (i, lit) = opt(Self::lit).parse_next(i)?;
if let Some(lit) = lit {
@ -118,12 +117,12 @@ impl<'a> Target<'a> {
fn lit(i: &'a str) -> ParseResult<'a, Self> {
alt((
map(str_lit, Self::StrLit),
map(char_lit, Self::CharLit),
map(num_lit.with_recognized(), |(num, full)| {
Target::NumLit(full, num)
}),
map(bool_lit, Self::BoolLit),
str_lit.map(Self::StrLit),
char_lit.map(Self::CharLit),
num_lit
.with_recognized()
.map(|(num, full)| Target::NumLit(full, num)),
bool_lit.map(Self::BoolLit),
))
.parse_next(i)
}
@ -201,8 +200,8 @@ fn collect_targets<'a, T>(
delim: char,
mut one: impl FnMut(&'a str, &State<'_>) -> ParseResult<'a, T>,
) -> ParseResult<'a, (bool, Vec<T>)> {
let opt_comma = |i| map(ws(opt(',')), |o| o.is_some()).parse_next(i);
let mut opt_end = |i| map(ws(opt(one_of(delim))), |o| o.is_some()).parse_next(i);
let opt_comma = |i| ws(opt(',')).map(|o| o.is_some()).parse_next(i);
let mut opt_end = |i| ws(opt(one_of(delim))).map(|o| o.is_some()).parse_next(i);
let (i, has_end) = opt_end.parse_next(i)?;
if has_end {