use std::collections::HashMap; pub type Value = i32; pub type Result = std::result::Result<(), Error>; type Stackop = fn(&mut Forth); pub struct Builtin { stack_min: usize, func: Stackop } pub struct Forth { v: Vec, f: HashMap, b: HashMap, s: Vec>, func: Vec, } #[derive(Debug, PartialEq)] pub enum Error { DivisionByZero, StackUnderflow, UnknownWord, InvalidWord, } impl Forth { pub fn op_drop(&mut self) { self.v.pop(); } pub fn op_dup(&mut self) { let temp = self.v[self.v.len() - 1]; self.v.push(temp); } pub fn op_over(&mut self) { let temp = self.v[self.v.len() - 2]; self.v.push(temp); } pub fn op_swap(&mut self) { let size = self.v.len(); let temp = self.v[size - 2]; self.v[size - 2] = self.v[size - 1]; self.v[size - 1] = temp; } pub fn new() -> Forth { let mut temp: Vec> = Vec::new(); temp.push(Vec::new()); let mut ftab: HashMap:: = HashMap::new(); ftab.insert("drop".to_string(), Builtin{stack_min:1,func:Self::op_drop}); ftab.insert("dup" .to_string(), Builtin{stack_min:1,func:Self::op_dup}); ftab.insert("over".to_string(), Builtin{stack_min:2,func:Self::op_over}); ftab.insert("swap".to_string(), Builtin{stack_min:2,func:Self::op_swap}); Forth{v: Vec::::new(), f: HashMap::new(), b:ftab, s: temp, func: Vec::new()} } pub fn stack(&self) -> &[Value] { &self.v } pub fn eval(&mut self, input: &str) -> Result { self.v.clear(); self.s[0].clear(); println!("\neval({})", input); // Parse the input text and store it in a vector { let temp: Vec<&str> = input.split(' ').collect(); let n = temp.len() as i32; for x in 0..n as usize { self.s[0].push(String::from(temp[x])); } } Self::exec(self, 0) } pub fn exec(&mut self, sx: usize) -> Result { let n: usize = self.s[sx].len(); let mut collecting = false; // User-defined functions store the function name at index 0, // so start with 1 unless it's the primary input line (sx == 0) let lo:usize = if sx == 0 {0} else {1}; for x in lo..n as usize { let word = &self.s[sx][x]; if word == ";" { if collecting { collecting = false; let index: usize = self.s.len(); // 1 for main + 1 for each function self.s.push(Vec::::new()); // Create vec for new user-def function for item in self.func.iter() { if self.s[index].len() > 0 && self.appropriate(&item,index) { let sx = *self.f.get(item).unwrap(); let n = self.s[sx].len(); for x in 1..n as usize { let symbol = self.s[sx][x].clone(); self.s[index].push(symbol); } } else { self.s[index].push(item.to_string()); } } self.f.insert(self.s[index][0].clone().to_lowercase(), index); self.func.clear(); continue; } continue; } if collecting { self.func.push(String::from(word)); continue; } if word == ":" { // There must be at least 3 more operands after a colon if self.s[sx].len() < x + 4 {return Err(Error::InvalidWord);} // In this implementation, numbers are not allowed to be function // names. match self.s[sx][x+1].parse::() { Ok(_) => { return Err(Error::InvalidWord); }, _ => () } // It's not a number, so we can proceed. collecting = true; self.func.clear(); continue; } // Integer values are just pushed onto the stack match word.parse::() { Ok(value) => { self.v.push(value); continue; }, _ => {} } // User-defined functions let lower = word.to_lowercase(); if self.f.contains_key(&lower) { let sx = *self.f.get(&lower).unwrap(); match Self::exec(self, sx) { Ok(_) => continue, Err(e) => return Err(e) }; } // Binary arithmetic operators if Self::is_op(word) { if self.v.len() < 2 { return Err(Error::StackUnderflow); } let b = self.v.pop().unwrap(); let a = self.v.pop().unwrap(); let c = match word.as_str() { "+" => a + b, "-" => a - b, "*" => a * b, "/" => {if b == 0 {return Err(Error::DivisionByZero);} a / b}, _ => 0 }; self.v.push(c); continue; } // Built-in functions let p = self.b.get(&lower); match p { Some(param) => { if self.v.len() < param.stack_min { return Err(Error::StackUnderflow); } (param.func)(self); continue; }, _ => { return Err(Error::UnknownWord); } } } // end loop Ok(()) } fn is_op(input: &str) -> bool { match input {"+"|"-"|"*"|"/" => true, _ => false} } fn appropriate(&self, item:&str, index:usize) -> bool { // Is it appropriate to emit the previous definition of a user-defined function? if self.s[index][0] == item { true // Yes because we are redefining a previously defined function } else { if index >= self.s.len() { false // Guard to be sure index is meaningful } else { if let Some(&sx) = self.f.get(item) { // Yes if the previous definition is a single term // and therefore will not increase storage requirements. // Length 2 means 1 for the function name and 1 for its definition. self.s[sx].len() == 2 } else { false } } } } } fn main() { let cmd = [ ": f over over + ;", "1 1 f f f f f f f f f f f" ]; let mut f = Forth::new(); for line in cmd { f.eval(line); println!("stack = {:?}", f.stack()); } }