@@ -24,8 +24,10 @@ enum States {
24
24
CharConstant ,
25
25
CharClose ,
26
26
IntConstant ,
27
- IfCond ,
28
- IfBody
27
+ SeekIfElse ( int ) ,
28
+ SeekIfElsePercent ( int ) ,
29
+ SeekIfEnd ( int ) ,
30
+ SeekIfEndPercent ( int )
29
31
}
30
32
31
33
/// Types of parameters a capability can use
@@ -126,44 +128,68 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
126
128
} else { return Err ( ~"stack is empty") } ,
127
129
'+' => if stack. len( ) > 1 {
128
130
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 +")
131
133
}
132
134
} else { return Err ( ~"stack is empty") } ,
133
135
'-' => if stack. len( ) > 1 {
134
136
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 -")
137
139
}
138
140
} else { return Err(~" stack is empty") } ,
139
141
'*' => if stack. len( ) > 1 {
140
142
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 * ")
143
145
}
144
146
} else { return Err(~" stack is empty") } ,
145
147
'/' => if stack. len ( ) > 1 {
146
148
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 /")
149
151
}
150
152
} else { return Err(~" stack is empty") } ,
151
153
'm' => if stack. len ( ) > 1 {
152
154
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 %")
155
157
}
156
158
} else { return Err(~" stack is empty") } ,
157
159
'&' => if stack. len ( ) > 1 {
158
160
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 & ")
161
163
}
162
164
} else { return Err(~" stack is empty") } ,
163
165
'|' => if stack. len ( ) > 1 {
164
166
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 <")
167
193
}
168
194
} else { return Err(~" stack is empty") } ,
169
195
'A' => if stack. len ( ) > 1 {
@@ -201,7 +227,19 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
201
227
} ,
202
228
( _, _) => return Err ( ~"first two params not numbers with %i")
203
229
} ,
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
+
205
243
_ => return Err ( fmt!( "unrecognized format option %c", cur))
206
244
}
207
245
},
@@ -260,7 +298,46 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
260
298
old_state = Nothing ;
261
299
}
262
300
}
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
+ }
264
341
}
265
342
if state == old_state {
266
343
state = Nothing ;
@@ -316,4 +393,38 @@ mod test {
316
393
fn test_push_bad_param( ) {
317
394
assert ! ( expand( bytes!( "%pa" ) , [ ] , & mut Variables :: new( ) ) . is_err( ) ) ;
318
395
}
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
+ }
319
430
}
0 commit comments