Skip to content

Commit f31767d

Browse files
committed
Implement terminfo param conditionals
Implement the %?, %t, %e, and %; operators. Also implement the %<, %=, %> operators, without which conditionals aren't very useful. Fix the order of parameters for the arithmetic operators. Implement the missing %^ operator.
1 parent 6423548 commit f31767d

File tree

1 file changed

+129
-18
lines changed

1 file changed

+129
-18
lines changed

src/libextra/terminfo/parm.rs

Lines changed: 129 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)