aboutsummaryrefslogtreecommitdiffstats
path: root/askama_shared
diff options
context:
space:
mode:
authorLibravatar Nathan Lapel <nathanlapel@gmail.com>2020-03-15 11:46:31 +0100
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2020-03-18 22:33:51 +0100
commit520c5d7d5f09c0b205e6e1c471483730380c5e33 (patch)
tree23b9c9560ebc78d74ddee2a71d48b3025659644e /askama_shared
parentcff49453a851029f87b35512f5234a999fea3e6c (diff)
downloadaskama-520c5d7d5f09c0b205e6e1c471483730380c5e33.tar.gz
askama-520c5d7d5f09c0b205e6e1c471483730380c5e33.tar.bz2
askama-520c5d7d5f09c0b205e6e1c471483730380c5e33.zip
Support function calls
Diffstat (limited to 'askama_shared')
-rw-r--r--askama_shared/src/generator.rs39
-rw-r--r--askama_shared/src/parser.rs66
2 files changed, 96 insertions, 9 deletions
diff --git a/askama_shared/src/generator.rs b/askama_shared/src/generator.rs
index 59df687..fb8619e 100644
--- a/askama_shared/src/generator.rs
+++ b/askama_shared/src/generator.rs
@@ -909,7 +909,9 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
Expr::StrLit(s) => self.visit_str_lit(buf, s),
Expr::CharLit(s) => self.visit_char_lit(buf, s),
Expr::Var(s) => self.visit_var(buf, s),
+ Expr::VarCall(var, ref args) => self.visit_var_call(buf, var, args),
Expr::Path(ref path) => self.visit_path(buf, path),
+ Expr::PathCall(ref path, ref args) => self.visit_path_call(buf, path, args),
Expr::Array(ref elements) => self.visit_array(buf, elements),
Expr::Attr(ref obj, name) => self.visit_attr(buf, obj, name),
Expr::Index(ref obj, ref key) => self.visit_index(buf, obj, key),
@@ -1160,6 +1162,24 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
DisplayWrap::Unwrapped
}
+ fn visit_path_call(&mut self, buf: &mut Buffer, path: &[&str], args: &[Expr]) -> DisplayWrap {
+ for (i, part) in path.iter().enumerate() {
+ if i > 0 {
+ buf.write("::");
+ }
+ buf.write(part);
+ }
+ buf.write("(");
+ for (i, arg) in args.iter().enumerate() {
+ if i > 0 {
+ buf.write(",");
+ }
+ self.visit_expr(buf, arg);
+ }
+ buf.write(")");
+ DisplayWrap::Unwrapped
+ }
+
fn visit_var(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap {
if self.locals.contains(s) || s == "self" {
buf.write(s);
@@ -1170,6 +1190,25 @@ impl<'a, S: std::hash::BuildHasher> Generator<'a, S> {
DisplayWrap::Unwrapped
}
+ fn visit_var_call(&mut self, buf: &mut Buffer, s: &str, args: &[Expr]) -> DisplayWrap {
+ buf.write("(");
+ if self.locals.contains(s) || s == "self" {
+ buf.write(s);
+ } else {
+ buf.write("self.");
+ buf.write(s);
+ }
+ buf.write(")(");
+ for (i, arg) in args.iter().enumerate() {
+ if i > 0 {
+ buf.write(",");
+ }
+ self.visit_expr(buf, arg);
+ }
+ buf.write(")");
+ DisplayWrap::Unwrapped
+ }
+
fn visit_bool_lit(&mut self, buf: &mut Buffer, s: &str) -> DisplayWrap {
buf.write(s);
DisplayWrap::Unwrapped
diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs
index 9c3358e..b6404c5 100644
--- a/askama_shared/src/parser.rs
+++ b/askama_shared/src/parser.rs
@@ -10,14 +10,16 @@ use std::str;
use crate::Syntax;
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub enum Expr<'a> {
BoolLit(&'a str),
NumLit(&'a str),
StrLit(&'a str),
CharLit(&'a str),
Var(&'a str),
+ VarCall(&'a str, Vec<Expr<'a>>),
Path(Vec<&'a str>),
+ PathCall(Vec<&'a str>, Vec<Expr<'a>>),
Array(Vec<Expr<'a>>),
Attr(Box<Expr<'a>>, &'a str),
Index(Box<Expr<'a>>, Box<Expr<'a>>),
@@ -30,7 +32,7 @@ pub enum Expr<'a> {
RustMacro(&'a str, &'a str),
}
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub enum MatchVariant<'a> {
Path(Vec<&'a str>),
Name(&'a str),
@@ -39,7 +41,7 @@ pub enum MatchVariant<'a> {
CharLit(&'a str),
}
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub enum MatchParameter<'a> {
Name(&'a str),
NumLit(&'a str),
@@ -47,16 +49,16 @@ pub enum MatchParameter<'a> {
CharLit(&'a str),
}
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub enum Target<'a> {
Name(&'a str),
Tuple(Vec<&'a str>),
}
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq)]
pub struct WS(pub bool, pub bool);
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub struct Macro<'a> {
pub ws1: WS,
pub args: Vec<&'a str>,
@@ -64,7 +66,7 @@ pub struct Macro<'a> {
pub ws2: WS,
}
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub enum Node<'a> {
Lit(&'a str, &'a str, &'a str),
Comment(WS),
@@ -84,6 +86,7 @@ pub enum Node<'a> {
}
pub type Cond<'a> = (WS, Option<Expr<'a>>, Vec<Node<'a>>);
+
pub type When<'a> = (
WS,
Option<MatchVariant<'a>>,
@@ -91,7 +94,7 @@ pub type When<'a> = (
Vec<Node<'a>>,
);
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub enum MatchParameters<'a> {
Simple(Vec<MatchParameter<'a>>),
Named(Vec<(&'a str, Option<MatchParameter<'a>>)>),
@@ -301,15 +304,30 @@ fn expr_var(i: &[u8]) -> IResult<&[u8], Expr> {
map(identifier, |s| Expr::Var(s))(i)
}
-fn expr_path(i: &[u8]) -> IResult<&[u8], Expr> {
+fn expr_var_call(i: &[u8]) -> IResult<&[u8], Expr> {
+ let (i, (s, args)) = tuple((identifier, arguments))(i)?;
+ Ok((i, Expr::VarCall(s, args)))
+}
+
+fn path(i: &[u8]) -> IResult<&[u8], Vec<&str>> {
let tail = separated_nonempty_list(tag("::"), identifier);
let (i, (start, _, rest)) = tuple((identifier, tag("::"), tail))(i)?;
let mut path = vec![start];
path.extend(rest);
+ Ok((i, path))
+}
+
+fn expr_path(i: &[u8]) -> IResult<&[u8], Expr> {
+ let (i, path) = path(i)?;
Ok((i, Expr::Path(path)))
}
+fn expr_path_call(i: &[u8]) -> IResult<&[u8], Expr> {
+ let (i, (path, args)) = tuple((path, arguments))(i)?;
+ Ok((i, Expr::PathCall(path, args)))
+}
+
fn variant_path(i: &[u8]) -> IResult<&[u8], MatchVariant> {
map(separated_nonempty_list(tag("::"), identifier), |path| {
MatchVariant::Path(path)
@@ -437,9 +455,11 @@ fn expr_single(i: &[u8]) -> IResult<&[u8], Expr> {
expr_num_lit,
expr_str_lit,
expr_char_lit,
+ expr_path_call,
expr_path,
expr_rust_macro,
expr_array_lit,
+ expr_var_call,
expr_var,
expr_group,
))(i)
@@ -1079,6 +1099,34 @@ mod tests {
}
#[test]
+ fn test_parse_var_call() {
+ assert_eq!(
+ super::parse("{{ function(\"123\", 3) }}", &Syntax::default()),
+ vec![super::Node::Expr(
+ super::WS(false, false),
+ super::Expr::VarCall(
+ "function",
+ vec![super::Expr::StrLit("123"), super::Expr::NumLit("3")]
+ ),
+ )],
+ );
+ }
+
+ #[test]
+ fn test_parse_path_call() {
+ assert_eq!(
+ super::parse("{{ self::function(\"123\", 3) }}", &Syntax::default()),
+ vec![super::Node::Expr(
+ super::WS(false, false),
+ super::Expr::PathCall(
+ vec!["self", "function"],
+ vec![super::Expr::StrLit("123"), super::Expr::NumLit("3")],
+ ),
+ )],
+ );
+ }
+
+ #[test]
fn change_delimiters_parse_filter() {
let syntax = Syntax {
expr_start: "{~",