mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-30 14:31:36 +00:00
refactor(parser): Switch 'map' from free to trait method
This commit is contained in:
parent
dadf98e965
commit
15207709a3
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user