mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 07:20:55 +00:00
fix rust macro arguments
This commit is contained in:
parent
65b4f6aae7
commit
39e08325c0
@ -1,6 +1,8 @@
|
||||
use super::{get_template_source, Context, Heritage};
|
||||
use crate::input::TemplateInput;
|
||||
use crate::parser::{Cond, Expr, MatchParameter, MatchParameters, MatchVariant, Node, Target, When, WS};
|
||||
use crate::parser::{
|
||||
Cond, Expr, MatchParameter, MatchParameters, MatchVariant, Node, Target, When, WS,
|
||||
};
|
||||
use askama_shared::filters;
|
||||
|
||||
use proc_macro2::Span;
|
||||
@ -773,14 +775,14 @@ impl<'a> Generator<'a> {
|
||||
Expr::MethodCall(ref obj, method, ref args) => {
|
||||
self.visit_method_call(buf, obj, method, args)
|
||||
}
|
||||
Expr::RustMacro(name, ref args) => self.visit_rust_macro(buf, name, args),
|
||||
Expr::RustMacro(name, args) => self.visit_rust_macro(buf, name, args),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_rust_macro(&mut self, buf: &mut Buffer, name: &str, args: &[Expr]) -> DisplayWrap {
|
||||
fn visit_rust_macro(&mut self, buf: &mut Buffer, name: &str, args: &str) -> DisplayWrap {
|
||||
buf.write(name);
|
||||
buf.write("!(");
|
||||
self._visit_args(buf, args);
|
||||
buf.write(args);
|
||||
buf.write(")");
|
||||
|
||||
DisplayWrap::Unwrapped
|
||||
|
@ -21,7 +21,7 @@ pub enum Expr<'a> {
|
||||
Range(&'a str, Option<Box<Expr<'a>>>, Option<Box<Expr<'a>>>),
|
||||
Group(Box<Expr<'a>>),
|
||||
MethodCall(Box<Expr<'a>>, &'a str, Vec<Expr<'a>>),
|
||||
RustMacro(&'a str, Vec<Expr<'a>>),
|
||||
RustMacro(&'a str, &'a str),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -302,6 +302,60 @@ named!(arguments<Input, Vec<Expr>>, do_parse!(
|
||||
(args.unwrap_or_default())
|
||||
));
|
||||
|
||||
named!(macro_arguments<Input, &str>,
|
||||
delimited!(char!('('), nested_parenthesis, char!(')'))
|
||||
);
|
||||
|
||||
fn nested_parenthesis(i: Input) -> Result<(Input, &str), nom::Err<Input>> {
|
||||
let mut nested = 0;
|
||||
let mut last = 0;
|
||||
let mut in_str = false;
|
||||
let mut escaped = false;
|
||||
|
||||
for (i, b) in i.iter().enumerate() {
|
||||
if !(*b == b'(' || *b == b')') || !in_str {
|
||||
match *b {
|
||||
b'(' => {
|
||||
nested += 1
|
||||
},
|
||||
b')' => {
|
||||
if nested == 0 {
|
||||
last = i;
|
||||
break;
|
||||
}
|
||||
nested -= 1;
|
||||
},
|
||||
b'"' => {
|
||||
if in_str {
|
||||
if !escaped {
|
||||
in_str = false;
|
||||
}
|
||||
} else {
|
||||
in_str = true;
|
||||
}
|
||||
},
|
||||
b'\\' => {
|
||||
escaped = !escaped;
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if escaped && *b != b'\\' {
|
||||
escaped = false;
|
||||
}
|
||||
}
|
||||
|
||||
if nested == 0 {
|
||||
Ok((Input(&i[last..]), str::from_utf8(&i[..last]).unwrap()))
|
||||
} else {
|
||||
Err(nom::Err::Error(error_position!(
|
||||
i,
|
||||
nom::ErrorKind::Custom(0)
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
named!(parameters<Input, Vec<&str>>, do_parse!(
|
||||
tag!("(") >>
|
||||
vals: opt!(do_parse!(
|
||||
@ -477,11 +531,10 @@ named!(expr_unary<Input, Expr>, do_parse!(
|
||||
named!(rust_macro<Input, Expr>, do_parse!(
|
||||
mname: identifier >>
|
||||
tag!("!") >>
|
||||
args: arguments >>
|
||||
args: macro_arguments >>
|
||||
(Expr::RustMacro(mname, args))
|
||||
));
|
||||
|
||||
|
||||
macro_rules! expr_prec_layer {
|
||||
( $name:ident, $inner:ident, $( $op:expr ),* ) => {
|
||||
named!($name<Input, Expr>, do_parse!(
|
||||
@ -503,9 +556,7 @@ expr_prec_layer!(expr_shifts, expr_addsub, ">>", "<<");
|
||||
expr_prec_layer!(expr_band, expr_shifts, "&");
|
||||
expr_prec_layer!(expr_bxor, expr_band, "^");
|
||||
expr_prec_layer!(expr_bor, expr_bxor, "|");
|
||||
expr_prec_layer!(expr_compare, expr_bor,
|
||||
"==", "!=", ">=", ">", "<=", "<"
|
||||
);
|
||||
expr_prec_layer!(expr_compare, expr_bor, "==", "!=", ">=", ">", "<=", "<");
|
||||
expr_prec_layer!(expr_and, expr_compare, "&&");
|
||||
expr_prec_layer!(expr_or, expr_and, "||");
|
||||
|
||||
|
26
testing/templates/rust-macro-args.html
Normal file
26
testing/templates/rust-macro-args.html
Normal file
@ -0,0 +1,26 @@
|
||||
{{
|
||||
call_a_or_b_on_tail!(
|
||||
(a: compute_len, b: zero),
|
||||
the recursive part that skips over all these
|
||||
tokens doesn't much care whether we will call a
|
||||
or call b: only the terminal rules care.
|
||||
)
|
||||
}}
|
||||
{{
|
||||
call_a_or_b_on_tail!(
|
||||
(a: compute_len, b: zero),
|
||||
and now, to justify the existence of two paths
|
||||
we will also call a: its input should somehow
|
||||
be self-referential, so let's make it return
|
||||
some ninety one!
|
||||
)
|
||||
}}
|
||||
{{
|
||||
call_a_or_b_on_tail!(
|
||||
(a: compute_len, b: zero),
|
||||
and now, to justify the existence of two paths
|
||||
we will also call a: its input should somehow
|
||||
be self-referential, so let's make it return
|
||||
some ninety "(\"()"nine!
|
||||
)
|
||||
}}
|
@ -15,3 +15,35 @@ fn main() {
|
||||
let template = RustMacrosTemplate {};
|
||||
assert_eq!("Hello, world!", template.render().unwrap());
|
||||
}
|
||||
|
||||
macro_rules! call_a_or_b_on_tail {
|
||||
((a: $a:expr, b: $b:expr), call a: $($tail:tt)*) => {
|
||||
$a(stringify!($($tail)*))
|
||||
};
|
||||
|
||||
((a: $a:expr, b: $b:expr), call b: $($tail:tt)*) => {
|
||||
$b(stringify!($($tail)*))
|
||||
};
|
||||
|
||||
($ab:tt, $_skip:tt $($tail:tt)*) => {
|
||||
call_a_or_b_on_tail!($ab, $($tail)*)
|
||||
};
|
||||
}
|
||||
|
||||
fn compute_len(s: &str) -> usize {
|
||||
s.len()
|
||||
}
|
||||
|
||||
fn zero(_s: &str) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
#[derive(Template)]
|
||||
#[template(path = "rust-macro-args.html")]
|
||||
struct RustMacrosArgTemplate {}
|
||||
|
||||
#[test]
|
||||
fn args() {
|
||||
let template = RustMacrosArgTemplate {};
|
||||
assert_eq!("0\n91\n99", template.render().unwrap());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user