1 use std
::collections
::HashMap
;
3 use crate::parser
::ast
::*;
4 use crate::parser
::parse
;
7 fn parse_empty_template() {
8 let ast
= parse("").unwrap();
9 assert_eq
!(ast
.len(), 0);
14 let ast
= parse("hello world").unwrap();
15 assert_eq
!(ast
[0], Node
::Text("hello world".to_string()));
19 fn parse_text_with_whitespace() {
20 let ast
= parse(" hello world ").unwrap();
21 assert_eq
!(ast
[0], Node
::Text(" hello world ".to_string()));
25 fn parse_include_tag() {
26 let ast
= parse("{% include \"index.html\" -%}").unwrap();
29 Node
::Include(WS { left: false, right: true }
, vec
!["index.html".to_string()], false,),
32 parse("{% include [\"custom/index.html\", \"index.html\"] ignore missing %}").unwrap();
36 WS { left: false, right: false }
,
37 vec
!["custom/index.html".to_string(), "index.html".to_string()],
45 let ast
= parse("{% extends \"index.html\" -%}").unwrap();
46 assert_eq
!(ast
[0], Node
::Extends(WS { left: false, right: true }
, "index.html".to_string(),),);
50 fn parse_comments_before_extends() {
51 let ast
= parse("{# A comment #}{% extends \"index.html\" -%}").unwrap();
52 assert_eq
!(ast
[0], Node
::Extends(WS { left: false, right: true }
, "index.html".to_string(),),);
56 fn parse_import_macro() {
57 let ast
= parse("\n{% import \"macros.html\" as macros -%}").unwrap();
61 WS { left: false, right: true }
,
62 "macros.html".to_string(),
69 fn parse_variable_with_whitespace_trimming() {
70 let ast
= parse("{{- id }}").unwrap();
74 WS { left: true, right: false }
,
75 Expr
::new(ExprVal
::Ident("id".to_string()))
81 fn parse_variable_tag_ident() {
82 let ast
= parse("{{ id }}").unwrap();
85 Node
::VariableBlock(WS
::default(), Expr
::new(ExprVal
::Ident("id".to_string()))),
90 fn parse_variable_tag_ident_with_simple_filters() {
91 let ast
= parse("{{ arr | first | join(n=2) }}").unwrap();
92 let mut join_args
= HashMap
::new();
93 join_args
.insert("n".to_string(), Expr
::new(ExprVal
::Int(2)));
100 ExprVal
::Ident("arr".to_string()),
102 FunctionCall { name: "first".to_string(), args: HashMap::new() }
,
103 FunctionCall { name: "join".to_string(), args: join_args }
,
111 fn parse_variable_tag_lit() {
112 let ast
= parse("{{ 2 }}{{ 3.14 }}{{ \"hey\" }}{{ true }}").unwrap();
113 assert_eq
!(ast
[0], Node
::VariableBlock(WS
::default(), Expr
::new(ExprVal
::Int(2))));
114 assert_eq
!(ast
[1], Node
::VariableBlock(WS
::default(), Expr
::new(ExprVal
::Float(3.14))));
117 Node
::VariableBlock(WS
::default(), Expr
::new(ExprVal
::String("hey".to_string()))),
119 assert_eq
!(ast
[3], Node
::VariableBlock(WS
::default(), Expr
::new(ExprVal
::Bool(true))));
123 fn parse_variable_tag_array_lit() {
124 let ast
= parse("{{ [1, 2, 3] }}").unwrap();
125 let mut join_args
= HashMap
::new();
126 join_args
.insert("n".to_string(), Expr
::new(ExprVal
::Int(2)));
132 Expr
::new(ExprVal
::Array(vec
![
133 Expr
::new(ExprVal
::Int(1)),
134 Expr
::new(ExprVal
::Int(2)),
135 Expr
::new(ExprVal
::Int(3))
142 fn parse_variable_tag_array_lit_with_filter() {
143 let ast
= parse("{{ [1, 2, 3] | length }}").unwrap();
144 let mut join_args
= HashMap
::new();
145 join_args
.insert("n".to_string(), Expr
::new(ExprVal
::Int(2)));
153 Expr
::new(ExprVal
::Int(1)),
154 Expr
::new(ExprVal
::Int(2)),
155 Expr
::new(ExprVal
::Int(3))
157 vec
![FunctionCall { name: "length".to_string(), args: HashMap::new() }
,],
164 fn parse_variable_tag_lit_math_expression() {
165 let ast
= parse("{{ count + 1 * 2.5 }}").unwrap();
171 Expr
::new(ExprVal
::Math(MathExpr
{
172 lhs
: Box
::new(Expr
::new(ExprVal
::Ident("count".to_string()))),
173 operator
: MathOperator
::Add
,
174 rhs
: Box
::new(Expr
::new(ExprVal
::Math(MathExpr
{
175 lhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
176 operator
: MathOperator
::Mul
,
177 rhs
: Box
::new(Expr
::new(ExprVal
::Float(2.5))),
185 fn parse_variable_tag_lit_math_expression_with_parentheses() {
186 let ast
= parse("{{ (count + 1) * 2.5 }}").unwrap();
191 Expr
::new(ExprVal
::Math(MathExpr
{
192 lhs
: Box
::new(Expr
::new(ExprVal
::Math(MathExpr
{
193 lhs
: Box
::new(Expr
::new(ExprVal
::Ident("count".to_string()))),
194 operator
: MathOperator
::Add
,
195 rhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
197 operator
: MathOperator
::Mul
,
198 rhs
: Box
::new(Expr
::new(ExprVal
::Float(2.5))),
205 fn parse_variable_tag_lit_math_expression_with_parentheses_and_filter() {
206 let ast
= parse("{{ (count + 1) * 2.5 | round }}").unwrap();
212 ExprVal
::Math(MathExpr
{
213 lhs
: Box
::new(Expr
::new(ExprVal
::Math(MathExpr
{
214 lhs
: Box
::new(Expr
::new(ExprVal
::Ident("count".to_string()))),
215 operator
: MathOperator
::Add
,
216 rhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
218 operator
: MathOperator
::Mul
,
219 rhs
: Box
::new(Expr
::new(ExprVal
::Float(2.5))),
221 vec
![FunctionCall { name: "round".to_string(), args: HashMap::new() }
,],
228 fn parse_variable_math_on_filter() {
229 let ast
= parse("{{ a | length - 1 }}").unwrap();
234 Expr
::new(ExprVal
::Math(MathExpr
{
235 lhs
: Box
::new(Expr
::with_filters(
236 ExprVal
::Ident("a".to_string()),
237 vec
![FunctionCall { name: "length".to_string(), args: HashMap::new() }
,],
239 operator
: MathOperator
::Sub
,
240 rhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
247 fn parse_variable_tag_simple_logic_expression() {
248 let ast
= parse("{{ 1 > 2 }}").unwrap();
253 Expr
::new(ExprVal
::Logic(LogicExpr
{
254 lhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
255 operator
: LogicOperator
::Gt
,
256 rhs
: Box
::new(Expr
::new(ExprVal
::Int(2))),
263 fn parse_variable_tag_math_and_logic_expression() {
264 let ast
= parse("{{ count + 1 * 2.5 and admin }}").unwrap();
269 Expr
::new(ExprVal
::Logic(LogicExpr
{
270 lhs
: Box
::new(Expr
::new(ExprVal
::Math(MathExpr
{
271 lhs
: Box
::new(Expr
::new(ExprVal
::Ident("count".to_string()))),
272 operator
: MathOperator
::Add
,
273 rhs
: Box
::new(Expr
::new(ExprVal
::Math(MathExpr
{
274 lhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
275 operator
: MathOperator
::Mul
,
276 rhs
: Box
::new(Expr
::new(ExprVal
::Float(2.5))),
279 operator
: LogicOperator
::And
,
280 rhs
: Box
::new(Expr
::new(ExprVal
::Ident("admin".to_string()))),
287 fn parse_variable_tag_math_with_filters_and_logic_expression() {
288 let ast
= parse("{{ count + 1 * 2.5 | round and admin }}").unwrap();
293 Expr
::new(ExprVal
::Logic(LogicExpr
{
294 lhs
: Box
::new(Expr
::with_filters(
295 ExprVal
::Math(MathExpr
{
296 lhs
: Box
::new(Expr
::new(ExprVal
::Ident("count".to_string()))),
297 operator
: MathOperator
::Add
,
298 rhs
: Box
::new(Expr
::new(ExprVal
::Math(MathExpr
{
299 lhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
300 operator
: MathOperator
::Mul
,
301 rhs
: Box
::new(Expr
::new(ExprVal
::Float(2.5))),
304 vec
![FunctionCall { name: "round".to_string(), args: HashMap::new() }
,],
306 operator
: LogicOperator
::And
,
307 rhs
: Box
::new(Expr
::new(ExprVal
::Ident("admin".to_string()))),
314 fn parse_variable_tag_simple_negated_expr() {
315 let ast
= parse("{{ not id }}").unwrap();
318 Node
::VariableBlock(WS
::default(), Expr
::new_negated(ExprVal
::Ident("id".to_string())))
324 let ast
= parse("{{ a is divisibleby(2) }}").unwrap();
329 Expr
::new(ExprVal
::Test(Test
{
330 ident
: "a".to_string(),
332 name
: "divisibleby".to_string(),
333 args
: vec
![Expr
::new(ExprVal
::Int(2))]
340 fn parse_variable_tag_negated_expr() {
341 let ast
= parse("{{ not id and not true and not 1 + 1 }}").unwrap();
346 Expr
::new(ExprVal
::Logic(LogicExpr
{
347 lhs
: Box
::new(Expr
::new(ExprVal
::Logic(LogicExpr
{
348 lhs
: Box
::new(Expr
::new_negated(ExprVal
::Ident("id".to_string()))),
349 operator
: LogicOperator
::And
,
350 rhs
: Box
::new(Expr
::new_negated(ExprVal
::Bool(true))),
352 operator
: LogicOperator
::And
,
353 rhs
: Box
::new(Expr
::new_negated(ExprVal
::Math(MathExpr
{
354 lhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
355 operator
: MathOperator
::Add
,
356 rhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
364 fn parse_variable_tag_simple_test() {
365 let ast
= parse("{{ id is defined }}").unwrap();
370 Expr
::new(ExprVal
::Test(Test
{
371 ident
: "id".to_string(),
373 name
: "defined".to_string(),
381 fn parse_variable_tag_simple_negated_test() {
382 let ast
= parse("{{ id is not defined }}").unwrap();
387 Expr
::new(ExprVal
::Test(Test
{
388 ident
: "id".to_string(),
390 name
: "defined".to_string(),
398 fn parse_variable_tag_test_as_expression() {
399 let ast
= parse("{{ user is defined and user.admin }}").unwrap();
404 Expr
::new(ExprVal
::Logic(LogicExpr
{
405 lhs
: Box
::new(Expr
::new(ExprVal
::Test(Test
{
406 ident
: "user".to_string(),
408 name
: "defined".to_string(),
411 operator
: LogicOperator
::And
,
412 rhs
: Box
::new(Expr
::new(ExprVal
::Ident("user.admin".to_string()))),
419 fn parse_variable_tag_macro_call() {
420 let ast
= parse("{{ macros::get_time(some=1) }}").unwrap();
421 let mut args
= HashMap
::new();
422 args
.insert("some".to_string(), Expr
::new(ExprVal
::Int(1)));
428 Expr
::new(ExprVal
::MacroCall(MacroCall
{
429 namespace
: "macros".to_string(),
430 name
: "get_time".to_string(),
438 fn parse_allow_block_in_filter_section() {
440 parse("{% filter upper %}{% block content %}Hello{% endblock %}{% endfilter %}").unwrap();
447 filter
: FunctionCall { name: "upper".to_owned(), args: HashMap::default() }
,
448 body
: vec
![Node
::Block(
451 name
: "content".to_owned(),
452 body
: vec
![Node
::Text("Hello".to_owned())]
462 // smoke test for array in kwargs
464 fn parse_variable_tag_macro_call_with_array() {
465 let ast
= parse("{{ macros::get_time(some=[1, 2]) }}").unwrap();
466 let mut args
= HashMap
::new();
469 Expr
::new(ExprVal
::Array(vec
![Expr
::new(ExprVal
::Int(1)), Expr
::new(ExprVal
::Int(2))])),
476 Expr
::new(ExprVal
::MacroCall(MacroCall
{
477 namespace
: "macros".to_string(),
478 name
: "get_time".to_string(),
485 // smoke test for array in kwargs
487 fn parse_variable_tag_macro_call_with_array_with_filters() {
488 let ast
= parse("{{ macros::get_time(some=[1, 2] | reverse) }}").unwrap();
489 let mut args
= HashMap
::new();
493 ExprVal
::Array(vec
![Expr
::new(ExprVal
::Int(1)), Expr
::new(ExprVal
::Int(2))]),
494 vec
![FunctionCall { name: "reverse".to_string(), args: HashMap::new() }
],
502 Expr
::new(ExprVal
::MacroCall(MacroCall
{
503 namespace
: "macros".to_string(),
504 name
: "get_time".to_string(),
512 fn parse_variable_tag_macro_call_with_filter() {
513 let ast
= parse("{{ macros::get_time(some=1) | round }}").unwrap();
514 let mut args
= HashMap
::new();
515 args
.insert("some".to_string(), Expr
::new(ExprVal
::Int(1)));
522 ExprVal
::MacroCall(MacroCall
{
523 namespace
: "macros".to_string(),
524 name
: "get_time".to_string(),
527 vec
![FunctionCall { name: "round".to_string(), args: HashMap::new() }
,],
534 fn parse_variable_tag_global_function() {
535 let ast
= parse("{{ get_time(some=1) }}").unwrap();
536 let mut args
= HashMap
::new();
537 args
.insert("some".to_string(), Expr
::new(ExprVal
::Int(1)));
543 Expr
::new(ExprVal
::FunctionCall(FunctionCall { name: "get_time".to_string(), args }
,))
549 fn parse_in_condition() {
550 let ast
= parse("{{ b in c }}").unwrap();
551 let mut args
= HashMap
::new();
552 args
.insert("some".to_string(), Expr
::new(ExprVal
::Int(1)));
558 Expr
::new(ExprVal
::In(In
{
559 lhs
: Box
::new(Expr
::new(ExprVal
::Ident("b".to_string()))),
560 rhs
: Box
::new(Expr
::new(ExprVal
::Ident("c".to_string()))),
568 fn parse_negated_in_condition() {
569 let ast
= parse("{{ b not in c }}").unwrap();
570 let mut args
= HashMap
::new();
571 args
.insert("some".to_string(), Expr
::new(ExprVal
::Int(1)));
577 Expr
::new(ExprVal
::In(In
{
578 lhs
: Box
::new(Expr
::new(ExprVal
::Ident("b".to_string()))),
579 rhs
: Box
::new(Expr
::new(ExprVal
::Ident("c".to_string()))),
587 fn parse_variable_tag_global_function_with_filter() {
588 let ast
= parse("{{ get_time(some=1) | round | upper }}").unwrap();
589 let mut args
= HashMap
::new();
590 args
.insert("some".to_string(), Expr
::new(ExprVal
::Int(1)));
597 ExprVal
::FunctionCall(FunctionCall { name: "get_time".to_string(), args }
,),
599 FunctionCall { name: "round".to_string(), args: HashMap::new() }
,
600 FunctionCall { name: "upper".to_string(), args: HashMap::new() }
,
608 fn parse_comment_tag() {
609 let ast
= parse("{# hey #}").unwrap();
610 assert
!(ast
.is_empty());
614 fn parse_set_tag_lit() {
615 let ast
= parse("{% set hello = \"hi\" %}").unwrap();
621 key
: "hello".to_string(),
622 value
: Expr
::new(ExprVal
::String("hi".to_string())),
630 fn parse_set_tag_macro_call() {
631 let ast
= parse("{% set hello = macros::something() %}").unwrap();
637 key
: "hello".to_string(),
638 value
: Expr
::new(ExprVal
::MacroCall(MacroCall
{
639 namespace
: "macros".to_string(),
640 name
: "something".to_string(),
641 args
: HashMap
::new(),
650 fn parse_set_tag_fn_call() {
651 let ast
= parse("{% set hello = utcnow() %}").unwrap();
657 key
: "hello".to_string(),
658 value
: Expr
::new(ExprVal
::FunctionCall(FunctionCall
{
659 name
: "utcnow".to_string(),
660 args
: HashMap
::new(),
669 fn parse_set_array() {
670 let ast
= parse("{% set hello = [1, true, 'hello'] %}").unwrap();
676 key
: "hello".to_string(),
677 value
: Expr
::new(ExprVal
::Array(vec
![
678 Expr
::new(ExprVal
::Int(1)),
679 Expr
::new(ExprVal
::Bool(true)),
680 Expr
::new(ExprVal
::String("hello".to_string())),
689 fn parse_set_array_with_filter() {
690 let ast
= parse("{% set hello = [1, true, 'hello'] | length %}").unwrap();
696 key
: "hello".to_string(),
697 value
: Expr
::with_filters(
699 Expr
::new(ExprVal
::Int(1)),
700 Expr
::new(ExprVal
::Bool(true)),
701 Expr
::new(ExprVal
::String("hello".to_string())),
703 vec
![FunctionCall { name: "length".to_string(), args: HashMap::new() }
,],
712 fn parse_set_global_tag() {
713 let ast
= parse("{% set_global hello = utcnow() %}").unwrap();
719 key
: "hello".to_string(),
720 value
: Expr
::new(ExprVal
::FunctionCall(FunctionCall
{
721 name
: "utcnow".to_string(),
722 args
: HashMap
::new(),
732 let ast
= parse("{% raw -%}{{hey}}{%- endraw %}").unwrap();
733 let mut start_ws
= WS
::default();
734 start_ws
.right
= true;
735 let mut end_ws
= WS
::default();
738 assert_eq
!(ast
[0], Node
::Raw(start_ws
, "{{hey}}".to_string(), end_ws
));
741 // https://github.com/Keats/tera/issues/513
743 fn parse_raw_tag_with_ws() {
744 // println!("{}", parse("{% raw %} yaml_test: {% endraw %}").unwrap_err());
745 let ast
= parse("{% raw %} yaml_test: {% endraw %}").unwrap();
746 let start_ws
= WS
::default();
747 let end_ws
= WS
::default();
749 assert_eq
!(ast
[0], Node
::Raw(start_ws
, " yaml_test: ".to_string(), end_ws
));
753 fn parse_filter_section_without_args() {
754 let ast
= parse("{% filter upper -%}A{%- endfilter %}").unwrap();
755 let mut start_ws
= WS
::default();
756 start_ws
.right
= true;
757 let mut end_ws
= WS
::default();
765 filter
: FunctionCall { name: "upper".to_string(), args: HashMap::new() }
,
766 body
: vec
![Node
::Text("A".to_string())],
774 fn parse_filter_section_with_args() {
775 let ast
= parse("{% filter upper(attr=1) -%}A{%- endfilter %}").unwrap();
776 let mut start_ws
= WS
::default();
777 start_ws
.right
= true;
778 let mut end_ws
= WS
::default();
781 let mut args
= HashMap
::new();
782 args
.insert("attr".to_string(), Expr
::new(ExprVal
::Int(1)));
789 filter
: FunctionCall { name: "upper".to_string(), args }
,
790 body
: vec
![Node
::Text("A".to_string())],
798 fn parse_filter_section_preserves_ws() {
799 let ast
= parse("{% filter upper %} {{a}} B {% endfilter %}").unwrap();
806 filter
: FunctionCall { name: "upper".to_string(), args: HashMap::new() }
,
808 Node
::Text(" ".to_string()),
809 Node
::VariableBlock(WS
::default(), Expr
::new(ExprVal
::Ident("a".to_string()))),
810 Node
::Text(" B ".to_string())
820 let ast
= parse("{% block hello %}{{super()}} hey{%- endblock hello %}").unwrap();
821 let start_ws
= WS
::default();
822 let mut end_ws
= WS
::default();
830 name
: "hello".to_string(),
831 body
: vec
![Node
::Super
, Node
::Text(" hey".to_string())],
839 fn parse_simple_macro_definition() {
840 let ast
= parse("{% macro hello(a=1, b='hello', c) %}A: {{a}}{% endmacro %}").unwrap();
841 let mut args
= HashMap
::new();
842 args
.insert("a".to_string(), Some(Expr
::new(ExprVal
::Int(1))));
843 args
.insert("b".to_string(), Some(Expr
::new(ExprVal
::String("hello".to_string()))));
844 args
.insert("c".to_string(), None
);
848 Node
::MacroDefinition(
851 name
: "hello".to_string(),
854 Node
::Text("A: ".to_string()),
855 Node
::VariableBlock(WS
::default(), Expr
::new(ExprVal
::Ident("a".to_string()))),
864 fn parse_value_forloop() {
865 let ast
= parse("{% for item in items | reverse %}A{%- endfor %}").unwrap();
866 let start_ws
= WS
::default();
867 let mut end_ws
= WS
::default();
876 value
: "item".to_string(),
877 container
: Expr
::with_filters(
878 ExprVal
::Ident("items".to_string()),
879 vec
![FunctionCall { name: "reverse".to_string(), args: HashMap::new() }
,],
881 body
: vec
![Node
::Text("A".to_string())],
890 fn parse_key_value_forloop() {
891 let ast
= parse("{% for key, item in get_map() %}A{%- endfor %}").unwrap();
892 let start_ws
= WS
::default();
893 let mut end_ws
= WS
::default();
901 key
: Some("key".to_string()),
902 value
: "item".to_string(),
903 container
: Expr
::new(ExprVal
::FunctionCall(FunctionCall
{
904 name
: "get_map".to_string(),
905 args
: HashMap
::new(),
907 body
: vec
![Node
::Text("A".to_string())],
916 fn parse_value_forloop_array() {
917 let ast
= parse("{% for item in [1,2,] %}A{%- endfor %}").unwrap();
918 let start_ws
= WS
::default();
919 let mut end_ws
= WS
::default();
928 value
: "item".to_string(),
929 container
: Expr
::new(ExprVal
::Array(vec
![
930 Expr
::new(ExprVal
::Int(1)),
931 Expr
::new(ExprVal
::Int(2)),
933 body
: vec
![Node
::Text("A".to_string())],
942 fn parse_value_forloop_array_with_filter() {
943 let ast
= parse("{% for item in [1,2,] | reverse %}A{%- endfor %}").unwrap();
944 let start_ws
= WS
::default();
945 let mut end_ws
= WS
::default();
954 value
: "item".to_string(),
955 container
: Expr
::with_filters(
956 ExprVal
::Array(vec
![Expr
::new(ExprVal
::Int(1)), Expr
::new(ExprVal
::Int(2)),]),
957 vec
![FunctionCall { name: "reverse".to_string(), args: HashMap::new() }
,],
959 body
: vec
![Node
::Text("A".to_string())],
968 fn parse_value_forloop_empty() {
969 let ast
= parse("{% for item in [1,2,] %}A{% else %}B{%- endfor %}").unwrap();
970 let start_ws
= WS
::default();
971 let mut end_ws
= WS
::default();
980 value
: "item".to_string(),
981 container
: Expr
::new(ExprVal
::Array(vec
![
982 Expr
::new(ExprVal
::Int(1)),
983 Expr
::new(ExprVal
::Int(2)),
985 body
: vec
![Node
::Text("A".to_string())],
986 empty_body
: Some(vec
![Node
::Text("B".to_string())]),
995 let ast
= parse("{% if item or admin %}A {%- elif 1 > 2 %}B{% else -%} C{%- endif %}").unwrap();
996 let mut end_ws
= WS
::default();
999 let mut else_ws
= WS
::default();
1000 else_ws
.right
= true;
1009 Expr
::new(ExprVal
::Logic(LogicExpr
{
1010 lhs
: Box
::new(Expr
::new(ExprVal
::Ident("item".to_string()))),
1011 operator
: LogicOperator
::Or
,
1012 rhs
: Box
::new(Expr
::new(ExprVal
::Ident("admin".to_string()))),
1014 vec
![Node
::Text("A ".to_string())],
1018 Expr
::new(ExprVal
::Logic(LogicExpr
{
1019 lhs
: Box
::new(Expr
::new(ExprVal
::Int(1))),
1020 operator
: LogicOperator
::Gt
,
1021 rhs
: Box
::new(Expr
::new(ExprVal
::Int(2))),
1023 vec
![Node
::Text("B".to_string())],
1026 otherwise
: Some((else_ws
, vec
![Node
::Text(" C".to_string())])),
1035 let ast
= parse("{% for item in items %}{% break -%}{% endfor %}").unwrap();
1036 let for_ws
= WS
::default();
1043 value
: "item".to_string(),
1044 container
: Expr
::new(ExprVal
::Ident("items".to_string())),
1045 body
: vec
![Node
::Break(WS { left: false, right: true }
),],
1054 fn parse_continue() {
1055 let ast
= parse("{% for item in items %}{% continue -%}{% endfor %}").unwrap();
1056 let for_ws
= WS
::default();
1063 value
: "item".to_string(),
1064 container
: Expr
::new(ExprVal
::Ident("items".to_string())),
1065 body
: vec
![Node
::Continue(WS { left: false, right: true }
),],
1074 fn parse_string_concat_can_merge() {
1075 let ast
= parse("{{ `hello` ~ 'hey' }}").unwrap();
1078 Node
::VariableBlock(WS
::default(), Expr
::new(ExprVal
::String("hellohey".to_string()))),
1082 fn parse_string_concat() {
1083 let ast
= parse("{{ `hello` ~ ident }}").unwrap();
1086 Node
::VariableBlock(
1088 Expr
::new(ExprVal
::StringConcat(StringConcat
{
1090 ExprVal
::String("hello".to_string()),
1091 ExprVal
::Ident("ident".to_string()),
1099 fn parse_string_concat_multiple() {
1100 let ast
= parse("{{ `hello` ~ ident ~ 'ho' }}").unwrap();
1103 Node
::VariableBlock(
1105 Expr
::new(ExprVal
::StringConcat(StringConcat
{
1107 ExprVal
::String("hello".to_string()),
1108 ExprVal
::Ident("ident".to_string()),
1109 ExprVal
::String("ho".to_string()),