mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-01 06:51:15 +00:00
Use "target()" to parse "when" block
`target()` as used in parsing "let" and "if let" implements parsing nested tuples and structs. But it does not implement parsing literals. The functions `match_variant()` and `with_parameters()` as used in parsing "when" blocks do not implement parsing nested structs, but it implements parsing literals. This PR combines `match_variant()` and `with_parameters()` into `target()`, so that all `{%when%}` support nested structs, too.
This commit is contained in:
parent
1622df7aee
commit
268d8250fb
@ -2,10 +2,7 @@ use super::{get_template_source, CompileError, Integrations};
|
||||
use crate::filters;
|
||||
use crate::heritage::{Context, Heritage};
|
||||
use crate::input::{Source, TemplateInput};
|
||||
use crate::parser::{
|
||||
parse, Cond, CondTest, Expr, MatchParameter, MatchParameters, MatchVariant, Node, Target, When,
|
||||
Ws,
|
||||
};
|
||||
use crate::parser::{parse, Cond, CondTest, Expr, Node, Target, When, Ws};
|
||||
|
||||
use proc_macro2::Span;
|
||||
|
||||
@ -498,14 +495,11 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
buf.write("} else if ");
|
||||
}
|
||||
|
||||
if let Some((variant, params)) = target {
|
||||
if let Some(target) = target {
|
||||
let mut expr_buf = Buffer::new(0);
|
||||
self.visit_expr(&mut expr_buf, expr)?;
|
||||
buf.write("let ");
|
||||
self.visit_match_variant(buf, variant);
|
||||
if let Some(params) = params {
|
||||
self.visit_match_params(buf, params);
|
||||
}
|
||||
self.visit_target(buf, true, true, target);
|
||||
buf.write(" = &(");
|
||||
buf.write(&expr_buf.buf);
|
||||
buf.write(")");
|
||||
@ -562,7 +556,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
|
||||
let mut arm_size = 0;
|
||||
for (i, arm) in arms.iter().enumerate() {
|
||||
let &(ws, ref variant, ref params, ref body) = arm;
|
||||
let &(ws, ref target, ref body) = arm;
|
||||
self.handle_ws(ws);
|
||||
|
||||
if i > 0 {
|
||||
@ -573,14 +567,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
}
|
||||
|
||||
self.locals.push();
|
||||
match *variant {
|
||||
Some(ref param) => {
|
||||
self.visit_match_variant(buf, param);
|
||||
}
|
||||
None => buf.write("_"),
|
||||
};
|
||||
|
||||
self.visit_match_params(buf, params);
|
||||
self.visit_target(buf, true, true, target);
|
||||
buf.writeln(" => {")?;
|
||||
|
||||
arm_size = self.handle(ctx, body, buf, AstLevel::Nested)?;
|
||||
@ -614,7 +601,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
|
||||
let flushed = self.write_buf_writable(buf)?;
|
||||
buf.write("for (");
|
||||
self.visit_target(buf, true, var);
|
||||
self.visit_target(buf, true, true, var);
|
||||
match iter {
|
||||
Expr::Range(_, _, _) => buf.writeln(&format!(
|
||||
", _loop_item) in ::askama::helpers::TemplateLoop::new({}) {{",
|
||||
@ -807,7 +794,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
self.handle_ws(ws);
|
||||
self.write_buf_writable(buf)?;
|
||||
buf.write("let ");
|
||||
self.visit_target(buf, false, var);
|
||||
self.visit_target(buf, false, true, var);
|
||||
buf.writeln(";")
|
||||
}
|
||||
|
||||
@ -830,6 +817,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
Target::Struct(_, named_targets) => named_targets
|
||||
.iter()
|
||||
.any(|(_, target)| self.is_shadowing_variable(target)),
|
||||
_ => panic!("Cannot have literals on the left-hand-side of an assignment."),
|
||||
}
|
||||
}
|
||||
|
||||
@ -857,7 +845,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
buf.write("let ");
|
||||
}
|
||||
|
||||
self.visit_target(buf, true, var);
|
||||
self.visit_target(buf, true, true, var);
|
||||
buf.writeln(&format!(" = {};", &expr_buf.buf))
|
||||
}
|
||||
|
||||
@ -1082,84 +1070,6 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
DisplayWrap::Unwrapped
|
||||
}
|
||||
|
||||
fn visit_match_variant(&mut self, buf: &mut Buffer, param: &MatchVariant<'_>) -> DisplayWrap {
|
||||
let mut expr_buf = Buffer::new(0);
|
||||
let wrapped = match *param {
|
||||
MatchVariant::StrLit(s) => {
|
||||
expr_buf.write("&");
|
||||
self.visit_str_lit(&mut expr_buf, s)
|
||||
}
|
||||
MatchVariant::CharLit(s) => self.visit_char_lit(&mut expr_buf, s),
|
||||
MatchVariant::NumLit(s) => self.visit_num_lit(&mut expr_buf, s),
|
||||
MatchVariant::Name(s) => {
|
||||
expr_buf.write(s);
|
||||
DisplayWrap::Unwrapped
|
||||
}
|
||||
MatchVariant::Path(ref s) => {
|
||||
expr_buf.write(&s.join("::"));
|
||||
DisplayWrap::Unwrapped
|
||||
}
|
||||
};
|
||||
buf.write(&expr_buf.buf);
|
||||
wrapped
|
||||
}
|
||||
|
||||
fn visit_match_param(&mut self, buf: &mut Buffer, param: &MatchParameter<'_>) -> DisplayWrap {
|
||||
let mut expr_buf = Buffer::new(0);
|
||||
let wrapped = match *param {
|
||||
MatchParameter::NumLit(s) => self.visit_num_lit(&mut expr_buf, s),
|
||||
MatchParameter::StrLit(s) => self.visit_str_lit(&mut expr_buf, s),
|
||||
MatchParameter::CharLit(s) => self.visit_char_lit(&mut expr_buf, s),
|
||||
MatchParameter::Name(s) => {
|
||||
expr_buf.write(s);
|
||||
DisplayWrap::Unwrapped
|
||||
}
|
||||
};
|
||||
buf.write(&expr_buf.buf);
|
||||
wrapped
|
||||
}
|
||||
|
||||
fn visit_match_params(&mut self, buf: &mut Buffer, params: &MatchParameters<'a>) {
|
||||
match params {
|
||||
MatchParameters::Simple(params) => {
|
||||
if !params.is_empty() {
|
||||
buf.write("(");
|
||||
for (i, param) in params.iter().enumerate() {
|
||||
if let MatchParameter::Name(p) = *param {
|
||||
self.locals.insert_with_default(p);
|
||||
}
|
||||
if i > 0 {
|
||||
buf.write(", ");
|
||||
}
|
||||
self.visit_match_param(buf, param);
|
||||
}
|
||||
buf.write(")");
|
||||
}
|
||||
}
|
||||
MatchParameters::Named(params) => {
|
||||
buf.write("{");
|
||||
for (i, param) in params.iter().enumerate() {
|
||||
if let Some(MatchParameter::Name(p)) = param.1 {
|
||||
let p = normalize_identifier(p);
|
||||
self.locals.insert_with_default(p);
|
||||
} else {
|
||||
self.locals.insert_with_default(param.0);
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
buf.write(", ");
|
||||
}
|
||||
buf.write(param.0);
|
||||
if let Some(param) = ¶m.1 {
|
||||
buf.write(":");
|
||||
self.visit_match_param(buf, param);
|
||||
}
|
||||
}
|
||||
buf.write("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_filter(
|
||||
&mut self,
|
||||
buf: &mut Buffer,
|
||||
@ -1514,8 +1424,17 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
DisplayWrap::Unwrapped
|
||||
}
|
||||
|
||||
fn visit_target(&mut self, buf: &mut Buffer, initialized: bool, target: &Target<'a>) {
|
||||
fn visit_target(
|
||||
&mut self,
|
||||
buf: &mut Buffer,
|
||||
initialized: bool,
|
||||
first_level: bool,
|
||||
target: &Target<'a>,
|
||||
) {
|
||||
match target {
|
||||
Target::Name("_") => {
|
||||
buf.write("_");
|
||||
}
|
||||
Target::Name(name) => {
|
||||
let name = normalize_identifier(name);
|
||||
match initialized {
|
||||
@ -1528,7 +1447,7 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
buf.write(&path.join("::"));
|
||||
buf.write("(");
|
||||
for target in targets {
|
||||
self.visit_target(buf, initialized, target);
|
||||
self.visit_target(buf, initialized, false, target);
|
||||
buf.write(",");
|
||||
}
|
||||
buf.write(")");
|
||||
@ -1539,11 +1458,32 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
|
||||
for (name, target) in targets {
|
||||
buf.write(normalize_identifier(name));
|
||||
buf.write(": ");
|
||||
self.visit_target(buf, initialized, target);
|
||||
self.visit_target(buf, initialized, false, target);
|
||||
buf.write(",");
|
||||
}
|
||||
buf.write(" }");
|
||||
}
|
||||
Target::Path(path) => {
|
||||
self.visit_path(buf, path);
|
||||
}
|
||||
Target::StrLit(s) => {
|
||||
if first_level {
|
||||
buf.write("&");
|
||||
}
|
||||
self.visit_str_lit(buf, s);
|
||||
}
|
||||
Target::NumLit(s) => {
|
||||
if first_level {
|
||||
buf.write("&");
|
||||
}
|
||||
self.visit_num_lit(buf, s);
|
||||
}
|
||||
Target::CharLit(s) => {
|
||||
if first_level {
|
||||
buf.write("&");
|
||||
}
|
||||
self.visit_char_lit(buf, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ impl<'a> Context<'a> {
|
||||
nested.push(nodes);
|
||||
}
|
||||
Node::Match(_, _, arms, _) => {
|
||||
for (_, _, _, arm) in arms {
|
||||
for (_, _, arm) in arms {
|
||||
nested.push(arm);
|
||||
}
|
||||
}
|
||||
|
@ -91,41 +91,7 @@ impl Expr<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub type When<'a> = (
|
||||
Ws,
|
||||
Option<MatchVariant<'a>>,
|
||||
MatchParameters<'a>,
|
||||
Vec<Node<'a>>,
|
||||
);
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MatchParameters<'a> {
|
||||
Simple(Vec<MatchParameter<'a>>),
|
||||
Named(Vec<(&'a str, Option<MatchParameter<'a>>)>),
|
||||
}
|
||||
|
||||
impl<'a> Default for MatchParameters<'a> {
|
||||
fn default() -> Self {
|
||||
MatchParameters::Simple(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MatchParameter<'a> {
|
||||
Name(&'a str),
|
||||
NumLit(&'a str),
|
||||
StrLit(&'a str),
|
||||
CharLit(&'a str),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum MatchVariant<'a> {
|
||||
Path(Vec<&'a str>),
|
||||
Name(&'a str),
|
||||
NumLit(&'a str),
|
||||
StrLit(&'a str),
|
||||
CharLit(&'a str),
|
||||
}
|
||||
pub type When<'a> = (Ws, Target<'a>, Vec<Node<'a>>);
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Macro<'a> {
|
||||
@ -140,6 +106,10 @@ pub enum Target<'a> {
|
||||
Name(&'a str),
|
||||
Tuple(Vec<&'a str>, Vec<Target<'a>>),
|
||||
Struct(Vec<&'a str>, Vec<(&'a str, Target<'a>)>),
|
||||
NumLit(&'a str),
|
||||
StrLit(&'a str),
|
||||
CharLit(&'a str),
|
||||
Path(Vec<&'a str>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
@ -149,7 +119,7 @@ pub type Cond<'a> = (Ws, Option<CondTest<'a>>, Vec<Node<'a>>);
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct CondTest<'a> {
|
||||
pub target: Option<(MatchVariant<'a>, Option<MatchParameters<'a>>)>,
|
||||
pub target: Option<Target<'a>>,
|
||||
pub expr: Expr<'a>,
|
||||
}
|
||||
|
||||
@ -297,12 +267,8 @@ fn expr_array_lit(i: &[u8]) -> IResult<&[u8], Expr<'_>> {
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn variant_num_lit(i: &[u8]) -> IResult<&[u8], MatchVariant<'_>> {
|
||||
map(num_lit, |s| MatchVariant::NumLit(s))(i)
|
||||
}
|
||||
|
||||
fn param_num_lit(i: &[u8]) -> IResult<&[u8], MatchParameter<'_>> {
|
||||
map(num_lit, |s| MatchParameter::NumLit(s))(i)
|
||||
fn variant_num_lit(i: &[u8]) -> IResult<&[u8], Target<'_>> {
|
||||
map(num_lit, |s| Target::NumLit(s))(i)
|
||||
}
|
||||
|
||||
fn str_lit(i: &[u8]) -> IResult<&[u8], &str> {
|
||||
@ -320,12 +286,8 @@ fn expr_str_lit(i: &[u8]) -> IResult<&[u8], Expr<'_>> {
|
||||
map(str_lit, |s| Expr::StrLit(s))(i)
|
||||
}
|
||||
|
||||
fn variant_str_lit(i: &[u8]) -> IResult<&[u8], MatchVariant<'_>> {
|
||||
map(str_lit, |s| MatchVariant::StrLit(s))(i)
|
||||
}
|
||||
|
||||
fn param_str_lit(i: &[u8]) -> IResult<&[u8], MatchParameter<'_>> {
|
||||
map(str_lit, |s| MatchParameter::StrLit(s))(i)
|
||||
fn variant_str_lit(i: &[u8]) -> IResult<&[u8], Target<'_>> {
|
||||
map(str_lit, |s| Target::StrLit(s))(i)
|
||||
}
|
||||
|
||||
fn char_lit(i: &[u8]) -> IResult<&[u8], &str> {
|
||||
@ -343,12 +305,8 @@ fn expr_char_lit(i: &[u8]) -> IResult<&[u8], Expr<'_>> {
|
||||
map(char_lit, |s| Expr::CharLit(s))(i)
|
||||
}
|
||||
|
||||
fn variant_char_lit(i: &[u8]) -> IResult<&[u8], MatchVariant<'_>> {
|
||||
map(char_lit, |s| MatchVariant::CharLit(s))(i)
|
||||
}
|
||||
|
||||
fn param_char_lit(i: &[u8]) -> IResult<&[u8], MatchParameter<'_>> {
|
||||
map(char_lit, |s| MatchParameter::CharLit(s))(i)
|
||||
fn variant_char_lit(i: &[u8]) -> IResult<&[u8], Target<'_>> {
|
||||
map(char_lit, |s| Target::CharLit(s))(i)
|
||||
}
|
||||
|
||||
fn expr_var(i: &[u8]) -> IResult<&[u8], Expr<'_>> {
|
||||
@ -399,12 +357,6 @@ fn expr_path_call(i: &[u8]) -> IResult<&[u8], Expr<'_>> {
|
||||
Ok((i, Expr::PathCall(path, args)))
|
||||
}
|
||||
|
||||
fn variant_path(i: &[u8]) -> IResult<&[u8], MatchVariant<'_>> {
|
||||
map(separated_list1(ws(tag("::")), identifier), |path| {
|
||||
MatchVariant::Path(path)
|
||||
})(i)
|
||||
}
|
||||
|
||||
fn named_target(i: &[u8]) -> IResult<&[u8], (&str, Target<'_>)> {
|
||||
let (i, (src, target)) = pair(identifier, opt(preceded(ws(tag(":")), target)))(i)?;
|
||||
Ok((i, (src, target.unwrap_or(Target::Name(src)))))
|
||||
@ -413,6 +365,12 @@ fn named_target(i: &[u8]) -> IResult<&[u8], (&str, Target<'_>)> {
|
||||
fn target(i: &[u8]) -> IResult<&[u8], Target<'_>> {
|
||||
let mut opt_opening_paren = map(opt(ws(tag("("))), |o| o.is_some());
|
||||
let mut opt_closing_paren = map(opt(ws(tag(")"))), |o| o.is_some());
|
||||
let mut opt_opening_brace = map(opt(ws(tag("{"))), |o| o.is_some());
|
||||
|
||||
let (i, lit) = opt(alt((variant_str_lit, variant_char_lit, variant_num_lit)))(i)?;
|
||||
if let Some(lit) = lit {
|
||||
return Ok((i, lit));
|
||||
}
|
||||
|
||||
// match tuples and unused parentheses
|
||||
let (i, target_is_tuple) = opt_opening_paren(i)?;
|
||||
@ -442,7 +400,9 @@ fn target(i: &[u8]) -> IResult<&[u8], Target<'_>> {
|
||||
// match structs
|
||||
let (i, path) = opt(path)(i)?;
|
||||
if let Some(path) = path {
|
||||
let i_before_matching_with = i;
|
||||
let (i, _) = opt(ws(tag("with")))(i)?;
|
||||
|
||||
let (i, is_unnamed_struct) = opt_opening_paren(i)?;
|
||||
if is_unnamed_struct {
|
||||
let (i, targets) = alt((
|
||||
@ -453,33 +413,27 @@ fn target(i: &[u8]) -> IResult<&[u8], Target<'_>> {
|
||||
),
|
||||
))(i)?;
|
||||
return Ok((i, Target::Tuple(path, targets)));
|
||||
} else {
|
||||
let (i, targets) = preceded(
|
||||
ws(tag("{")),
|
||||
alt((
|
||||
map(tag("}"), |_| Vec::new()),
|
||||
terminated(
|
||||
separated_list1(ws(tag(",")), named_target),
|
||||
pair(opt(ws(tag(","))), ws(tag("}"))),
|
||||
),
|
||||
)),
|
||||
)(i)?;
|
||||
}
|
||||
|
||||
let (i, is_named_struct) = opt_opening_brace(i)?;
|
||||
if is_named_struct {
|
||||
let (i, targets) = alt((
|
||||
map(tag("}"), |_| Vec::new()),
|
||||
terminated(
|
||||
separated_list1(ws(tag(",")), named_target),
|
||||
pair(opt(ws(tag(","))), ws(tag("}"))),
|
||||
),
|
||||
))(i)?;
|
||||
return Ok((i, Target::Struct(path, targets)));
|
||||
}
|
||||
|
||||
return Ok((i_before_matching_with, Target::Path(path)));
|
||||
}
|
||||
|
||||
// neither nor struct
|
||||
// neither literal nor struct nor path
|
||||
map(identifier, Target::Name)(i)
|
||||
}
|
||||
|
||||
fn variant_name(i: &[u8]) -> IResult<&[u8], MatchVariant<'_>> {
|
||||
map(identifier, |s| MatchVariant::Name(s))(i)
|
||||
}
|
||||
|
||||
fn param_name(i: &[u8]) -> IResult<&[u8], MatchParameter<'_>> {
|
||||
map(identifier, |s| MatchParameter::Name(s))(i)
|
||||
}
|
||||
|
||||
fn arguments(i: &[u8]) -> IResult<&[u8], Vec<Expr<'_>>> {
|
||||
delimited(
|
||||
ws(tag("(")),
|
||||
@ -548,35 +502,6 @@ fn parameters(i: &[u8]) -> IResult<&[u8], Vec<&str>> {
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn with_parameters(i: &[u8]) -> IResult<&[u8], MatchParameters<'_>> {
|
||||
let (i, (_, value)) = tuple((
|
||||
opt(tag("with")),
|
||||
alt((match_simple_parameters, match_named_parameters)),
|
||||
))(i)?;
|
||||
Ok((i, value))
|
||||
}
|
||||
|
||||
fn match_simple_parameters(i: &[u8]) -> IResult<&[u8], MatchParameters<'_>> {
|
||||
delimited(
|
||||
ws(tag("(")),
|
||||
map(separated_list0(tag(","), ws(match_parameter)), |mps| {
|
||||
MatchParameters::Simple(mps)
|
||||
}),
|
||||
tag(")"),
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn match_named_parameters(i: &[u8]) -> IResult<&[u8], MatchParameters<'_>> {
|
||||
delimited(
|
||||
ws(tag("{")),
|
||||
map(
|
||||
separated_list0(tag(","), ws(match_named_parameter)),
|
||||
MatchParameters::Named,
|
||||
),
|
||||
tag("}"),
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn expr_group(i: &[u8]) -> IResult<&[u8], Expr<'_>> {
|
||||
map(delimited(ws(char('(')), expr_any, ws(char(')'))), |s| {
|
||||
Expr::Group(Box::new(s))
|
||||
@ -599,26 +524,6 @@ fn expr_single(i: &[u8]) -> IResult<&[u8], Expr<'_>> {
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn match_variant(i: &[u8]) -> IResult<&[u8], MatchVariant<'_>> {
|
||||
alt((
|
||||
variant_path,
|
||||
variant_name,
|
||||
variant_num_lit,
|
||||
variant_str_lit,
|
||||
variant_char_lit,
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn match_parameter(i: &[u8]) -> IResult<&[u8], MatchParameter<'_>> {
|
||||
alt((param_name, param_num_lit, param_str_lit, param_char_lit))(i)
|
||||
}
|
||||
|
||||
fn match_named_parameter(i: &[u8]) -> IResult<&[u8], (&str, Option<MatchParameter<'_>>)> {
|
||||
let param = tuple((ws(tag(":")), match_parameter));
|
||||
let (i, (name, param)) = tuple((identifier, opt(param)))(i)?;
|
||||
Ok((i, (name, param.map(|s| s.1))))
|
||||
}
|
||||
|
||||
fn attr(i: &[u8]) -> IResult<&[u8], (&str, Option<Vec<Expr<'_>>>)> {
|
||||
let (i, (_, attr, args)) =
|
||||
tuple((ws(tag(".")), alt((num_lit, identifier)), ws(opt(arguments))))(i)?;
|
||||
@ -790,8 +695,7 @@ fn cond_if(i: &[u8]) -> IResult<&[u8], CondTest<'_>> {
|
||||
ws(tag("if")),
|
||||
opt(tuple((
|
||||
ws(alt((tag("let"), tag("set")))),
|
||||
ws(match_variant),
|
||||
opt(alt((match_simple_parameters, match_named_parameters))),
|
||||
ws(target),
|
||||
ws(tag("=")),
|
||||
))),
|
||||
ws(expr_any),
|
||||
@ -800,7 +704,7 @@ fn cond_if(i: &[u8]) -> IResult<&[u8], CondTest<'_>> {
|
||||
Ok((
|
||||
i,
|
||||
CondTest {
|
||||
target: dest.map(|(_, variant, params, _)| (variant, params)),
|
||||
target: dest.map(|(_, target, _)| target),
|
||||
expr,
|
||||
},
|
||||
))
|
||||
@ -852,12 +756,7 @@ fn match_else_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Whe
|
||||
let (i, (_, pws, _, nws, _, block)) = p(i)?;
|
||||
Ok((
|
||||
i,
|
||||
(
|
||||
Ws(pws.is_some(), nws.is_some()),
|
||||
None,
|
||||
MatchParameters::Simple(vec![]),
|
||||
block,
|
||||
),
|
||||
(Ws(pws.is_some(), nws.is_some()), Target::Name("_"), block),
|
||||
))
|
||||
}
|
||||
|
||||
@ -866,22 +765,13 @@ fn when_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], When<'a>>
|
||||
|i| tag_block_start(i, s),
|
||||
opt(tag("-")),
|
||||
ws(tag("when")),
|
||||
ws(match_variant),
|
||||
opt(ws(with_parameters)),
|
||||
ws(target),
|
||||
opt(tag("-")),
|
||||
|i| tag_block_end(i, s),
|
||||
|i| parse_template(i, s),
|
||||
));
|
||||
let (i, (_, pws, _, variant, params, nws, _, block)) = p(i)?;
|
||||
Ok((
|
||||
i,
|
||||
(
|
||||
Ws(pws.is_some(), nws.is_some()),
|
||||
Some(variant),
|
||||
params.unwrap_or_default(),
|
||||
block,
|
||||
),
|
||||
))
|
||||
let (i, (_, pws, _, target, nws, _, block)) = p(i)?;
|
||||
Ok((i, (Ws(pws.is_some(), nws.is_some()), target, block)))
|
||||
}
|
||||
|
||||
fn block_match<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>> {
|
||||
|
10
testing/templates/match-option-result-option.html
Normal file
10
testing/templates/match-option-result-option.html
Normal file
@ -0,0 +1,10 @@
|
||||
{%- match foo -%}
|
||||
{%- when None -%}
|
||||
nothing
|
||||
{%- when Some(Err(err)) -%}
|
||||
err={{err}}
|
||||
{%- when Some(Ok(None)) -%}
|
||||
num=absent
|
||||
{%- when Some(Ok(Some(num))) -%}
|
||||
num={{num}}
|
||||
{%- endmatch -%}
|
@ -130,3 +130,27 @@ fn test_match_without_with_keyword() {
|
||||
let s = MatchWithoutWithKeyword { foo: None };
|
||||
assert_eq!(s.render().unwrap(), "");
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "match-option-result-option.html")]
|
||||
struct MatchOptionResultOption {
|
||||
foo: Option<Result<Option<usize>, &'static str>>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_option_result_option() {
|
||||
let s = MatchOptionResultOption { foo: None };
|
||||
assert_eq!(s.render().unwrap(), "nothing");
|
||||
let s = MatchOptionResultOption {
|
||||
foo: Some(Err("fail")),
|
||||
};
|
||||
assert_eq!(s.render().unwrap(), "err=fail");
|
||||
let s = MatchOptionResultOption {
|
||||
foo: Some(Ok(None)),
|
||||
};
|
||||
assert_eq!(s.render().unwrap(), "num=absent");
|
||||
let s = MatchOptionResultOption {
|
||||
foo: Some(Ok(Some(4711))),
|
||||
};
|
||||
assert_eq!(s.render().unwrap(), "num=4711");
|
||||
}
|
||||
|
11
testing/tests/ui/lit_on_assignment_lhs.rs
Normal file
11
testing/tests/ui/lit_on_assignment_lhs.rs
Normal file
@ -0,0 +1,11 @@
|
||||
use askama::Template;
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(
|
||||
source = "{%let 7=x%}",
|
||||
ext = "txt"
|
||||
)]
|
||||
struct MyTemplate;
|
||||
|
||||
fn main() {
|
||||
}
|
7
testing/tests/ui/lit_on_assignment_lhs.stderr
Normal file
7
testing/tests/ui/lit_on_assignment_lhs.stderr
Normal file
@ -0,0 +1,7 @@
|
||||
error: proc-macro derive panicked
|
||||
--> $DIR/lit_on_assignment_lhs.rs:3:10
|
||||
|
|
||||
3 | #[derive(Template)]
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= help: message: Cannot have literals on the left-hand-side of an assignment.
|
@ -105,3 +105,29 @@ fn test_destruct_tuple() {
|
||||
};
|
||||
assert_eq!(t.render().unwrap(), "wxyz\nwz\nw");
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(
|
||||
source = "{% let x = 1 %}{% for x in x..=x %}{{ x }}{% endfor %}",
|
||||
ext = "txt"
|
||||
)]
|
||||
struct DeclRange;
|
||||
|
||||
#[test]
|
||||
fn test_decl_range() {
|
||||
let t = DeclRange;
|
||||
assert_eq!(t.render().unwrap(), "1");
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(
|
||||
source = "{% let x %}{% let x = 1 %}{% for x in x..=x %}{{ x }}{% endfor %}",
|
||||
ext = "txt"
|
||||
)]
|
||||
struct DeclAssignRange;
|
||||
|
||||
#[test]
|
||||
fn test_decl_assign_range() {
|
||||
let t = DeclAssignRange;
|
||||
assert_eq!(t.render().unwrap(), "1");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user