We have SSA
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
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, scope: &HashMap<String, VarType>) -> Result<TeaValue, InterpreterError> {
|
||||
match v {
|
||||
Value::Lit(t) => Ok(t),
|
||||
Value::Id(s) => match scope.get(&s) {
|
||||
None => Err(InterpreterError::new("undefined variable")),
|
||||
Some(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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn interpret(ast: Vec<ASTNode>) -> Result<Vec<Value>, InterpreterError> {
|
||||
let mut ast = ast.clone();
|
||||
ast.reverse();
|
||||
let mut stack = vec![];
|
||||
let mut global_scope: HashMap<String, VarType> = HashMap::new();
|
||||
loop {
|
||||
match ast.pop() {
|
||||
None => return Ok(stack),
|
||||
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, &global_scope)?;
|
||||
let a: TeaValue = get_value(a, &global_scope)?;
|
||||
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, &global_scope)?;
|
||||
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, &global_scope)?;
|
||||
match lhs {
|
||||
Value::Lit(_) => return Err(InterpreterError::new("invalid left hand side")),
|
||||
Value::Id(s) => {
|
||||
if global_scope.contains_key(&s) {
|
||||
return Err(InterpreterError::new("already defined constant"));
|
||||
} else {
|
||||
global_scope.insert(s, VarType::Const(rhs));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(ASTNode::StatementEnd) => {
|
||||
if !stack.is_empty() {
|
||||
return Err(InterpreterError::new("stack not empty"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user