mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 15:25:19 +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::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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user