#[derive(Debug, Copy, Clone)]
pub enum Error {
StackUnderflow,
TypeMismatch,
InvalidInstruction,
}
pub trait AtomExtender {
fn atom(&mut self, u8, &mut Stack) -> Result<(),Error>;
}
pub struct NullExtender {}
impl AtomExtender for NullExtender {
fn atom(&mut self, _: u8, _: &mut Stack) -> Result<(),Error> {
Err(Error::InvalidInstruction)
}
}
impl Error {
pub fn to_string(&self) -> &'static str {
match self {
&Error::StackUnderflow => {return "Stack Underflow";},
&Error::TypeMismatch => {return "Type Mismatch";},
&Error::InvalidInstruction => {return "Invalid Instruction";},
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum Data {
Int(i64),
Float(f64),
}
#[derive(Debug, Copy, Clone)]
pub enum Pair {
Int(i64,i64),
Float(f64,f64),
}
pub struct Stack {
stack: Vec<Data>,
}
impl Stack {
pub fn new() -> Stack {
Stack {
stack: Vec::new()
}
}
pub fn len(&self) -> usize {self.stack.len()}
pub fn push(&mut self, value: Data) {
self.stack.push(value);
}
pub fn pop(&mut self) -> Result<Data,Error> {
match self.stack.pop() {
Some(n) => Ok(n),
None => Err(Error::StackUnderflow),
}
}
pub fn pop_two(&mut self) -> Result<Pair,Error> {
let a = self.stack.pop();
let b = self.stack.pop();
if let None = a {return Err(Error::StackUnderflow);}
if let None = b {return Err(Error::StackUnderflow);}
let a = a.unwrap();
let b = b.unwrap();
match (a,b) {
(Data::Float(x),Data::Float(y)) => Ok(Pair::Float(x,y)),
(Data::Int(x),Data::Int(y)) => Ok(Pair::Int(x,y)),
(Data::Float(_),Data::Int(_)) => Err(Error::TypeMismatch),
(Data::Int(_),Data::Float(_)) => Err(Error::TypeMismatch),
}
}
pub fn cast_to_int(&mut self) -> Result<(),Error> {
let value = self.pop();
let value = match value {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
match value {
Data::Int(_) => {self.push(value);},
Data::Float(n) => {self.push(Data::Int(n as i64));}
}
return Ok(());
}
pub fn cast_to_float(&mut self) -> Result<(),Error> {
let value = self.pop();
let value = match value {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
match value {
Data::Int(n) => {self.push(Data::Float(n as f64));},
Data::Float(_) => {self.push(value);}
}
return Ok(());
}
pub fn dup(&mut self) -> Result<(),Error> {
let value = self.pop();
let value = match value {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
self.push(value);
self.push(value);
Ok(())
}
pub fn swap(&mut self) -> Result<(), Error> {
let x = self.pop();
let y = self.pop();
let x = match x {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
let y = match y {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
self.push(x);
self.push(y);
Ok(())
}
pub fn over(&mut self) -> Result<(), Error> {
let x = self.pop();
let y = self.pop();
let x = match x {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
let y = match y {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
self.push(y);
self.push(x);
self.push(y);
Ok(())
}
pub fn add(&mut self) -> Result<(),Error> {
let values = self.pop_two();
let values = match values {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
match values {
Pair::Int(x,y) => {self.push(Data::Int(x+y));}
Pair::Float(x,y) => { self.push(Data::Float(x+y));}
}
Ok(())
}
pub fn sub(&mut self) -> Result<(),Error> {
let values = self.pop_two();
let values = match values {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
match values {
Pair::Int(x,y) => {self.push(Data::Int(y-x));}
Pair::Float(x,y) => { self.push(Data::Float(y-x));}
}
Ok(())
}
pub fn mul(&mut self) -> Result<(),Error> {
let values = self.pop_two();
let values = match values {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
match values {
Pair::Int(x,y) => {self.push(Data::Int(y*x));}
Pair::Float(x,y) => { self.push(Data::Float(y*x));}
}
Ok(())
}
pub fn div(&mut self) -> Result<(),Error> {
let values = self.pop_two();
let values = match values {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
match values {
Pair::Int(x,y) => {self.push(Data::Int(y/x));}
Pair::Float(x,y) => { self.push(Data::Float(y/x));}
}
Ok(())
}
pub fn modulus(&mut self) -> Result<(),Error> {
let values = self.pop_two();
let values = match values {
Err(n) => { return Err(n);},
Ok(n) => { n }
};
match values {
Pair::Int(x,y) => {self.push(Data::Int(y%x));}
Pair::Float(x,y) => { self.push(Data::Float(y%x));}
}
Ok(())
}
}
pub fn run<T: AtomExtender>(
code: &Vec<u8>,
stack: &mut Stack,
mut pc: usize,
mut extender: T,
memory: &mut Vec<Data>
) -> Result<(),(usize,Error)> {
let mut rstack: Vec<usize> = Vec::new();
let mut value: i64 = 0;
let mut divider: f64 = 1.0;
while pc < code.len() {
let instruction = code[pc];
pc += 1;
match instruction {
10 => {},
13 => {}, 32 => {}, 34 => { let v = value as f64;
stack.push(Data::Float(v / divider));
},
35 => { value = 0;
divider = 1.0;
},
36 => { value = -value;
},
37 => { if let Err(n) = stack.modulus() { return Err((pc, n)); }
}
39 => { stack.push(Data::Int(value));
},
42 => { if let Err(n) = stack.mul() { return Err((pc, n)); }
},
43 => { if let Err(n) = stack.add() { return Err((pc, n)); }
},
45 => { if let Err(n) = stack.sub() { return Err((pc, n)); }
},
46 => { divider *= 1000.0;
},
47 => { if let Err(n) = stack.div() { return Err((pc, n)); }
},
48...57 => { value *= 10;
value += (instruction as i64) - 48;
},
59 => { let home = match rstack.pop() {
Some(n) => n,
None => { return Ok(()) }
};
pc = home;
},
82 => { let value = stack.pop();
let value = match value {
Err(n) => { return Err((pc,n));},
Ok(n) => { n }
};
match value {
Data::Float(_) => { return Err((pc, Error::TypeMismatch)); }
Data::Int(n) => {
let val = memory[(n as usize) % memory.len()];
stack.push(val);
}
}
},
87 => {
let address = stack.pop();
let value = stack.pop();
let address = match address {
Err(n) => { return Err((pc,n));},
Ok(n) => { n }
};
let value = match value {
Err(n) => { return Err((pc,n));},
Ok(n) => { n }
};
match address {
Data::Float(_) => { return Err((pc, Error::TypeMismatch)); }
Data::Int(n) => {
let addr = (n as usize) % memory.len();
memory[addr] = value;
}
}
},
98 => { let value = stack.pop();
let value = match value {
Err(n) => { return Err((pc,n));},
Ok(n) => { n }
};
match value {
Data::Float(_) => { return Err((pc, Error::TypeMismatch)); }
Data::Int(n) => {
pc = n as usize;
}
}
},
99 => { let value = stack.pop();
let value = match value {
Err(n) => { return Err((pc,n));},
Ok(n) => { n }
};
match value {
Data::Float(_) => { return Err((pc, Error::TypeMismatch)); }
Data::Int(n) => {
rstack.push(pc);
pc = n as usize;
}
}
},
100 => { if let Err(n) = stack.dup() { return Err((pc, n)); }
},
112 => {
let value = stack.pop();
let value = match value {
Err(n) => { return Err((pc,n));},
Ok(n) => { n }
};
match value {
Data::Int(n) => println!("Int:{}",n),
Data::Float(n) => println!("Float:{}",n)
}
},
114 => { if let Err(n) = stack.pop() { return Err((pc, n)); }
},
115 => { if let Err(n) = stack.swap() { return Err((pc, n)); }
}
118 => { if let Err(n) = stack.over() { return Err((pc, n)); }
}
121 => { let address = stack.pop();
let address = match address { Err(n) => {return Err((pc,n));}, Ok(n) => {n} };
let data = stack.pop();
let data = match data { Err(n) => {return Err((pc,n));}, Ok(n) => {n} };
let address = match address { Data::Float(_) => {return Err((pc, Error::TypeMismatch));}, Data::Int(n) => n as usize };
let condition = match data {
Data::Float(n) => if n != 0.0 {true} else {false},
Data::Int(n) => if n != 0 {true} else {false}
};
if condition { pc = address; }
},
122 => { let address = stack.pop();
let address = match address { Err(n) => {return Err((pc,n));}, Ok(n) => {n} };
let data = stack.pop();
let data = match data { Err(n) => {return Err((pc,n));}, Ok(n) => {n} };
let address = match address { Data::Float(_) => {return Err((pc, Error::TypeMismatch));}, Data::Int(n) => n as usize };
let condition = match data {
Data::Float(n) => if n == 0.0 {true} else {false},
Data::Int(n) => if n == 0 {true} else {false}
};
if condition { pc = address; }
},
_ => {
if let Err(n) = extender.atom(instruction, stack) { return Err((pc, n)); }
},
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use Stack;
use Error;
use Data;
#[test]
fn it_works() {
let mut s = Stack::new();
let v = s.pop();
assert!(if let Err(Error::StackUnderflow) = v {true} else {false});
s.push(Data::Int(5));
let five = s.pop();
match five {
Err(_) => panic!("Error"),
Ok(n) => match n {
Data::Int(v) => match v {
5 => {},
_ => panic!("No good"),
},
Data::Float(_) => panic!("Wrong type")
}
}
s.push(Data::Int(5));
s.push(Data::Float(2.0));
let pair = s.pop_two();
assert!(if let Err(Error::TypeMismatch) = pair {true} else {false});
assert!(if let Err(Error::StackUnderflow) = s.cast_to_int() {true} else {false});
s.push(Data::Int(2));
s.push(Data::Int(6));
assert!(if let Ok(()) = s.add() {true} else {false});
let eight = s.pop();
match eight {
Err(_) => panic!("Error"),
Ok(n) => match n {
Data::Int(v) => match v {
8 => {},
_ => panic!("No good"),
},
Data::Float(_) => panic!("Wrong type")
}
}
}
}