aboutsummaryrefslogtreecommitdiff
path: root/src/interpret
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-21 23:46:01 +0200
committerMel <einebeere@gmail.com>2021-10-21 23:46:01 +0200
commitcff714c07e5e2c0f11c121504500a554d60c08cc (patch)
tree6c9e98696530b2661343942948b9f1a50a8665e7 /src/interpret
parenta4980b8dbf1394c2b302f1de7c72d2264426b86e (diff)
downloadrabbithole-cff714c07e5e2c0f11c121504500a554d60c08cc.tar.zst
rabbithole-cff714c07e5e2c0f11c121504500a554d60c08cc.zip
Implement program walking.
Diffstat (limited to 'src/interpret')
-rw-r--r--src/interpret/mod.rs4
-rw-r--r--src/interpret/scope.rs45
-rw-r--r--src/interpret/value.rs181
-rw-r--r--src/interpret/walker.rs225
4 files changed, 330 insertions, 125 deletions
diff --git a/src/interpret/mod.rs b/src/interpret/mod.rs
index 2544ca3..813f45d 100644
--- a/src/interpret/mod.rs
+++ b/src/interpret/mod.rs
@@ -1 +1,3 @@
-pub mod walker; \ No newline at end of file
+mod scope;
+mod value;
+pub mod walker;
diff --git a/src/interpret/scope.rs b/src/interpret/scope.rs
new file mode 100644
index 0000000..de32692
--- /dev/null
+++ b/src/interpret/scope.rs
@@ -0,0 +1,45 @@
+use super::value::Value;
+use crate::parse::ast::nodes::Identifier;
+use std::collections::HashMap;
+
+pub struct Scope {
+ scopes: Vec<HashMap<Identifier, Value>>,
+}
+
+impl Scope {
+ pub fn new() -> Self {
+ Scope { scopes: Vec::new() }
+ }
+
+ pub fn nest(&mut self) {
+ self.scopes.push(HashMap::new());
+ }
+
+ pub fn unnest(&mut self) {
+ self.scopes.pop();
+ }
+
+ pub fn set_var(&mut self, ident: &Identifier, value: Value) {
+ for scope in self.scopes.iter_mut() {
+ if scope.contains_key(ident) {
+ scope.insert(ident.clone(), value);
+ return;
+ }
+ }
+
+ let inner_scope = self
+ .scopes
+ .last_mut()
+ .expect("Tried accessing scope after last frame is gone.");
+ inner_scope.insert(ident.clone(), value);
+ }
+
+ pub fn get_var(&self, ident: &Identifier) -> Option<Value> {
+ for scope in self.scopes.iter().rev() {
+ if let Some(value) = scope.get(ident) {
+ return Some(value.clone());
+ }
+ }
+ None
+ }
+}
diff --git a/src/interpret/value.rs b/src/interpret/value.rs
new file mode 100644
index 0000000..0c7843c
--- /dev/null
+++ b/src/interpret/value.rs
@@ -0,0 +1,181 @@
+use crate::parse::ast::nodes::FnNode;
+use anyhow::{anyhow, Result};
+use std::{cell::RefCell, rc::Rc};
+
+type Ref<T> = RefCell<Rc<T>>;
+
+#[derive(Clone, Debug)]
+pub enum Value {
+ Str(String),
+ Float(f64),
+ Int(i64),
+ Fn(Ref<FnNode>),
+ Void,
+}
+
+impl Value {
+ pub fn add(self, rhs: Value) -> Result<Value> {
+ match self {
+ Value::Str(l) => match rhs {
+ Value::Str(r) => Ok(Value::Str(l + &r)),
+ Value::Float(r) => Ok(Value::Str(l + &r.to_string())),
+ Value::Int(r) => Ok(Value::Str(l + &r.to_string())),
+ _ => Err(anyhow!("Right operand can't be added.")),
+ },
+ Value::Float(l) => match rhs {
+ Value::Str(r) => Ok(Value::Str(l.to_string() + &r)),
+ Value::Float(r) => Ok(Value::Float(l + r)),
+ Value::Int(r) => Ok(Value::Float(l + r as f64)),
+ _ => Err(anyhow!("Right operand can't be added.")),
+ },
+ Value::Int(l) => match rhs {
+ Value::Str(r) => Ok(Value::Str(l.to_string() + &r)),
+ Value::Float(r) => Ok(Value::Float(l as f64 + r)),
+ Value::Int(r) => Ok(Value::Int(l + r)),
+ _ => Err(anyhow!("Right operand can't be added.")),
+ },
+ _ => Err(anyhow!("Left operand can't be added.")),
+ }
+ }
+
+ pub fn sub(self, rhs: Value) -> Result<Value> {
+ match self {
+ Value::Float(l) => match rhs {
+ Value::Float(r) => Ok(Value::Float(l - r)),
+ Value::Int(r) => Ok(Value::Float(l - r as f64)),
+ _ => Err(anyhow!("Right operand can't be substracted.")),
+ },
+ Value::Int(l) => match rhs {
+ Value::Float(r) => Ok(Value::Float(l as f64 - r)),
+ Value::Int(r) => Ok(Value::Int(l - r)),
+ _ => Err(anyhow!("Right operand can't be substracted.")),
+ },
+ _ => Err(anyhow!("Left operand can't be substracted from.")),
+ }
+ }
+
+ pub fn mul(self, rhs: Value) -> Result<Value> {
+ match self {
+ Value::Float(l) => match rhs {
+ Value::Float(r) => Ok(Value::Float(l * r)),
+ Value::Int(r) => Ok(Value::Float(l * r as f64)),
+ _ => Err(anyhow!("Right operand can't be multiplied.")),
+ },
+ Value::Int(l) => match rhs {
+ Value::Float(r) => Ok(Value::Float(l as f64 * r)),
+ Value::Int(r) => Ok(Value::Int(l * r)),
+ _ => Err(anyhow!("Right operand can't be multiplied.")),
+ },
+ _ => Err(anyhow!("Left operand can't be multiplied.")),
+ }
+ }
+
+ pub fn div(self, rhs: Value) -> Result<Value> {
+ match self {
+ Value::Float(l) => match rhs {
+ Value::Float(r) => Ok(Value::Float(l / r)),
+ Value::Int(r) => Ok(Value::Float(l / r as f64)),
+ _ => Err(anyhow!("Right operand can't be multiplied.")),
+ },
+ Value::Int(l) => match rhs {
+ Value::Float(r) => Ok(Value::Float(l as f64 / r)),
+ Value::Int(r) => Ok(Value::Float(l as f64 / r as f64)),
+ _ => Err(anyhow!("Right operand can't be multiplied.")),
+ },
+ _ => Err(anyhow!("Left operand can't be multiplied.")),
+ }
+ }
+}
+
+// pub enum Value {
+// Float(f64),
+// Int(i64),
+// }
+
+// impl Add for WalkValue {
+// type Output = Self;
+
+// fn add(self, rhs: Self) -> Self::Output {
+// match self {
+// Self::Float(float) => match rhs {
+// Self::Float(other_float) => Self::Float(float + other_float),
+// Self::Int(other_int) => Self::Float(float + other_int as f64),
+// },
+// Self::Int(int) => match rhs {
+// Self::Float(other_float) => Self::Float(int as f64 + other_float),
+// Self::Int(other_int) => Self::Int(int + other_int),
+// },
+// }
+// }
+// }
+
+// impl Sub for WalkValue {
+// type Output = Self;
+
+// fn sub(self, rhs: Self) -> Self::Output {
+// match self {
+// Self::Float(float) => match rhs {
+// Self::Float(other_float) => Self::Float(float - other_float),
+// Self::Int(other_int) => Self::Float(float - other_int as f64),
+// },
+// Self::Int(int) => match rhs {
+// Self::Float(other_float) => Self::Float(int as f64 - other_float),
+// Self::Int(other_int) => Self::Int(int - other_int),
+// },
+// }
+// }
+// }
+
+// impl Mul for WalkValue {
+// type Output = Self;
+
+// fn mul(self, rhs: Self) -> Self::Output {
+// match self {
+// Self::Float(float) => match rhs {
+// Self::Float(other_float) => Self::Float(float * other_float),
+// Self::Int(other_int) => Self::Float(float * other_int as f64),
+// },
+// Self::Int(int) => match rhs {
+// Self::Float(other_float) => Self::Float(int as f64 * other_float),
+// Self::Int(other_int) => Self::Int(int * other_int),
+// },
+// }
+// }
+// }
+
+// impl Div for WalkValue {
+// type Output = Self;
+
+// fn div(self, rhs: Self) -> Self::Output {
+// match self {
+// Self::Float(float) => match rhs {
+// Self::Float(other_float) => Self::Float(float / other_float),
+// Self::Int(other_int) => Self::Float(float / other_int as f64),
+// },
+// Self::Int(int) => match rhs {
+// Self::Float(other_float) => Self::Float(int as f64 / other_float),
+// Self::Int(other_int) => Self::Float(int as f64 / other_int as f64),
+// },
+// }
+// }
+// }
+
+// impl Neg for WalkValue {
+// type Output = Self;
+
+// fn neg(self) -> Self::Output {
+// match self {
+// Self::Float(float) => Self::Float(-float),
+// Self::Int(int) => Self::Int(-int),
+// }
+// }
+// }
+
+// impl Display for WalkValue {
+// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+// match self {
+// Self::Float(float) => write!(f, "{}", float),
+// Self::Int(int) => write!(f, "{}", int),
+// }
+// }
+// }
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index 817e94e..576cfb5 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -1,161 +1,138 @@
-use std::{
- fmt::Display,
- ops::{Add, Div, Mul, Neg, Sub},
-};
+use std::{cell::RefCell, rc::Rc};
use crate::parse::ast::{
expression::Expression,
- value::{BinaryOperator, Literal, UnaryOperator},
+ nodes::{BinaryOperator as BinOp, Literal, UnaryOperator as UnOp},
+ statement::Statement,
+ Program,
};
-use anyhow::Result;
+use anyhow::{anyhow, Result};
+
+use super::{scope::Scope, value::Value};
// No state for now.
-pub struct Walker {}
+pub struct Walker {
+ scope: Scope,
+}
impl Walker {
pub fn new() -> Self {
- Walker {}
+ Walker {
+ scope: Scope::new(),
+ }
+ }
+
+ pub fn walk(&mut self, program: &Program) {
+ self.scope.nest();
+ for statement in program.statements.iter() {
+ self.walk_statement(statement).expect("Runtime error.");
+ }
+ }
+
+ fn walk_statement(&mut self, statement: &Statement) -> Result<Option<Value>> {
+ let result = match statement {
+ Statement::Expression(node) => {
+ self.walk_expression(node)?;
+ None
+ }
+ Statement::Print(node) => {
+ let result = self.walk_expression(node)?;
+ println!("{:?}", result);
+ None
+ }
+ Statement::Return(node) => Some(self.walk_expression(node)?),
+ };
+
+ Ok(result)
}
- pub fn walk(&self, node: &Expression) -> Result<WalkValue> {
+ fn walk_expression(&mut self, node: &Expression) -> Result<Value> {
match node {
Expression::Binary { left, op, right } => {
- let left_value = self.walk(left)?;
- let right_value = self.walk(right)?;
-
let new_value = match op {
- BinaryOperator::Plus => left_value + right_value,
- BinaryOperator::Minus => left_value - right_value,
- BinaryOperator::Star => left_value * right_value,
- BinaryOperator::Slash => left_value / right_value,
- BinaryOperator::Eq => todo!(),
- BinaryOperator::Neq => todo!(),
- BinaryOperator::Gt => todo!(),
- BinaryOperator::Gte => todo!(),
- BinaryOperator::Lt => todo!(),
- BinaryOperator::Lte => todo!(),
- BinaryOperator::Assign => todo!(),
- BinaryOperator::ConstAssign => todo!(),
- BinaryOperator::Dot => todo!(),
- };
+ BinOp::Plus => self
+ .walk_expression(left)?
+ .add(self.walk_expression(right)?),
+ BinOp::Minus => self
+ .walk_expression(left)?
+ .sub(self.walk_expression(right)?),
+ BinOp::Star => self
+ .walk_expression(left)?
+ .mul(self.walk_expression(right)?),
+ BinOp::Slash => self
+ .walk_expression(left)?
+ .div(self.walk_expression(right)?),
+ // No difference between assignments for now.
+ BinOp::Assign | BinOp::ConstAssign => {
+ let identifier = match left.as_ref() {
+ Expression::Identifier(i) => i,
+ _ => todo!("Lvalues can only be identifiers."),
+ };
+
+ let value = self.walk_expression(right)?;
+ self.scope.set_var(identifier, value.clone());
+ Ok(value)
+ }
+ // Boolean logic comes later.
+ BinOp::Eq | BinOp::Neq | BinOp::Gt | BinOp::Gte | BinOp::Lt | BinOp::Lte => {
+ todo!()
+ }
+ // No structure access yet.
+ BinOp::Dot => todo!(),
+ }?;
Ok(new_value)
}
Expression::Unary { op, right } => {
- let value = self.walk(right)?;
+ let value = self.walk_expression(right)?;
let new_value = match op {
- UnaryOperator::Plus => value,
- UnaryOperator::Minus => -value,
- UnaryOperator::Not => todo!("Implement boolean arithmetic."),
+ UnOp::Plus => value,
+ UnOp::Minus => todo!(),
+ UnOp::Not => todo!("Implement boolean arithmetic."),
};
Ok(new_value)
}
- Expression::Group(node) => self.walk(node),
+ Expression::Group(node) => self.walk_expression(node),
Expression::Literal(token) => {
let value = match token {
- Literal::Int(int) => WalkValue::Int(*int as i64),
- Literal::Float(float) => WalkValue::Float(*float as f64),
- _ => todo!(),
+ Literal::Int(int) => Value::Int(*int as i64),
+ Literal::Float(float) => Value::Float(*float as f64),
+ Literal::Str(string) => Value::Str(string.clone()),
};
Ok(value)
}
- _ => todo!(),
- }
- }
-}
-
-pub enum WalkValue {
- Float(f64),
- Int(i64),
-}
-
-impl Add for WalkValue {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self::Output {
- match self {
- Self::Float(float) => match rhs {
- Self::Float(other_float) => Self::Float(float + other_float),
- Self::Int(other_int) => Self::Float(float + other_int as f64),
- },
- Self::Int(int) => match rhs {
- Self::Float(other_float) => Self::Float(int as f64 + other_float),
- Self::Int(other_int) => Self::Int(int + other_int),
- },
- }
- }
-}
-
-impl Sub for WalkValue {
- type Output = Self;
-
- fn sub(self, rhs: Self) -> Self::Output {
- match self {
- Self::Float(float) => match rhs {
- Self::Float(other_float) => Self::Float(float - other_float),
- Self::Int(other_int) => Self::Float(float - other_int as f64),
- },
- Self::Int(int) => match rhs {
- Self::Float(other_float) => Self::Float(int as f64 - other_float),
- Self::Int(other_int) => Self::Int(int - other_int),
- },
- }
- }
-}
-
-impl Mul for WalkValue {
- type Output = Self;
-
- fn mul(self, rhs: Self) -> Self::Output {
- match self {
- Self::Float(float) => match rhs {
- Self::Float(other_float) => Self::Float(float * other_float),
- Self::Int(other_int) => Self::Float(float * other_int as f64),
- },
- Self::Int(int) => match rhs {
- Self::Float(other_float) => Self::Float(int as f64 * other_float),
- Self::Int(other_int) => Self::Int(int * other_int),
- },
- }
- }
-}
+ Expression::Block(block) => {
+ self.scope.nest();
-impl Div for WalkValue {
- type Output = Self;
+ for statement in block.statements.iter() {
+ self.walk_statement(statement)?;
+ }
- fn div(self, rhs: Self) -> Self::Output {
- match self {
- Self::Float(float) => match rhs {
- Self::Float(other_float) => Self::Float(float / other_float),
- Self::Int(other_int) => Self::Float(float / other_int as f64),
- },
- Self::Int(int) => match rhs {
- Self::Float(other_float) => Self::Float(int as f64 / other_float),
- Self::Int(other_int) => Self::Float(int as f64 / other_int as f64),
- },
- }
- }
-}
+ let result = if let Some(tail_expression) = &block.tail_expression {
+ Ok(self.walk_expression(tail_expression)?)
+ } else {
+ Ok(Value::Void)
+ };
-impl Neg for WalkValue {
- type Output = Self;
+ self.scope.unnest();
- fn neg(self) -> Self::Output {
- match self {
- Self::Float(float) => Self::Float(-float),
- Self::Int(int) => Self::Int(-int),
- }
- }
-}
-
-impl Display for WalkValue {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Self::Float(float) => write!(f, "{}", float),
- Self::Int(int) => write!(f, "{}", int),
+ result
+ }
+ Expression::Fn(fn_node) => {
+ let node = fn_node.as_ref().clone();
+ Ok(Value::Fn(RefCell::new(Rc::new(node))))
+ }
+ Expression::If(_) => todo!(),
+ Expression::Identifier(ident) => {
+ if let Some(value) = self.scope.get_var(ident) {
+ Ok(value)
+ } else {
+ Err(anyhow!("Unknown identifier: {}.", ident))
+ }
+ }
}
}
}