1+ use std:: fmt;
12use std:: slice:: Iter ;
23
34use itertools;
@@ -20,6 +21,31 @@ enum Range {
2021 Counted ( Argument , Argument ) ,
2122}
2223
24+ impl Range {
25+ pub fn evaluate ( & self , context : & Context ) -> Result < Vec < Value > > {
26+ let range = match * self {
27+ Range :: Array ( ref array_id) => get_array ( context, array_id) ?,
28+
29+ Range :: Counted ( ref start_arg, ref stop_arg) => {
30+ let start = int_argument ( start_arg, context, "start" ) ?;
31+ let stop = int_argument ( stop_arg, context, "end" ) ?;
32+ ( start..stop) . map ( |x| Value :: scalar ( x as i32 ) ) . collect ( )
33+ }
34+ } ;
35+
36+ Ok ( range)
37+ }
38+ }
39+
40+ impl fmt:: Display for Range {
41+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
42+ match * self {
43+ Range :: Array ( ref arr) => write ! ( f, "{}" , arr) ,
44+ Range :: Counted ( ref start, ref end) => write ! ( f, "({}..{})" , start, end) ,
45+ }
46+ }
47+ }
48+
2349#[ derive( Debug ) ]
2450struct For {
2551 var_name : String ,
@@ -31,6 +57,16 @@ struct For {
3157 reversed : bool ,
3258}
3359
60+ impl For {
61+ fn trace ( & self ) -> String {
62+ trace_for_tag ( & self . var_name ,
63+ & self . range ,
64+ self . limit ,
65+ self . offset ,
66+ self . reversed )
67+ }
68+ }
69+
3470fn get_array ( context : & Context , array_id : & Argument ) -> Result < Vec < Value > > {
3571 let array = array_id. evaluate ( context) ?;
3672 match array {
@@ -39,49 +75,50 @@ fn get_array(context: &Context, array_id: &Argument) -> Result<Vec<Value>> {
3975 }
4076}
4177
42- fn int_argument ( arg : & Argument , context : & Context ) -> Result < isize > {
78+ fn int_argument ( arg : & Argument , context : & Context , arg_name : & str ) -> Result < isize > {
4379 let value = arg. evaluate ( context) ?;
4480
45- let value =
46- value
47- . as_scalar ( )
48- . and_then ( Scalar :: to_integer )
49- . ok_or_else ( || unexpected_value_error ( "whole number" , Some ( value. type_name ( ) ) ) ) ?;
81+ let value = value
82+ . as_scalar ( )
83+ . and_then ( Scalar :: to_integer )
84+ . ok_or_else ( || unexpected_value_error ( "whole number" , Some ( value . type_name ( ) ) ) )
85+ . context_with ( || ( arg_name . to_string ( ) . into ( ) , value. to_string ( ) ) ) ?;
5086
5187 Ok ( value as isize )
5288}
5389
54- impl Renderable for For {
55- fn render ( & self , context : & mut Context ) -> Result < Option < String > > {
56- let mut range = match self . range {
57- Range :: Array ( ref array_id) => get_array ( context, array_id) ?,
90+ fn for_slice ( range : & mut [ Value ] , limit : Option < usize > , offset : usize , reversed : bool ) -> & [ Value ] {
91+ let end = match limit {
92+ Some ( n) => offset + n,
93+ None => range. len ( ) ,
94+ } ;
5895
59- Range :: Counted ( ref start_arg, ref stop_arg) => {
60- let start = int_argument ( start_arg, context) ?;
61- let stop = int_argument ( stop_arg, context) ?;
62- ( start..stop) . map ( |x| Value :: scalar ( x as i32 ) ) . collect ( )
63- }
64- } ;
96+ let slice = if end > range. len ( ) {
97+ & mut range[ offset..]
98+ } else {
99+ & mut range[ offset..end]
100+ } ;
65101
66- let end = match self . limit {
67- Some ( n) => self . offset + n,
68- None => range. len ( ) ,
69- } ;
102+ if reversed {
103+ slice. reverse ( ) ;
104+ } ;
70105
71- let slice = if end > range. len ( ) {
72- & mut range[ self . offset ..]
73- } else {
74- & mut range[ self . offset ..end]
75- } ;
106+ slice
107+ }
76108
77- if self . reversed {
78- slice. reverse ( ) ;
79- } ;
109+ impl Renderable for For {
110+ fn render ( & self , context : & mut Context ) -> Result < Option < String > > {
111+ let mut range = self . range
112+ . evaluate ( context)
113+ . trace_with ( || self . trace ( ) . into ( ) ) ?;
114+ let range = for_slice ( & mut range, self . limit , self . offset , self . reversed ) ;
80115
81- match slice . len ( ) {
116+ match range . len ( ) {
82117 0 => {
83118 if let Some ( ref t) = self . else_template {
84119 t. render ( context)
120+ . trace_with ( || "{{% else %}}" . to_owned ( ) . into ( ) )
121+ . trace_with ( || self . trace ( ) . into ( ) )
85122 } else {
86123 Ok ( None )
87124 }
@@ -93,7 +130,7 @@ impl Renderable for For {
93130 let mut helper_vars = Object :: new ( ) ;
94131 helper_vars. insert ( "length" . to_owned ( ) , Value :: scalar ( range_len as i32 ) ) ;
95132
96- for ( i, v) in slice . iter ( ) . enumerate ( ) {
133+ for ( i, v) in range . iter ( ) . enumerate ( ) {
97134 helper_vars. insert ( "index0" . to_owned ( ) , Value :: scalar ( i as i32 ) ) ;
98135 helper_vars. insert ( "index" . to_owned ( ) , Value :: scalar ( ( i + 1 ) as i32 ) ) ;
99136 helper_vars. insert ( "rindex0" . to_owned ( ) ,
@@ -105,7 +142,11 @@ impl Renderable for For {
105142
106143 scope. set_val ( "forloop" , Value :: Object ( helper_vars. clone ( ) ) ) ;
107144 scope. set_val ( & self . var_name , v. clone ( ) ) ;
108- let inner = try!( self . item_template . render ( & mut scope) )
145+ let inner = self . item_template
146+ . render ( & mut scope)
147+ . trace_with ( || self . trace ( ) . into ( ) )
148+ . context_with ( || ( self . var_name . clone ( ) . into ( ) , v. to_string ( ) ) )
149+ . context ( "index" , & ( i + 1 ) ) ?
109150 . unwrap_or_else ( String :: new) ;
110151 ret = ret + & inner;
111152
@@ -159,10 +200,6 @@ fn trace_for_tag(var_name: &str,
159200 if reversed {
160201 parameters. push ( "reversed" . to_owned ( ) ) ;
161202 }
162- let range = match * range {
163- Range :: Array ( ref arr) => arr. to_string ( ) ,
164- Range :: Counted ( ref start, ref end) => format ! ( "({}..{})" , start, end) ,
165- } ;
166203 format ! ( "{{% for {} in {} {} %}}" ,
167204 var_name,
168205 range,
0 commit comments