use crate::lex::{ TeaValue, Operator }; use crate::parse::{ ASTNode, Value }; use std::collections::HashMap; #[derive(Debug)] enum VarType { Const(TeaValue), //Mut, } #[derive(Debug)] pub struct InterpreterError { description: String, } impl InterpreterError { pub fn new(e: &str) -> Self { Self { description: e.to_owned(), } } } macro_rules! some_or_error { ($matchee:expr, $ret:expr) => { match $matchee { Some(s) => s, _ => return Err($ret), } } } fn get_value(v: Value, scopes: &mut [Scope]) -> Result { match v { Value::Lit(t) => Ok(t), Value::Id(s) => { match scopes.iter().rev().skip_while(|scope| !scope.contains_key(&s)).next() { None => Err(InterpreterError::new("undefined variable")), Some(scope) => match scope.get(&s).unwrap() { VarType::Const(t) => Ok(t.clone()), }, } }, } } macro_rules! apply_op { ($a:ident, $b:ident, $op:tt) => { match ($a, $b) { (TeaValue::Float(aa), TeaValue::Float(bb)) => { TeaValue::Float(aa $op bb) }, (TeaValue::Int(aa), TeaValue::Int(bb)) => { TeaValue::Int(aa $op bb) }, //(TeaValue::Uint(aa), TeaValue::Uint(bb)) => { // TeaValue::Uint(aa $op bb) //}, _ => panic!("Invalid types"), } } } type Scope = HashMap; fn interpret_block(ast: Vec, scopes: &mut Vec) -> Result, InterpreterError> { let mut ast = ast.clone(); ast.reverse(); let mut stack = vec![]; //let mut scope = Scope::new(); loop { match ast.pop() { None => return Ok(stack), Some(ASTNode::Block(tokens)) => { scopes.push(HashMap::new()); let mut result = interpret_block(tokens, scopes)?; scopes.pop(); stack.append(&mut result); }, Some(ASTNode::Val(v)) => stack.push(v), Some(ASTNode::BinOp(op)) => { let b = some_or_error!(stack.pop(), InterpreterError::new("right value needed")); let a = some_or_error!(stack.pop(), InterpreterError::new("left value needed")); let b: TeaValue = get_value(b, scopes)?; let a: TeaValue = get_value(a, scopes)?; stack.push(Value::Lit(match op { Operator::Plus => { apply_op!(a, b, +) }, Operator::Minus => { apply_op!(a, b, -) }, Operator::Star => { apply_op!(a, b, *) }, Operator::Slash => { apply_op!(a, b, /) }, })); }, Some(ASTNode::UnaryMinus) => { let x = some_or_error!(stack.pop(), InterpreterError::new("value needed")); let x: TeaValue = get_value(x, scopes)?; stack.push(Value::Lit(match x { TeaValue::Float(f) => TeaValue::Float(-f), TeaValue::Int(i) => TeaValue::Int(-i), TeaValue::Uint(u) => TeaValue::Int(-(u as i32)), TeaValue::String(_) => return Err(InterpreterError::new("cannot invert string")), })); }, Some(ASTNode::ConstDecl) => { let rhs = some_or_error!(stack.pop(), InterpreterError::new("rhs value needed")); let lhs = some_or_error!(stack.pop(), InterpreterError::new("lhs value needed")); let rhs: TeaValue = get_value(rhs, scopes)?; //let current_scope = .unwrap(); match lhs { Value::Lit(_) => return Err(InterpreterError::new("invalid left hand side")), Value::Id(s) => { if scopes.last().unwrap().contains_key(&s) { return Err(InterpreterError::new("already defined constant")); } else { scopes.last_mut().unwrap().insert(s, VarType::Const(rhs)); } } } }, Some(ASTNode::StatementEnd) => { if !stack.is_empty() { return Err(InterpreterError::new("stack not empty")); } } } } } pub fn interpret(ast: Vec) -> Result, InterpreterError> { let mut scopes = vec![HashMap::new()]; interpret_block(ast, &mut scopes) }