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.
This commit is contained in:
parent
6423548818
commit
f31767df66
@ -24,8 +24,10 @@ enum States {
|
||||
CharConstant,
|
||||
CharClose,
|
||||
IntConstant,
|
||||
IfCond,
|
||||
IfBody
|
||||
SeekIfElse(int),
|
||||
SeekIfElsePercent(int),
|
||||
SeekIfEnd(int),
|
||||
SeekIfEndPercent(int)
|
||||
}
|
||||
|
||||
/// Types of parameters a capability can use
|
||||
@ -126,44 +128,68 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
|
||||
} else { return Err(~"stack is empty") },
|
||||
'+' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x + y)),
|
||||
(_, _) => return Err(~"non-numbers on stack with +")
|
||||
(Number(y), Number(x)) => stack.push(Number(x + y)),
|
||||
_ => return Err(~"non-numbers on stack with +")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'-' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x - y)),
|
||||
(_, _) => return Err(~"non-numbers on stack with -")
|
||||
(Number(y), Number(x)) => stack.push(Number(x - y)),
|
||||
_ => return Err(~"non-numbers on stack with -")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'*' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x * y)),
|
||||
(_, _) => return Err(~"non-numbers on stack with *")
|
||||
(Number(y), Number(x)) => stack.push(Number(x * y)),
|
||||
_ => return Err(~"non-numbers on stack with *")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'/' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x / y)),
|
||||
(_, _) => return Err(~"non-numbers on stack with /")
|
||||
(Number(y), Number(x)) => stack.push(Number(x / y)),
|
||||
_ => return Err(~"non-numbers on stack with /")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'm' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x % y)),
|
||||
(_, _) => return Err(~"non-numbers on stack with %")
|
||||
(Number(y), Number(x)) => stack.push(Number(x % y)),
|
||||
_ => return Err(~"non-numbers on stack with %")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'&' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x & y)),
|
||||
(_, _) => return Err(~"non-numbers on stack with &")
|
||||
(Number(y), Number(x)) => stack.push(Number(x & y)),
|
||||
_ => return Err(~"non-numbers on stack with &")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'|' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x | y)),
|
||||
(_, _) => return Err(~"non-numbers on stack with |")
|
||||
(Number(y), Number(x)) => stack.push(Number(x | y)),
|
||||
_ => return Err(~"non-numbers on stack with |")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'^' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(y), Number(x)) => stack.push(Number(x ^ y)),
|
||||
_ => return Err(~"non-numbers on stack with ^")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'=' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(y), Number(x)) => stack.push(Number(if x == y { 1 } else { 0 })),
|
||||
_ => return Err(~"non-numbers on stack with =")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'>' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(y), Number(x)) => stack.push(Number(if x > y { 1 } else { 0 })),
|
||||
_ => return Err(~"non-numbers on stack with >")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'<' => if stack.len() > 1 {
|
||||
match (stack.pop(), stack.pop()) {
|
||||
(Number(y), Number(x)) => stack.push(Number(if x < y { 1 } else { 0 })),
|
||||
_ => return Err(~"non-numbers on stack with <")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'A' => if stack.len() > 1 {
|
||||
@ -201,7 +227,19 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
|
||||
},
|
||||
(_, _) => return Err(~"first two params not numbers with %i")
|
||||
},
|
||||
'?' => state = return Err(fmt!("if expressions unimplemented (%?)", cap)),
|
||||
|
||||
// conditionals
|
||||
'?' => (),
|
||||
't' => if stack.len() > 0 {
|
||||
match stack.pop() {
|
||||
Number(0) => state = SeekIfElse(0),
|
||||
Number(_) => (),
|
||||
_ => return Err(~"non-number on stack with conditional")
|
||||
}
|
||||
} else { return Err(~"stack is empty") },
|
||||
'e' => state = SeekIfEnd(0),
|
||||
';' => (),
|
||||
|
||||
_ => return Err(fmt!("unrecognized format option %c", cur))
|
||||
}
|
||||
},
|
||||
@ -260,7 +298,46 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
|
||||
old_state = Nothing;
|
||||
}
|
||||
}
|
||||
_ => return Err(~"unimplemented state")
|
||||
SeekIfElse(level) => {
|
||||
if cur == '%' {
|
||||
state = SeekIfElsePercent(level);
|
||||
}
|
||||
old_state = Nothing;
|
||||
}
|
||||
SeekIfElsePercent(level) => {
|
||||
if cur == ';' {
|
||||
if level == 0 {
|
||||
state = Nothing;
|
||||
} else {
|
||||
state = SeekIfElse(level-1);
|
||||
}
|
||||
} else if cur == 'e' && level == 0 {
|
||||
state = Nothing;
|
||||
} else if cur == '?' {
|
||||
state = SeekIfElse(level+1);
|
||||
} else {
|
||||
state = SeekIfElse(level);
|
||||
}
|
||||
}
|
||||
SeekIfEnd(level) => {
|
||||
if cur == '%' {
|
||||
state = SeekIfEndPercent(level);
|
||||
}
|
||||
old_state = Nothing;
|
||||
}
|
||||
SeekIfEndPercent(level) => {
|
||||
if cur == ';' {
|
||||
if level == 0 {
|
||||
state = Nothing;
|
||||
} else {
|
||||
state = SeekIfEnd(level-1);
|
||||
}
|
||||
} else if cur == '?' {
|
||||
state = SeekIfEnd(level+1);
|
||||
} else {
|
||||
state = SeekIfEnd(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
if state == old_state {
|
||||
state = Nothing;
|
||||
@ -316,4 +393,38 @@ mod test {
|
||||
fn test_push_bad_param() {
|
||||
assert!(expand(bytes!("%pa"), [], &mut Variables::new()).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_comparison_ops() {
|
||||
let v = [('<', [1u8, 0u8, 0u8]), ('=', [0u8, 1u8, 0u8]), ('>', [0u8, 0u8, 1u8])];
|
||||
for v.iter().advance |&(op, bs)| {
|
||||
let s = fmt!("%%{1}%%{2}%%%c%%d", op);
|
||||
let res = expand(s.as_bytes(), [], &mut Variables::new());
|
||||
assert!(res.is_ok(), res.unwrap_err());
|
||||
assert_eq!(res.unwrap(), ~['0' as u8 + bs[0]]);
|
||||
let s = fmt!("%%{1}%%{1}%%%c%%d", op);
|
||||
let res = expand(s.as_bytes(), [], &mut Variables::new());
|
||||
assert!(res.is_ok(), res.unwrap_err());
|
||||
assert_eq!(res.unwrap(), ~['0' as u8 + bs[1]]);
|
||||
let s = fmt!("%%{2}%%{1}%%%c%%d", op);
|
||||
let res = expand(s.as_bytes(), [], &mut Variables::new());
|
||||
assert!(res.is_ok(), res.unwrap_err());
|
||||
assert_eq!(res.unwrap(), ~['0' as u8 + bs[2]]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conditionals() {
|
||||
let mut vars = Variables::new();
|
||||
let s = bytes!("\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m");
|
||||
let res = expand(s, [Number(1)], &mut vars);
|
||||
assert!(res.is_ok(), res.unwrap_err());
|
||||
assert_eq!(res.unwrap(), bytes!("\\E[31m").to_owned());
|
||||
let res = expand(s, [Number(8)], &mut vars);
|
||||
assert!(res.is_ok(), res.unwrap_err());
|
||||
assert_eq!(res.unwrap(), bytes!("\\E[90m").to_owned());
|
||||
let res = expand(s, [Number(42)], &mut vars);
|
||||
assert!(res.is_ok(), res.unwrap_err());
|
||||
assert_eq!(res.unwrap(), bytes!("\\E[38;5;42m").to_owned());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user