@@ -24,8 +24,10 @@ enum States {
2424 CharConstant ,
2525 CharClose ,
2626 IntConstant ,
27- IfCond ,
28- IfBody
27+ SeekIfElse ( int ) ,
28+ SeekIfElsePercent ( int ) ,
29+ SeekIfEnd ( int ) ,
30+ SeekIfEndPercent ( int )
2931}
3032
3133/// Types of parameters a capability can use
@@ -126,44 +128,68 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
126128 } else { return Err ( ~"stack is empty") } ,
127129 '+' => if stack. len( ) > 1 {
128130 match ( stack. pop( ) , stack. pop( ) ) {
129- ( Number ( x ) , Number ( y ) ) => stack. push( Number ( x + y) ) ,
130- ( _ , _ ) => return Err ( ~"non-numbers on stack with +")
131+ ( Number ( y ) , Number ( x ) ) => stack. push( Number ( x + y) ) ,
132+ _ => return Err ( ~"non-numbers on stack with +")
131133 }
132134 } else { return Err ( ~"stack is empty") } ,
133135 '-' => if stack. len( ) > 1 {
134136 match ( stack. pop( ) , stack. pop( ) ) {
135- ( Number ( x ) , Number ( y ) ) => stack. push( Number ( x - y) ) ,
136- ( _ , _ ) => return Err ( ~"non-numbers on stack with -")
137+ ( Number ( y ) , Number ( x ) ) => stack. push( Number ( x - y) ) ,
138+ _ => return Err ( ~"non-numbers on stack with -")
137139 }
138140 } else { return Err(~" stack is empty") } ,
139141 '*' => if stack. len( ) > 1 {
140142 match ( stack. pop( ) , stack. pop( ) ) {
141- ( Number ( x ) , Number ( y ) ) => stack. push( Number ( x * y) ) ,
142- ( _ , _ ) => return Err ( ~"non-numbers on stack with * ")
143+ ( Number ( y ) , Number ( x ) ) => stack. push( Number ( x * y) ) ,
144+ _ => return Err ( ~"non-numbers on stack with * ")
143145 }
144146 } else { return Err(~" stack is empty") } ,
145147 '/' => if stack. len ( ) > 1 {
146148 match ( stack. pop ( ) , stack. pop ( ) ) {
147- ( Number ( x ) , Number ( y ) ) => stack. push ( Number ( x / y) ) ,
148- ( _ , _ ) => return Err ( ~"non-numbers on stack with /")
149+ ( Number ( y ) , Number ( x ) ) => stack. push ( Number ( x / y) ) ,
150+ _ => return Err ( ~"non-numbers on stack with /")
149151 }
150152 } else { return Err(~" stack is empty") } ,
151153 'm' => if stack. len ( ) > 1 {
152154 match ( stack. pop ( ) , stack. pop ( ) ) {
153- ( Number ( x ) , Number ( y ) ) => stack. push ( Number ( x % y) ) ,
154- ( _ , _ ) => return Err ( ~"non-numbers on stack with %")
155+ ( Number ( y ) , Number ( x ) ) => stack. push ( Number ( x % y) ) ,
156+ _ => return Err ( ~"non-numbers on stack with %")
155157 }
156158 } else { return Err(~" stack is empty") } ,
157159 '&' => if stack. len ( ) > 1 {
158160 match ( stack. pop ( ) , stack. pop ( ) ) {
159- ( Number ( x ) , Number ( y ) ) => stack. push ( Number ( x & y) ) ,
160- ( _ , _ ) => return Err ( ~"non-numbers on stack with & ")
161+ ( Number ( y ) , Number ( x ) ) => stack. push ( Number ( x & y) ) ,
162+ _ => return Err ( ~"non-numbers on stack with & ")
161163 }
162164 } else { return Err(~" stack is empty") } ,
163165 '|' => if stack. len ( ) > 1 {
164166 match ( stack. pop ( ) , stack. pop ( ) ) {
165- ( Number ( x) , Number ( y) ) => stack. push ( Number ( x | y) ) ,
166- ( _, _) => return Err ( ~"non-numbers on stack with |")
167+ ( Number ( y) , Number ( x) ) => stack. push ( Number ( x | y) ) ,
168+ _ => return Err ( ~"non-numbers on stack with |")
169+ }
170+ } else { return Err(~" stack is empty") } ,
171+ '^' => if stack. len ( ) > 1 {
172+ match ( stack. pop ( ) , stack. pop ( ) ) {
173+ ( Number ( y) , Number ( x) ) => stack. push ( Number ( x ^ y) ) ,
174+ _ => return Err ( ~"non-numbers on stack with ^")
175+ }
176+ } else { return Err(~" stack is empty") } ,
177+ '=' => if stack. len ( ) > 1 {
178+ match ( stack. pop ( ) , stack. pop ( ) ) {
179+ ( Number ( y) , Number ( x) ) => stack. push ( Number ( if x == y { 1 } else { 0 } ) ) ,
180+ _ => return Err ( ~"non-numbers on stack with =")
181+ }
182+ } else { return Err(~" stack is empty") } ,
183+ '>' => if stack. len ( ) > 1 {
184+ match ( stack. pop ( ) , stack. pop ( ) ) {
185+ ( Number ( y) , Number ( x) ) => stack. push ( Number ( if x > y { 1 } else { 0 } ) ) ,
186+ _ => return Err ( ~"non-numbers on stack with >")
187+ }
188+ } else { return Err(~" stack is empty") } ,
189+ '<' => if stack. len ( ) > 1 {
190+ match ( stack. pop ( ) , stack. pop ( ) ) {
191+ ( Number ( y) , Number ( x) ) => stack. push ( Number ( if x < y { 1 } else { 0 } ) ) ,
192+ _ => return Err ( ~"non-numbers on stack with <")
167193 }
168194 } else { return Err(~" stack is empty") } ,
169195 'A' => if stack. len ( ) > 1 {
@@ -201,7 +227,19 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
201227 } ,
202228 ( _, _) => return Err ( ~"first two params not numbers with %i")
203229 } ,
204- '?' => state = return Err ( fmt ! ( "if expressions unimplemented (%?)" , cap) ) ,
230+
231+ // conditionals
232+ '?' => ( ) ,
233+ 't' => if stack. len ( ) > 0 {
234+ match stack. pop ( ) {
235+ Number ( 0 ) => state = SeekIfElse ( 0 ) ,
236+ Number ( _) => ( ) ,
237+ _ => return Err ( ~"non-number on stack with conditional")
238+ }
239+ } else { return Err ( ~"stack is empty") } ,
240+ 'e' => state = SeekIfEnd ( 0 ) ,
241+ ';' => ( ) ,
242+
205243 _ => return Err ( fmt!( "unrecognized format option %c", cur))
206244 }
207245 },
@@ -260,7 +298,46 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
260298 old_state = Nothing ;
261299 }
262300 }
263- _ => return Err ( ~"unimplemented state")
301+ SeekIfElse ( level) => {
302+ if cur == '%' {
303+ state = SeekIfElsePercent ( level) ;
304+ }
305+ old_state = Nothing ;
306+ }
307+ SeekIfElsePercent ( level) => {
308+ if cur == ';' {
309+ if level == 0 {
310+ state = Nothing ;
311+ } else {
312+ state = SeekIfElse ( level-1 ) ;
313+ }
314+ } else if cur == 'e' && level == 0 {
315+ state = Nothing ;
316+ } else if cur == '?' {
317+ state = SeekIfElse ( level+1 ) ;
318+ } else {
319+ state = SeekIfElse ( level) ;
320+ }
321+ }
322+ SeekIfEnd ( level) => {
323+ if cur == '%' {
324+ state = SeekIfEndPercent ( level) ;
325+ }
326+ old_state = Nothing ;
327+ }
328+ SeekIfEndPercent ( level) => {
329+ if cur == ';' {
330+ if level == 0 {
331+ state = Nothing ;
332+ } else {
333+ state = SeekIfEnd ( level-1 ) ;
334+ }
335+ } else if cur == '?' {
336+ state = SeekIfEnd ( level+1 ) ;
337+ } else {
338+ state = SeekIfEnd ( level) ;
339+ }
340+ }
264341 }
265342 if state == old_state {
266343 state = Nothing ;
@@ -316,4 +393,38 @@ mod test {
316393 fn test_push_bad_param( ) {
317394 assert ! ( expand( bytes!( "%pa" ) , [ ] , & mut Variables :: new( ) ) . is_err( ) ) ;
318395 }
396+
397+ #[ test]
398+ fn test_comparison_ops( ) {
399+ let v = [ ( '<' , [ 1u8 , 0u8 , 0u8 ] ) , ( '=' , [ 0u8 , 1u8 , 0u8 ] ) , ( '>' , [ 0u8 , 0u8 , 1u8 ] ) ] ;
400+ for v. iter( ) . advance |& ( op, bs) | {
401+ let s = fmt ! ( "%%{1}%%{2}%%%c%%d" , op) ;
402+ let res = expand( s. as_bytes( ) , [ ] , & mut Variables :: new( ) ) ;
403+ assert ! ( res. is_ok( ) , res. unwrap_err( ) ) ;
404+ assert_eq ! ( res. unwrap( ) , ~[ '0' as u8 + bs[ 0 ] ] ) ;
405+ let s = fmt ! ( "%%{1}%%{1}%%%c%%d" , op) ;
406+ let res = expand( s. as_bytes( ) , [ ] , & mut Variables :: new( ) ) ;
407+ assert ! ( res. is_ok( ) , res. unwrap_err( ) ) ;
408+ assert_eq ! ( res. unwrap( ) , ~[ '0' as u8 + bs[ 1 ] ] ) ;
409+ let s = fmt ! ( "%%{2}%%{1}%%%c%%d" , op) ;
410+ let res = expand( s. as_bytes( ) , [ ] , & mut Variables :: new( ) ) ;
411+ assert ! ( res. is_ok( ) , res. unwrap_err( ) ) ;
412+ assert_eq ! ( res. unwrap( ) , ~[ '0' as u8 + bs[ 2 ] ] ) ;
413+ }
414+ }
415+
416+ #[ test]
417+ fn test_conditionals ( ) {
418+ let mut vars = Variables : : new( ) ;
419+ let s = bytes ! ( "\\ E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m" ) ;
420+ let res = expand( s, [ Number ( 1 ) ] , & mut vars) ;
421+ assert ! ( res. is_ok( ) , res. unwrap_err( ) ) ;
422+ assert_eq ! ( res. unwrap( ) , bytes!( "\\ E[31m" ) . to_owned( ) ) ;
423+ let res = expand( s, [ Number ( 8 ) ] , & mut vars) ;
424+ assert ! ( res. is_ok( ) , res. unwrap_err( ) ) ;
425+ assert_eq ! ( res. unwrap( ) , bytes!( "\\ E[90m" ) . to_owned( ) ) ;
426+ let res = expand( s, [ Number ( 42 ) ] , & mut vars) ;
427+ assert ! ( res. is_ok( ) , res. unwrap_err( ) ) ;
428+ assert_eq ! ( res. unwrap( ) , bytes!( "\\ E[38;5;42m" ) . to_owned( ) ) ;
429+ }
319430}
0 commit comments