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::branch::alt;
use winnow::bytes::take_till0; use winnow::bytes::take_till0;
use winnow::character::digit1; 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::error::{ErrorKind, ParseError as _};
use winnow::multi::{fold_many0, many0, separated0, separated1}; use winnow::multi::{fold_many0, many0, separated0, separated1};
use winnow::sequence::{preceded, terminated}; use winnow::sequence::{preceded, terminated};
@ -155,19 +155,16 @@ impl<'a> Expr<'a> {
let range_right = let range_right =
move |i| (ws(alt(("..=", ".."))), opt(move |i| Self::or(i, level))).parse_next(i); move |i| (ws(alt(("..=", ".."))), opt(move |i| Self::or(i, level))).parse_next(i);
alt(( alt((
map(range_right, |(op, right)| { range_right.map(|(op, right)| {
WithSpan::new(Self::Range(op, None, right.map(Box::new)), start) WithSpan::new(Self::Range(op, None, right.map(Box::new)), start)
}), }),
map( (move |i| Self::or(i, level), opt(range_right)).map(|(left, right)| match right {
(move |i| Self::or(i, level), opt(range_right)), Some((op, right)) => WithSpan::new(
|(left, right)| match right { Self::Range(op, Some(Box::new(left)), right.map(Box::new)),
Some((op, right)) => WithSpan::new( start,
Self::Range(op, Some(Box::new(left)), right.map(Box::new)), ),
start, None => left,
), }),
None => left,
},
),
)) ))
.parse_next(i) .parse_next(i)
} }
@ -339,19 +336,22 @@ impl<'a> Expr<'a> {
fn path_var_bool(i: &'a str) -> ParseResult<'a, WithSpan<'a, Self>> { fn path_var_bool(i: &'a str) -> ParseResult<'a, WithSpan<'a, Self>> {
let start = i; let start = i;
map(path_or_identifier, |v| match v { path_or_identifier
PathOrIdentifier::Path(v) => Self::Path(v), .map(|v| match v {
PathOrIdentifier::Identifier("true") => Self::BoolLit(true), PathOrIdentifier::Path(v) => Self::Path(v),
PathOrIdentifier::Identifier("false") => Self::BoolLit(false), PathOrIdentifier::Identifier("true") => Self::BoolLit(true),
PathOrIdentifier::Identifier(v) => Self::Var(v), PathOrIdentifier::Identifier("false") => Self::BoolLit(false),
}) PathOrIdentifier::Identifier(v) => Self::Var(v),
.parse_next(i) })
.map(|(i, expr)| (i, WithSpan::new(expr, start))) .parse_next(i)
.map(|(i, expr)| (i, WithSpan::new(expr, start)))
} }
fn str(i: &'a str) -> ParseResult<'a, WithSpan<'a, Self>> { fn str(i: &'a str) -> ParseResult<'a, WithSpan<'a, Self>> {
let start = i; 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>> { 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>> { fn char(i: &'a str) -> ParseResult<'a, WithSpan<'a, Self>> {
let start = i; 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] #[must_use]
@ -525,7 +527,7 @@ impl<'a> Suffix<'a> {
preceded( preceded(
(ws('!'), '('), (ws('!'), '('),
cut_err(terminated( 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> { fn attr(i: &'a str) -> ParseResult<'a, Self> {
map( preceded(ws(('.', not('.'))), cut_err(alt((digit1, identifier))))
preceded(ws(('.', not('.'))), cut_err(alt((digit1, identifier)))), .map(Self::Attr)
Self::Attr, .parse_next(i)
)
.parse_next(i)
} }
fn index(i: &'a str, level: Level) -> ParseResult<'a, Self> { fn index(i: &'a str, level: Level) -> ParseResult<'a, Self> {
let (_, level) = level.nest(i)?; let (_, level) = level.nest(i)?;
map( preceded(
preceded( ws('['),
ws('['), cut_err(terminated(ws(move |i| Expr::parse(i, level)), ']')),
cut_err(terminated(ws(move |i| Expr::parse(i, level)), ']')),
),
Self::Index,
) )
.map(Self::Index)
.parse_next(i) .parse_next(i)
} }
fn call(i: &'a str, level: Level) -> ParseResult<'a, Self> { fn call(i: &'a str, level: Level) -> ParseResult<'a, Self> {
let (_, level) = level.nest(i)?; 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> { 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::branch::alt;
use winnow::bytes::{any, one_of, tag, take_till0, take_till1, take_while_m_n, take_while1}; use winnow::bytes::{any, one_of, tag, take_till0, take_till1, take_while_m_n, take_while1};
use winnow::character::escaped; 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::error::{ErrorKind, FromExternalError};
use winnow::multi::{many0, many1}; use winnow::multi::{many0, many1};
use winnow::sequence::{delimited, preceded}; use winnow::sequence::{delimited, preceded};
@ -297,7 +297,7 @@ fn skip_till<'a, 'b, O>(
candidate_finder: impl crate::memchr_splitter::Splitter, candidate_finder: impl crate::memchr_splitter::Splitter,
end: impl Parser<&'a str, O, ErrorContext<'a>>, end: impl Parser<&'a str, O, ErrorContext<'a>>,
) -> impl Parser<&'a str, (&'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| { move |start: &'a str| {
let mut i = start; let mut i = start;
loop { loop {
@ -562,6 +562,7 @@ fn char_lit(i: &str) -> Result<(&str, CharLit<'_>), ParseErr<'_>> {
} }
/// Represents the different kinds of char declarations: /// Represents the different kinds of char declarations:
#[derive(Copy, Clone)]
enum Char<'a> { enum Char<'a> {
/// Any character that is not escaped. /// Any character that is not escaped.
Literal, Literal,
@ -578,35 +579,29 @@ impl<'a> Char<'a> {
if i.chars().count() == 1 { if i.chars().count() == 1 {
return Ok(("", Self::Literal)); return Ok(("", Self::Literal));
} }
map( (
( '\\',
'\\', alt((
alt(( one_of('n').value(Self::Escaped),
map('n', |_| Self::Escaped), one_of('r').value(Self::Escaped),
map('r', |_| Self::Escaped), one_of('t').value(Self::Escaped),
map('t', |_| Self::Escaped), one_of('\\').value(Self::Escaped),
map('\\', |_| Self::Escaped), one_of('0').value(Self::Escaped),
map('0', |_| Self::Escaped), one_of('\'').value(Self::Escaped),
map('\'', |_| Self::Escaped), // Not useful but supported by rust.
// Not useful but supported by rust. one_of('"').value(Self::Escaped),
map('"', |_| Self::Escaped), ('x', take_while_m_n(2, 2, |c: char| c.is_ascii_hexdigit()))
map( .map(|(_, s)| Self::AsciiEscape(s)),
('x', take_while_m_n(2, 2, |c: char| c.is_ascii_hexdigit())), (
|(_, s)| Self::AsciiEscape(s), "u{",
), take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()),
map( '}',
( )
"u{", .map(|(_, s, _)| Self::UnicodeEscape(s)),
take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()), )),
'}',
),
|(_, s, _)| Self::UnicodeEscape(s),
),
)),
),
|(_, ch)| ch,
) )
.parse_next(i) .map(|(_, ch)| ch)
.parse_next(i)
} }
} }

View File

@ -3,7 +3,7 @@ use std::str;
use winnow::Parser; use winnow::Parser;
use winnow::branch::alt; use winnow::branch::alt;
use winnow::bytes::{any, tag, take_till0}; 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::multi::{many0, separated0, separated1};
use winnow::sequence::{delimited, preceded}; use winnow::sequence::{delimited, preceded};
@ -64,8 +64,8 @@ impl<'a> Node<'a> {
fn many(i: &'a str, s: &State<'_>) -> ParseResult<'a, Vec<Self>> { fn many(i: &'a str, s: &State<'_>) -> ParseResult<'a, Vec<Self>> {
many0(alt(( many0(alt((
map(|i| Lit::parse(i, s), Self::Lit), (|i| Lit::parse(i, s)).map(Self::Lit),
map(|i| Comment::parse(i, s), Self::Comment), (|i| Comment::parse(i, s)).map(Self::Comment),
|i| Self::expr(i, s), |i| Self::expr(i, s),
|i| Self::parse(i, s), |i| Self::parse(i, s),
))) )))
@ -292,37 +292,35 @@ impl<'a> When<'a> {
#[allow(clippy::self_named_constructors)] #[allow(clippy::self_named_constructors)]
fn when(i: &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> { fn when(i: &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
let start = i; let start = i;
let endwhen = map( let endwhen = ws((
ws(( delimited(
delimited( |i| s.tag_block_start(i),
|i| s.tag_block_start(i), opt(Whitespace::parse),
ws(keyword("endwhen")),
),
cut_node(
Some("match-endwhen"),
(
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("endwhen")), |i| s.tag_block_end(i),
), many0(value((), ws(|i| Comment::parse(i, s)))).map(|()| ()),
cut_node(
Some("match-endwhen"),
(
opt(Whitespace::parse),
|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 = ( let mut p = (
|i| s.tag_block_start(i), |i| s.tag_block_start(i),
opt(Whitespace::parse), opt(Whitespace::parse),
@ -373,7 +371,7 @@ impl<'a> Cond<'a> {
preceded(ws(keyword("else")), opt(|i| CondTest::parse(i, s))), preceded(ws(keyword("else")), opt(|i| CondTest::parse(i, s))),
preceded( preceded(
ws(keyword("elif")), 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), opt(Whitespace::parse),

View File

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