aboutsummaryrefslogtreecommitdiff
path: root/src/interpret
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-22 22:44:21 +0200
committerMel <einebeere@gmail.com>2021-10-22 22:52:24 +0200
commitc35a7ba06a47a8b26bd784df552ad4c881383898 (patch)
tree1ae23ace7246a0a97d6d53d6b0d0b88528ca5ad1 /src/interpret
parentce9007bd5aefc37cf7e48eefc0fab4049c8a6b7d (diff)
downloadrabbithole-c35a7ba06a47a8b26bd784df552ad4c881383898.tar.zst
rabbithole-c35a7ba06a47a8b26bd784df552ad4c881383898.zip
Boolean logic and If expressions.
Diffstat (limited to 'src/interpret')
-rw-r--r--src/interpret/value.rs150
-rw-r--r--src/interpret/walker.rs113
2 files changed, 127 insertions, 136 deletions
diff --git a/src/interpret/value.rs b/src/interpret/value.rs
index 0c7843c..1ca0f0e 100644
--- a/src/interpret/value.rs
+++ b/src/interpret/value.rs
@@ -9,6 +9,7 @@ pub enum Value {
Str(String),
Float(f64),
Int(i64),
+ Bool(bool),
Fn(Ref<FnNode>),
Void,
}
@@ -85,97 +86,66 @@ impl Value {
_ => 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),
-// },
-// }
-// }
-// }
+ pub fn eq(self, rhs: Value) -> Result<Value> {
+ match self {
+ Value::Str(l) => match rhs {
+ Value::Str(r) => Ok(Value::Bool(l == r)),
+ _ => Ok(Value::Bool(false)),
+ },
+ Value::Float(l) => match rhs {
+ Value::Float(r) => Ok(Value::Bool(l == r)),
+ _ => Ok(Value::Bool(false)),
+ },
+ Value::Int(l) => match rhs {
+ Value::Int(r) => Ok(Value::Bool(l == r)),
+ _ => Ok(Value::Bool(false)),
+ },
+ Value::Bool(l) => match rhs {
+ Value::Bool(r) => Ok(Value::Bool(l == r)),
+ _ => Ok(Value::Bool(false)),
+ },
+ _ => Ok(Value::Bool(false)),
+ }
+ }
-// impl Neg for WalkValue {
-// type Output = Self;
+ pub fn neq(self, rhs: Value) -> Result<Value> {
+ if let Ok(Value::Bool(value)) = self.eq(rhs) {
+ Ok(Value::Bool(!value))
+ } else {
+ unreachable!()
+ }
+ }
-// fn neg(self) -> Self::Output {
-// match self {
-// Self::Float(float) => Self::Float(-float),
-// Self::Int(int) => Self::Int(-int),
-// }
-// }
-// }
+ pub fn gt(self, rhs: Value) -> Result<Value> {
+ match self {
+ Value::Float(r) => match rhs {
+ Value::Float(l) => Ok(Value::Bool(r > l)),
+ Value::Int(l) => Ok(Value::Bool(r > l as f64)),
+ _ => Err(anyhow!("Right operand can't be compared.")),
+ },
+ Value::Int(r) => match rhs {
+ Value::Float(l) => Ok(Value::Bool(r as f64 > l)),
+ Value::Int(l) => Ok(Value::Bool(r > l)),
+ _ => Err(anyhow!("Right operand can't be compared.")),
+ },
+ _ => Err(anyhow!("Left operand can't be compared.")),
+ }
+ }
-// 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),
-// }
-// }
-// }
+ pub fn gte(self, rhs: Value) -> Result<Value> {
+ match self {
+ Value::Float(r) => match rhs {
+ Value::Float(l) => Ok(Value::Bool(r >= l)),
+ Value::Int(l) => Ok(Value::Bool(r >= l as f64)),
+ _ => Err(anyhow!("Right operand can't be compared.")),
+ },
+ Value::Int(r) => match rhs {
+ Value::Float(l) => Ok(Value::Bool(r as f64 >= l)),
+ Value::Int(l) => Ok(Value::Bool(r >= l)),
+ _ => Err(anyhow!("Right operand can't be compared.")),
+ },
+ _ => Err(anyhow!("Left operand can't be compared.")),
+ }
+ }
+}
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index 16f3f1c..79ef87f 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc};
use crate::parse::ast::{
expression::Expression,
- nodes::{BinaryOperator as BinOp, Literal, UnaryOperator as UnOp},
+ nodes::{BinaryOperator as BinOp, BlockNode, Literal, UnaryOperator as UnOp},
statement::Statement,
Program,
};
@@ -10,7 +10,6 @@ use anyhow::{anyhow, Result};
use super::{scope::Scope, value::Value};
-// No state for now.
pub struct Walker {
scope: Scope,
}
@@ -49,36 +48,37 @@ impl Walker {
pub fn walk_expression(&mut self, node: &Expression) -> Result<Value> {
match node {
Expression::Binary { left, op, right } => {
- let new_value = match op {
- 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."),
- };
+ // Assignment
+ // No difference between assignments for now.
+ if let BinOp::ConstAssign | BinOp::Assign = op {
+ 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!()
- }
+ let value = self.walk_expression(right)?;
+ self.scope.set_var(identifier, value.clone());
+ return Ok(value);
+ }
+
+ let left = self.walk_expression(left)?;
+ let right = self.walk_expression(right)?;
+
+ // Other operators
+ let new_value = match op {
+ BinOp::Plus => left.add(right),
+ BinOp::Minus => left.sub(right),
+ BinOp::Star => left.mul(right),
+ BinOp::Slash => left.div(right),
+ BinOp::Eq => left.eq(right),
+ BinOp::Neq => left.neq(right),
+ BinOp::Gt => left.gt(right),
+ BinOp::Gte => left.gte(right),
+ BinOp::Lt => right.gt(left),
+ BinOp::Lte => right.gte(left),
// No structure access yet.
BinOp::Dot => todo!(),
+ _ => unreachable!(),
}?;
Ok(new_value)
@@ -100,32 +100,35 @@ impl Walker {
Literal::Int(int) => Value::Int(*int as i64),
Literal::Float(float) => Value::Float(*float as f64),
Literal::Str(string) => Value::Str(string.clone()),
+ Literal::Bool(bool) => Value::Bool(*bool),
};
Ok(value)
}
- Expression::Block(block) => {
- self.scope.nest();
-
- for statement in block.statements.iter() {
- self.walk_statement(statement)?;
+ Expression::Block(block) => self.walk_block(block.as_ref()),
+ Expression::Fn(fn_node) => {
+ let node = fn_node.as_ref().clone();
+ Ok(Value::Fn(RefCell::new(Rc::new(node))))
+ }
+ Expression::If(if_node) => {
+ for conditional in &if_node.conditionals {
+ if let Value::Bool(bool) = self.walk_expression(&conditional.condition)? {
+ if bool {
+ return self.walk_block(&conditional.block);
+ }
+ } else {
+ return Err(anyhow!(
+ "If and Elif expressions can only take boolean values as conditions."
+ ));
+ }
}
- let result = if let Some(tail_expression) = &block.tail_expression {
- Ok(self.walk_expression(tail_expression)?)
+ if let Some(else_conditional) = &if_node.else_block {
+ self.walk_block(else_conditional)
} else {
Ok(Value::Void)
- };
-
- self.scope.unnest();
-
- 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)
@@ -135,4 +138,22 @@ impl Walker {
}
}
}
+
+ fn walk_block(&mut self, block: &BlockNode) -> Result<Value> {
+ self.scope.nest();
+
+ for statement in block.statements.iter() {
+ self.walk_statement(statement)?;
+ }
+
+ let result = if let Some(tail_expression) = &block.tail_expression {
+ Ok(self.walk_expression(tail_expression)?)
+ } else {
+ Ok(Value::Void)
+ };
+
+ self.scope.unnest();
+
+ result
+ }
}