1
0
Files
developing-compilers/src/interpreter/mod.rs
2024-11-13 12:32:09 +03:00

145 lines
4.5 KiB
Rust

mod value;
use std::collections::HashMap;
use anyhow::Context;
pub use value::Value;
use crate::ast::BinOp;
use crate::ast::typed::Type;
use crate::representation::intermediate::{IntermediateExpr, IntermediateValue};
use crate::symbols::{Symbol, SymbolsTable};
pub struct Interpreter<I> {
exprs: Vec<IntermediateExpr>,
symbols: SymbolsTable,
initializer: I,
}
type Variables = HashMap<Symbol, Value>;
impl<I> Interpreter<I>
where
I: Fn(&Type, &str) -> Value,
{
pub fn new(exprs: Vec<IntermediateExpr>, symbols: SymbolsTable, initializer: I) -> Self {
Self {
symbols,
exprs,
initializer,
}
}
pub fn run(&mut self) -> anyhow::Result<Option<Value>> {
let mut variables = self.initialize_variables()?;
let mut last_value = None;
for expr in &self.exprs {
let (result, value) = match expr {
IntermediateExpr::IntToFloat { result, value } => {
let value = Self::intermediate_value(&variables, value)?;
(result, self.int2float(value))
},
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} => {
let lhs = Self::intermediate_value(&variables, lhs)?;
let rhs = Self::intermediate_value(&variables, rhs)?;
(result, self.bin_op(lhs, op, rhs)?)
},
IntermediateExpr::Identity { result, value } => {
let value = Self::intermediate_value(&variables, value)?;
(result, self.identity(value))
},
};
Self::store(&mut variables, result, value)?;
last_value = Some(value);
}
Ok(last_value)
}
fn initialize_variables(&self) -> anyhow::Result<Variables> {
let mut variables = Variables::new();
for (_, data) in &self.symbols {
if data.ty.is_none() {
anyhow::bail!("type not found for '{}'", data.name);
}
if !data.temporary {
variables.insert(data.id, (self.initializer)(&data.ty.unwrap(), &data.name));
} else {
variables.insert(data.id, match data.ty {
None => continue,
Some(Type::Int) => Value::Int(0),
Some(Type::Float) => Value::Float(0.0),
});
};
}
Ok(variables)
}
fn int2float(&self, value: Value) -> Value {
match value {
Value::Int(v) => Value::Float(v as f64),
_ => value,
}
}
fn identity(&self, value: Value) -> Value {
value
}
fn bin_op(&self, lhs: Value, op: &BinOp, rhs: Value) -> anyhow::Result<Value> {
match (lhs, rhs) {
(Value::Int(lhs), Value::Int(rhs)) => Ok(Value::Int(match op {
BinOp::Add => lhs + rhs,
BinOp::Sub => lhs - rhs,
BinOp::Mul => lhs * rhs,
BinOp::Div => lhs / rhs,
})),
(Value::Float(lhs), Value::Float(rhs)) => Ok(Value::Float(match op {
BinOp::Add => lhs + rhs,
BinOp::Sub => lhs - rhs,
BinOp::Mul => lhs * rhs,
BinOp::Div => lhs / rhs,
})),
_ => Err(anyhow::anyhow!("invalid types for binary operation")),
}
}
fn intermediate_value(
variables: &Variables,
value: &IntermediateValue,
) -> anyhow::Result<Value> {
Ok(match value {
IntermediateValue::Int { value } => Value::Int(*value),
IntermediateValue::Float { value } => Value::Float(*value),
IntermediateValue::Var { name } => Self::load(variables, name)?,
})
}
fn load(variables: &Variables, symbol: &Symbol) -> anyhow::Result<Value> {
let symbol_value = variables.get(symbol).context("no such variable")?;
Ok(*symbol_value)
}
fn store(variables: &mut Variables, symbol: &Symbol, value: Value) -> anyhow::Result<()> {
let symbol_value = variables.get_mut(symbol).context("no such variable")?;
match (symbol_value, value) {
(Value::Int(v), Value::Int(a)) => *v = a,
(Value::Float(v), Value::Float(a)) => *v = a,
_ => return Err(anyhow::anyhow!("invalid types for assignment")),
};
Ok(())
}
}