diff options
| author | Mel <einebeere@gmail.com> | 2021-11-20 00:31:28 +0100 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2021-11-20 00:31:28 +0100 |
| commit | 395d086f0dce355ccdcf3da149c309826c539b48 (patch) | |
| tree | 888ad59d8fcebcec0c04bcfd13364889c5047349 /src/interpret | |
| parent | 334f70f5a2f63ec636ac1a8bc375ce51effba424 (diff) | |
| download | rabbithole-395d086f0dce355ccdcf3da149c309826c539b48.tar.zst rabbithole-395d086f0dce355ccdcf3da149c309826c539b48.zip | |
Runtime types
Diffstat (limited to 'src/interpret')
| -rw-r--r-- | src/interpret/mod.rs | 5 | ||||
| -rw-r--r-- | src/interpret/operator.rs | 300 | ||||
| -rw-r--r-- | src/interpret/scope.rs | 38 | ||||
| -rw-r--r-- | src/interpret/value.rs | 341 | ||||
| -rw-r--r-- | src/interpret/walker.rs | 125 |
5 files changed, 464 insertions, 345 deletions
diff --git a/src/interpret/mod.rs b/src/interpret/mod.rs index 813f45d..7f1c844 100644 --- a/src/interpret/mod.rs +++ b/src/interpret/mod.rs @@ -1,3 +1,4 @@ mod scope; -mod value; -pub mod walker; +mod operator; +pub mod value; +pub mod walker; \ No newline at end of file diff --git a/src/interpret/operator.rs b/src/interpret/operator.rs new file mode 100644 index 0000000..78ebe75 --- /dev/null +++ b/src/interpret/operator.rs @@ -0,0 +1,300 @@ +use thiserror::Error; + +use crate::{parse::ast::expression::Expression, types::bag::TypeBag}; + +use super::{ + value::{Value, ValueVariant}, + walker::{Walker, WalkerError}, +}; + +pub struct ValueOperator<'types> { + types: &'types TypeBag, +} + +impl<'t> ValueOperator<'t> { + pub fn new(types: &'t TypeBag) -> Self { + ValueOperator { types } + } + + pub fn add(&self, lhs: Value, rhs: Value) -> Result<Value, OperationError> { + match lhs.variant { + ValueVariant::Str(ref l) => match rhs.variant { + ValueVariant::Str(r) => Ok(Value::str(format!("{}{}", l, r), self.types)), + ValueVariant::Float(r) => Ok(Value::str(format!("{}{}", l, r), self.types)), + ValueVariant::Int(r) => Ok(Value::str(format!("{}{}", l, r), self.types)), + _ => Err(OperationError::AddTypes(lhs, rhs)), + }, + ValueVariant::Float(l) => match rhs.variant { + ValueVariant::Str(r) => Ok(Value::str(l.to_string() + &r, self.types)), + ValueVariant::Float(r) => Ok(Value::float(l + r, self.types)), + ValueVariant::Int(r) => Ok(Value::float(l + r as f64, self.types)), + _ => Err(OperationError::AddTypes(lhs, rhs)), + }, + ValueVariant::Int(l) => match rhs.variant { + ValueVariant::Str(r) => Ok(Value::str(l.to_string() + &r, self.types)), + ValueVariant::Float(r) => Ok(Value::float(l as f64 + r, self.types)), + ValueVariant::Int(r) => Ok(Value::int(l + r, self.types)), + _ => Err(OperationError::AddTypes(lhs, rhs)), + }, + _ => Err(OperationError::AddTypes(lhs, rhs)), + } + } + + pub fn sub(&self, lhs: Value, rhs: Value) -> Result<Value, OperationError> { + match lhs.variant { + ValueVariant::Float(l) => match rhs.variant { + ValueVariant::Float(r) => Ok(Value::float(l - r, self.types)), + ValueVariant::Int(r) => Ok(Value::float(l - r as f64, self.types)), + _ => Err(OperationError::SubTypes(lhs, rhs)), + }, + ValueVariant::Int(l) => match rhs.variant { + ValueVariant::Float(r) => Ok(Value::float(l as f64 - r, self.types)), + ValueVariant::Int(r) => Ok(Value::int(l - r, self.types)), + _ => Err(OperationError::SubTypes(lhs, rhs)), + }, + _ => Err(OperationError::SubTypes(lhs, rhs)), + } + } + + pub fn mul(&self, lhs: Value, rhs: Value) -> Result<Value, OperationError> { + match lhs.variant { + ValueVariant::Float(l) => match rhs.variant { + ValueVariant::Float(r) => Ok(Value::float(l * r, self.types)), + ValueVariant::Int(r) => Ok(Value::float(l * r as f64, self.types)), + _ => Err(OperationError::MulTypes(lhs, rhs)), + }, + ValueVariant::Int(l) => match rhs.variant { + ValueVariant::Float(r) => Ok(Value::float(l as f64 * r, self.types)), + ValueVariant::Int(r) => Ok(Value::int(l * r, self.types)), + _ => Err(OperationError::MulTypes(lhs, rhs)), + }, + _ => Err(OperationError::MulTypes(lhs, rhs)), + } + } + + pub fn div(&self, lhs: Value, rhs: Value) -> Result<Value, OperationError> { + match lhs.variant { + ValueVariant::Float(l) => match rhs.variant { + ValueVariant::Float(r) => Ok(Value::float(l / r, self.types)), + ValueVariant::Int(r) => Ok(Value::float(l / r as f64, self.types)), + _ => Err(OperationError::DivTypes(lhs, rhs)), + }, + ValueVariant::Int(l) => match rhs.variant { + ValueVariant::Float(r) => Ok(Value::float(l as f64 / r, self.types)), + ValueVariant::Int(r) => Ok(Value::float(l as f64 / r as f64, self.types)), + _ => Err(OperationError::DivTypes(lhs, rhs)), + }, + _ => Err(OperationError::DivTypes(lhs, rhs)), + } + } + + pub fn eq(&self, lhs: Value, rhs: Value) -> Result<Value, OperationError> { + match lhs.variant { + ValueVariant::Str(l) => match rhs.variant { + ValueVariant::Str(r) => Ok(Value::bool(l == r, self.types)), + _ => Ok(Value::bool(false, self.types)), + }, + ValueVariant::Float(l) => match rhs.variant { + ValueVariant::Float(r) => Ok(Value::bool(l == r, self.types)), + _ => Ok(Value::bool(false, self.types)), + }, + ValueVariant::Int(l) => match rhs.variant { + ValueVariant::Int(r) => Ok(Value::bool(l == r, self.types)), + _ => Ok(Value::bool(false, self.types)), + }, + ValueVariant::Bool(l) => match rhs.variant { + ValueVariant::Bool(r) => Ok(Value::bool(l == r, self.types)), + _ => Ok(Value::bool(false, self.types)), + }, + _ => Ok(Value::bool(false, self.types)), + } + } + + pub fn neq(&self, lhs: Value, rhs: Value) -> Result<Value, OperationError> { + if let Ok(Value { + variant: ValueVariant::Bool(value), + .. + }) = self.eq(lhs, rhs) + { + Ok(Value::bool(!value, self.types)) + } else { + unreachable!() + } + } + + pub fn gt(&self, lhs: Value, rhs: Value) -> Result<Value, OperationError> { + match lhs.variant { + ValueVariant::Float(r) => match rhs.variant { + ValueVariant::Float(l) => Ok(Value::bool(r > l, self.types)), + ValueVariant::Int(l) => Ok(Value::bool(r > l as f64, self.types)), + _ => Err(OperationError::CompareTypes(lhs, rhs)), + }, + ValueVariant::Int(r) => match rhs.variant { + ValueVariant::Float(l) => Ok(Value::bool(r as f64 > l, self.types)), + ValueVariant::Int(l) => Ok(Value::bool(r > l, self.types)), + _ => Err(OperationError::CompareTypes(lhs, rhs)), + }, + _ => Err(OperationError::CompareTypes(lhs, rhs)), + } + } + + pub fn gte(&self, lhs: Value, rhs: Value) -> Result<Value, OperationError> { + match lhs.variant { + ValueVariant::Float(r) => match rhs.variant { + ValueVariant::Float(l) => Ok(Value::bool(r >= l, self.types)), + ValueVariant::Int(l) => Ok(Value::bool(r >= l as f64, self.types)), + _ => Err(OperationError::CompareTypes(lhs, rhs)), + }, + ValueVariant::Int(r) => match rhs.variant { + ValueVariant::Float(l) => Ok(Value::bool(r as f64 >= l, self.types)), + ValueVariant::Int(l) => Ok(Value::bool(r >= l, self.types)), + _ => Err(OperationError::CompareTypes(lhs, rhs)), + }, + _ => Err(OperationError::CompareTypes(lhs, rhs)), + } + } + + pub fn neg(&self, val: Value) -> Result<Value, OperationError> { + match val.variant { + ValueVariant::Float(float) => Ok(Value::float(-float, self.types)), + ValueVariant::Int(int) => Ok(Value::int(-int, self.types)), + _ => Err(OperationError::NegType(val)), + } + } + + pub fn not(&self, val: Value) -> Result<Value, OperationError> { + match val.variant { + ValueVariant::Bool(bool) => Ok(Value::bool(bool, self.types)), + _ => Err(OperationError::NotType(val)), + } + } + + pub fn subscript(&self, val: Value, index: Value) -> Result<Value, OperationError> { + let index = match index.variant { + ValueVariant::Int(i) => i, + _ => return Err(OperationError::ArrayIndexType(index)), + }; + + match val.variant { + ValueVariant::Array(a) => { + let array = a.borrow(); + if index < 0 || index as usize >= array.len() { + Err(OperationError::ArrayIndexOutOfRange { + index, + length: array.len(), + }) + } else { + Ok(array[index as usize].clone()) + } + } + // Maybe allow string subscripts? + _ => Err(OperationError::ArrayType(val)), + } + } + + pub fn subscript_assign( + &self, + val: &mut Value, + index: Value, + value: Value, + ) -> Result<Value, OperationError> { + let index = match index.variant { + ValueVariant::Int(i) => i, + _ => return Err(OperationError::ArrayIndexType(index)), + }; + + match &val.variant { + ValueVariant::Array(a) => { + let mut array = a.borrow_mut(); + if index < 0 || index as usize >= array.len() { + Err(OperationError::ArrayIndexOutOfRange { + index, + length: array.len(), + }) + } else { + array[index as usize] = value; + Ok(array[index as usize].clone()) + } + } + _ => Err(OperationError::ArrayType(val.clone())), + } + } + + pub fn call(&self, val: &Value, arguments: Vec<Value>) -> Result<Value, WalkerError> { + let called = match &val.variant { + ValueVariant::Fn(i) => i, + _ => { + return Err(WalkerError::OperationError(OperationError::CallableType( + val.clone(), + ))) + } + } + .borrow(); + + // FIXME: Currently closures are able to re-assign values from the upper scopes. + // This is good behaviour, until a closure re-assigns a value that was declared after + // the closure even existed. + // Minimal reproducible example: + // ```rh + // closure = fn { y = 10; }; + // y = 1; + // closure(); + // print y; + // ``` + // Expected: 1 + // Actual: 10 + let mut scope = called.scope.clone(); + scope.nest(); + + let parameters = &called.node.header.parameters; + + if parameters.len() != arguments.len() { + return Err(WalkerError::OperationError( + OperationError::WrongArgumentCount(parameters.len(), arguments.len()), + )); + } + + for (argument, parameter) in arguments.into_iter().zip(parameters.iter()) { + scope.set_var_shadowed(¶meter.identifier, argument); + } + + // Yes, we create a new walker for every function call, + // it's *way* easier that way. + let mut walker = Walker::new(scope, self.types.clone()); + let result = walker.walk_expression(&Expression::Block(Box::new(called.node.body.clone()))); + + if let Err(WalkerError::Return(returned)) = result { + Ok(returned) + } else { + result + } + } +} + +#[derive(Error, Debug)] +pub enum OperationError { + #[error("Can't add value '{0}' of type '{}' to value '{1}' of type '{}'.", .0.type_name(), .1.type_name())] + AddTypes(Value, Value), + #[error("Can't subtract value '{1}' of type '{}' from value '{0}' of type '{}'.", .1.type_name(), .0.type_name())] + SubTypes(Value, Value), + #[error("Can't multiply value '{0}' of type '{}' with value '{1}' of type '{}'.", .0.type_name(), .1.type_name())] + MulTypes(Value, Value), + #[error("Can't divide value '{0}' of type '{}' by value '{1}' of type '{}'.", .0.type_name(), .1.type_name())] + DivTypes(Value, Value), + #[error("Can't compare value '{0}' of type '{}' with value '{1}' of type '{}'.", .0.type_name(), .1.type_name())] + CompareTypes(Value, Value), + #[error("Can't negate value '{0}' of type '{}'.", .0.type_name())] + NegType(Value), + #[error("Can't flip value '{0}' of type '{}'.", .0.type_name())] + NotType(Value), + #[error("Can't use value '{0}' of type '{}' as a subsript index.", .0.type_name())] + ArrayIndexType(Value), + #[error("Can't subscript value '{0}' of type '{}'.", .0.type_name())] + ArrayType(Value), + #[error("Array index '{index}' out of range for array of length '{length}'.")] + ArrayIndexOutOfRange { index: i64, length: usize }, + #[error("Can't call value '{0}' of type '{}'.", .0.type_name())] + CallableType(Value), + #[error("Function expects {0} arguments, but {1} were given.")] + WrongArgumentCount(usize, usize), +} diff --git a/src/interpret/scope.rs b/src/interpret/scope.rs index 0db34c2..3813cab 100644 --- a/src/interpret/scope.rs +++ b/src/interpret/scope.rs @@ -1,5 +1,8 @@ -use super::value::Value; -use crate::parse::ast::nodes::Identifier; +use super::value::{Value, ValueVariant}; +use crate::{ + parse::ast::nodes::Identifier, + types::{bag::TypeBag, TypeVariant}, +}; use std::{cell::RefCell, collections::HashMap, rc::Rc}; use thiserror::Error; @@ -82,10 +85,10 @@ impl ScopeChain { } } - pub fn get_var(&self, ident: &str) -> Result<Value, ScopeError> { + pub fn get_var(&self, ident: &str, types: &TypeBag) -> Result<Value, ScopeError> { for scope in self.scopes.iter().rev() { if let Some(value) = scope.get(ident) { - return Ok(value.get_value()); + return Ok(value.get_value(types)); } } Err(ScopeError::UnknownIdentifier(ident.to_string())) @@ -111,19 +114,32 @@ enum AssignedValue { } impl AssignedValue { - fn get_value(&self) -> Value { + fn get_value(&self, types: &TypeBag) -> Value { match self { Self::Mutable(value) => value.clone(), - Self::Constant(value) => match value { - Value::Array(reference) => { + Self::Constant(value) => match &value.variant { + ValueVariant::Array(reference) => { let underlying_value = reference.borrow().clone(); - Value::Array(Rc::new(RefCell::new(underlying_value))) + + Value { + variant: ValueVariant::Array(Rc::new(RefCell::new(underlying_value))), + // FIXME: Give arrays actual type instead of void. + typ: types.create_type(TypeVariant::Array(types.void())), + } } - Value::Fn(reference) => { + ValueVariant::Fn(reference) => { let underlying_value = reference.borrow().clone(); - Value::Fn(Rc::new(RefCell::new(underlying_value))) + + Value { + variant: ValueVariant::Fn(Rc::new(RefCell::new(underlying_value))), + // FIXME: Give functions actual types. + typ: types.create_type(TypeVariant::Fn { + parameters: HashMap::new(), + returns: types.void(), + }), + } } - x => x.clone(), + _ => value.clone(), }, } } diff --git a/src/interpret/value.rs b/src/interpret/value.rs index d108c68..45c177d 100644 --- a/src/interpret/value.rs +++ b/src/interpret/value.rs @@ -1,298 +1,90 @@ -use crate::parse::ast::{expression::Expression, nodes::FnNode}; -use std::{cell::RefCell, fmt::Display, rc::Rc}; -use thiserror::Error; - -use super::{ - scope::ScopeChain, - walker::{Walker, WalkerError}, +use crate::{ + parse::ast::nodes::{FnNode, Identifier}, + types::{bag::TypeBag, Type}, }; +use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc}; + +use super::scope::ScopeChain; type ReferenceOnCopy<T> = Rc<RefCell<T>>; #[derive(Clone, Debug)] -pub enum Value { +pub struct Value { + pub variant: ValueVariant, + pub typ: Type, +} + +#[derive(Clone, Debug)] +pub enum ValueVariant { Str(String), Float(f64), Int(i64), Bool(bool), Array(ReferenceOnCopy<Vec<Value>>), Fn(ReferenceOnCopy<FnValue>), + Data(HashMap<Identifier, Value>), Void, } impl Value { - pub fn add(self, rhs: Value) -> Result<Value, OperationError> { - match self { - Value::Str(ref l) => match rhs { - Value::Str(r) => Ok(Value::Str(format!("{}{}", l, r))), - Value::Float(r) => Ok(Value::Str(format!("{}{}", l, r))), - Value::Int(r) => Ok(Value::Str(format!("{}{}", l, r))), - r => Err(OperationError::AddTypes(self, r)), - }, - 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)), - r => Err(OperationError::AddTypes(self, r)), - }, - 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)), - r => Err(OperationError::AddTypes(self, r)), - }, - _ => Err(OperationError::AddTypes(self, rhs)), - } - } - - pub fn sub(self, rhs: Value) -> Result<Value, OperationError> { - 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)), - r => Err(OperationError::SubTypes(self, r)), - }, - Value::Int(l) => match rhs { - Value::Float(r) => Ok(Value::Float(l as f64 - r)), - Value::Int(r) => Ok(Value::Int(l - r)), - r => Err(OperationError::SubTypes(self, r)), - }, - _ => Err(OperationError::SubTypes(self, rhs)), - } - } - - pub fn mul(self, rhs: Value) -> Result<Value, OperationError> { - 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)), - r => Err(OperationError::MulTypes(self, r)), - }, - Value::Int(l) => match rhs { - Value::Float(r) => Ok(Value::Float(l as f64 * r)), - Value::Int(r) => Ok(Value::Int(l * r)), - r => Err(OperationError::MulTypes(self, r)), - }, - _ => Err(OperationError::MulTypes(self, rhs)), - } - } - - pub fn div(self, rhs: Value) -> Result<Value, OperationError> { - 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)), - r => Err(OperationError::DivTypes(self, r)), - }, - 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)), - r => Err(OperationError::DivTypes(self, r)), - }, - _ => Err(OperationError::DivTypes(self, rhs)), - } - } - - pub fn eq(self, rhs: Value) -> Result<Value, OperationError> { - 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)), - } - } - - pub fn neq(self, rhs: Value) -> Result<Value, OperationError> { - if let Ok(Value::Bool(value)) = self.eq(rhs) { - Ok(Value::Bool(!value)) - } else { - unreachable!() - } - } - - pub fn gt(self, rhs: Value) -> Result<Value, OperationError> { - 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)), - r => Err(OperationError::CompareTypes(self, r)), - }, - Value::Int(r) => match rhs { - Value::Float(l) => Ok(Value::Bool(r as f64 > l)), - Value::Int(l) => Ok(Value::Bool(r > l)), - r => Err(OperationError::CompareTypes(self, r)), - }, - _ => Err(OperationError::CompareTypes(self, rhs)), + pub fn str(val: String, types: &TypeBag) -> Self { + Self { + variant: ValueVariant::Str(val), + typ: types.str(), } } - pub fn gte(self, rhs: Value) -> Result<Value, OperationError> { - 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)), - r => Err(OperationError::CompareTypes(self, r)), - }, - Value::Int(r) => match rhs { - Value::Float(l) => Ok(Value::Bool(r as f64 >= l)), - Value::Int(l) => Ok(Value::Bool(r >= l)), - r => Err(OperationError::CompareTypes(self, r)), - }, - _ => Err(OperationError::CompareTypes(self, rhs)), + pub fn int(val: i64, types: &TypeBag) -> Self { + Self { + variant: ValueVariant::Int(val), + typ: types.int(), } } - pub fn neg(self) -> Result<Value, OperationError> { - match self { - Value::Float(float) => Ok(Value::Float(-float)), - Value::Int(int) => Ok(Value::Int(-int)), - _ => Err(OperationError::NegType(self)), + pub fn float(val: f64, types: &TypeBag) -> Self { + Self { + variant: ValueVariant::Float(val), + typ: types.float(), } } - pub fn not(self) -> Result<Value, OperationError> { - match self { - Value::Bool(bool) => Ok(Value::Bool(bool)), - _ => Err(OperationError::NotType(self)), + pub fn bool(val: bool, types: &TypeBag) -> Self { + Self { + variant: ValueVariant::Bool(val), + typ: types.bool(), } } - pub fn subscript(self, index: Value) -> Result<Value, OperationError> { - let index = match index { - Value::Int(i) => i, - i => return Err(OperationError::ArrayIndexType(i)), - }; - - match self { - Value::Array(a) => { - let array = a.borrow(); - if index < 0 || index as usize >= array.len() { - Err(OperationError::ArrayIndexOutOfRange { - index, - length: array.len(), - }) - } else { - Ok(array[index as usize].clone()) - } - } - // Maybe allow string subscripts? - x => Err(OperationError::ArrayType(x.clone())), - } - } - - pub fn subscript_assign( - &mut self, - index: Value, - value: Value, - ) -> Result<Value, OperationError> { - let index = match index { - Value::Int(i) => i, - i => return Err(OperationError::ArrayIndexType(i)), - }; - - match self { - Value::Array(a) => { - let mut array = a.borrow_mut(); - if index < 0 || index as usize >= array.len() { - Err(OperationError::ArrayIndexOutOfRange { - index, - length: array.len(), - }) - } else { - array[index as usize] = value; - Ok(array[index as usize].clone()) - } - } - x => Err(OperationError::ArrayType(x.clone())), + pub fn void(types: &TypeBag) -> Self { + Self { + variant: ValueVariant::Void, + typ: types.void(), } } - pub fn call(&self, arguments: Vec<Value>) -> Result<Value, WalkerError> { - let called = match self { - Value::Fn(i) => i, - i => { - return Err(WalkerError::OperationError(OperationError::CallableType( - i.clone(), - ))) - } - } - .borrow(); - - // FIXME: Currently closures are able to re-assign values from the upper scopes. - // This is good behaviour, until a closure re-assigns a value that was declared after - // the closure even existed. - // Minimal reproducible example: - // ```rh - // closure = fn { y = 10; }; - // y = 1; - // closure(); - // print y; - // ``` - // Expected: 1 - // Actual: 10 - let mut scope = called.scope.clone(); - scope.nest(); - - let parameters = &called.node.header.parameters; - - if parameters.len() != arguments.len() { - return Err(WalkerError::OperationError( - OperationError::WrongArgumentCount(parameters.len(), arguments.len()), - )); - } - - for (argument, parameter) in arguments.into_iter().zip(parameters.iter()) { - scope.set_var_shadowed(¶meter.identifier, argument); - } - - // Yes, we create a new walker for every function call, - // it's *way* easier that way. - let mut walker = Walker::new_with_scope(scope); - let result = walker.walk_expression(&Expression::Block(Box::new(called.node.body.clone()))); - - if let Err(WalkerError::Return(returned)) = result { - Ok(returned) - } else { - result - } - } -} - -impl Value { pub fn type_name(&self) -> &'static str { - match self { - Value::Str(_) => "Str", - Value::Float(_) => "Float", - Value::Int(_) => "Int", - Value::Bool(_) => "Bool", - Value::Array(_) => "Array", - Value::Fn(_) => "Fn", - Value::Void => "Void", + // TODO: Base this off of the type. + match self.variant { + ValueVariant::Str(_) => "Str", + ValueVariant::Float(_) => "Float", + ValueVariant::Int(_) => "Int", + ValueVariant::Bool(_) => "Bool", + ValueVariant::Array(_) => "Array", + ValueVariant::Fn(_) => "Fn", + ValueVariant::Void => "Void", + _ => todo!(), } } } impl Display for Value { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Value::Str(v) => write!(f, "{}", v), - Value::Float(v) => write!(f, "{}", v), - Value::Int(v) => write!(f, "{}", v), - Value::Bool(v) => write!(f, "{}", v), - Value::Array(a) => { + match &self.variant { + ValueVariant::Str(v) => write!(f, "{}", v), + ValueVariant::Float(v) => write!(f, "{}", v), + ValueVariant::Int(v) => write!(f, "{}", v), + ValueVariant::Bool(v) => write!(f, "{}", v), + ValueVariant::Array(a) => { write!( f, "[{}]", @@ -303,8 +95,9 @@ impl Display for Value { .join(", ") ) } - Value::Fn(v) => write!(f, "<fn {:?}>", v.as_ptr()), - Value::Void => write!(f, "<void>"), + ValueVariant::Fn(v) => write!(f, "<fn {:?}>", v.as_ptr()), + ValueVariant::Void => write!(f, "<void>"), + _ => todo!(), } } } @@ -315,30 +108,4 @@ pub struct FnValue { pub scope: ScopeChain, } -#[derive(Error, Debug)] -pub enum OperationError { - #[error("Can't add value '{0}' of type '{}' to value '{1}' of type '{}'.", .0.type_name(), .1.type_name())] - AddTypes(Value, Value), - #[error("Can't subtract value '{1}' of type '{}' from value '{0}' of type '{}'.", .1.type_name(), .0.type_name())] - SubTypes(Value, Value), - #[error("Can't multiply value '{0}' of type '{}' with value '{1}' of type '{}'.", .0.type_name(), .1.type_name())] - MulTypes(Value, Value), - #[error("Can't divide value '{0}' of type '{}' by value '{1}' of type '{}'.", .0.type_name(), .1.type_name())] - DivTypes(Value, Value), - #[error("Can't compare value '{0}' of type '{}' with value '{1}' of type '{}'.", .0.type_name(), .1.type_name())] - CompareTypes(Value, Value), - #[error("Can't negate value '{0}' of type '{}'.", .0.type_name())] - NegType(Value), - #[error("Can't flip value '{0}' of type '{}'.", .0.type_name())] - NotType(Value), - #[error("Can't use value '{0}' of type '{}' as a subsript index.", .0.type_name())] - ArrayIndexType(Value), - #[error("Can't subscript value '{0}' of type '{}'.", .0.type_name())] - ArrayType(Value), - #[error("Array index '{index}' out of range for array of length '{length}'.")] - ArrayIndexOutOfRange { index: i64, length: usize }, - #[error("Can't call value '{0}' of type '{}'.", .0.type_name())] - CallableType(Value), - #[error("Function expects {0} arguments, but {1} were given.")] - WrongArgumentCount(usize, usize), -} +pub type ValueMap = HashMap<Identifier, Value>; diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs index 15ab37d..171f4d1 100644 --- a/src/interpret/walker.rs +++ b/src/interpret/walker.rs @@ -1,7 +1,10 @@ -use std::{cell::RefCell, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; use crate::{ - interpret::value::FnValue, + interpret::{ + operator::ValueOperator, + value::{FnValue, ValueVariant}, + }, parse::ast::{ expression::Expression, nodes::{ @@ -10,27 +13,32 @@ use crate::{ statement::Statement, Program, }, + types::{bag::TypeBag, TypeVariant}, }; use thiserror::Error; use super::{ + operator::OperationError, scope::{ScopeChain, ScopeError}, - value::{OperationError, Value}, + value::Value, }; pub struct Walker { + types: TypeBag, scope: ScopeChain, } impl Walker { - pub fn new() -> Self { + // Should preferably be called only once. + pub fn root() -> Self { Walker { scope: ScopeChain::new(), + types: TypeBag::new(), } } - pub fn new_with_scope(scope: ScopeChain) -> Self { - Walker { scope } + pub fn new(scope: ScopeChain, types: TypeBag) -> Self { + Walker { scope, types } } pub fn walk(&mut self, program: &Program) { @@ -85,17 +93,17 @@ impl Walker { // Short-circuting operators if let BinOp::And | BinOp::Or = op { let left_value = self.walk_expression(left)?; - let is_left_true = match left_value { - Value::Bool(bool) => bool, + let is_left_true = match left_value.variant { + ValueVariant::Bool(bool) => bool, _ => return Err(WalkerError::WrongAndOrType), }; if let BinOp::And = op { if !is_left_true { - return Ok(Value::Bool(false)); + return Ok(Value::bool(false, &self.types)); } } else if is_left_true { - return Ok(Value::Bool(true)); + return Ok(Value::bool(true, &self.types)); } return self.walk_expression(right); @@ -104,19 +112,21 @@ impl Walker { let left = self.walk_expression(left)?; let right = self.walk_expression(right)?; + let exe = ValueOperator::new(&self.types); + // Other operators match op { - BinOp::Plus => left.add(right), - BinOp::Minus => left.sub(right), - BinOp::Star => left.mul(right), - BinOp::Slash => left.div(right), + BinOp::Plus => exe.add(left, right), + BinOp::Minus => exe.sub(left, right), + BinOp::Star => exe.mul(left, right), + BinOp::Slash => exe.div(left, right), BinOp::Dot => todo!("Structures not implemented yet."), - 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), + BinOp::Eq => exe.eq(left, right), + BinOp::Neq => exe.neq(left, right), + BinOp::Gt => exe.gt(left, right), + BinOp::Gte => exe.gte(left, right), + BinOp::Lt => exe.gt(right, left), + BinOp::Lte => exe.gte(right, left), _ => unreachable!(), } @@ -125,9 +135,11 @@ impl Walker { Expression::Unary { op, right } => { let value = self.walk_expression(right)?; + let exe = ValueOperator::new(&self.types); + match op { - UnOp::Minus => value.neg(), - UnOp::Not => value.not(), + UnOp::Minus => exe.neg(value), + UnOp::Not => exe.not(value), } .map_err(WalkerError::OperationError) } @@ -139,12 +151,16 @@ impl Walker { argument_values.push(self.walk_expression(argument_node)?); } - called.call(argument_values) + let exe = ValueOperator::new(&self.types); + exe.call(&called, argument_values) } Expression::ArrayAccess(node) => { let array = self.walk_expression(&node.array)?; let index = self.walk_expression(&node.index)?; - array.subscript(index).map_err(WalkerError::OperationError) + + let exe = ValueOperator::new(&self.types); + exe.subscript(array, index) + .map_err(WalkerError::OperationError) } Expression::MemberAccess(_) => todo!("Structures not implemented yet."), Expression::Group(node) => self.walk_expression(node), @@ -153,13 +169,19 @@ impl Walker { for expression in &node.elements { elements.push(self.walk_expression(expression)?); } - Ok(Value::Array(Rc::new(RefCell::new(elements)))) + Ok(Value { + variant: ValueVariant::Array(Rc::new(RefCell::new(elements))), + // FIXME: Use actual type. + typ: self + .types + .create_type(TypeVariant::Array(self.types.void())), + }) } Expression::SimpleLiteral(token) => { let value = match token { - SimpleLiteral::Int(int) => Value::Int(*int as i64), - SimpleLiteral::Float(float) => Value::Float(*float as f64), - SimpleLiteral::Bool(bool) => Value::Bool(*bool), + SimpleLiteral::Int(int) => Value::int(*int as i64, &self.types), + SimpleLiteral::Float(float) => Value::float(*float as f64, &self.types), + SimpleLiteral::Bool(bool) => Value::bool(*bool, &self.types), }; Ok(value) @@ -177,15 +199,24 @@ impl Walker { }; } - Ok(Value::Str(buffer)) + Ok(Value::str(buffer, &self.types)) } - Expression::FnLiteral(node) => Ok(Value::Fn(Rc::new(RefCell::new(FnValue { - node: node.as_ref().clone(), - scope: self.scope.clone(), - })))), + Expression::FnLiteral(node) => Ok(Value { + variant: ValueVariant::Fn(Rc::new(RefCell::new(FnValue { + node: node.as_ref().clone(), + scope: self.scope.clone(), + }))), + // FIXME: Use actual type here. + typ: self.types.create_type(TypeVariant::Fn { + parameters: HashMap::new(), + returns: self.types.void(), + }), + }), Expression::If(if_node) => { for conditional in &if_node.conditionals { - if let Value::Bool(bool) = self.walk_expression(&conditional.condition)? { + if let ValueVariant::Bool(bool) = + self.walk_expression(&conditional.condition)?.variant + { if bool { return self.walk_block(&conditional.block); } @@ -197,17 +228,19 @@ impl Walker { if let Some(else_conditional) = &if_node.else_block { self.walk_block(else_conditional) } else { - Ok(Value::Void) + Ok(Value::void(&self.types)) } } Expression::Loop(loop_node) => { if let Some(condition) = &loop_node.condition { loop { - if let Value::Bool(should_repeat) = self.walk_expression(condition)? { + if let ValueVariant::Bool(should_repeat) = + self.walk_expression(condition)?.variant + { if should_repeat { match self.walk_block(&loop_node.body) { Err(WalkerError::LoopBreak(loop_value)) => { - return Ok(loop_value.unwrap_or(Value::Void)); + return Ok(loop_value.unwrap_or(Value::void(&self.types))); } // Do nothing for continue and continue looping of course, you dummy. Err(WalkerError::LoopContinue) => {} @@ -216,7 +249,7 @@ impl Walker { _ => {} } } else { - return Ok(Value::Void); + return Ok(Value::void(&self.types)); } } else { return Err(WalkerError::WrongLoopConditionType); @@ -227,7 +260,7 @@ impl Walker { loop { match self.walk_block(&loop_node.body) { Err(WalkerError::LoopBreak(loop_value)) => { - break Ok(loop_value.unwrap_or(Value::Void)); + break Ok(loop_value.unwrap_or(Value::void(&self.types))); } Err(WalkerError::LoopContinue) => {} Err(x) => return Err(x), @@ -236,9 +269,10 @@ impl Walker { } } } - Expression::Identifier(ident) => { - self.scope.get_var(ident).map_err(WalkerError::ScopeError) - } + Expression::Identifier(ident) => self + .scope + .get_var(ident, &self.types) + .map_err(WalkerError::ScopeError), } } @@ -252,7 +286,7 @@ impl Walker { let result = if let Some(tail_expression) = &block.tail_expression { Ok(self.walk_expression(tail_expression)?) } else { - Ok(Value::Void) + Ok(Value::void(&self.types)) }; self.scope.unnest(); @@ -274,8 +308,9 @@ impl Walker { let index = self.walk_expression(&node.index)?; let value = self.walk_expression(rvalue)?; - array - .subscript_assign(index, value) + let exe = ValueOperator::new(&self.types); + + exe.subscript_assign(&mut array, index, value) .map_err(WalkerError::OperationError) } Expression::Identifier(ident) => { |
