Files
matcha/src/interpret.rs
T
2026-07-08 05:22:42 -05:00

141 lines
3.7 KiB
Rust

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<TeaValue, InterpreterError> {
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<String, VarType>;
fn interpret_block(ast: Vec<ASTNode>, scopes: &mut Vec<Scope>) -> Result<Vec<Value>, 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<ASTNode>) -> Result<Vec<Value>, InterpreterError> {
let mut scopes = vec![HashMap::new()];
interpret_block(ast, &mut scopes)
}