aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interpret/mod.rs5
-rw-r--r--src/interpret/operator.rs300
-rw-r--r--src/interpret/scope.rs38
-rw-r--r--src/interpret/value.rs341
-rw-r--r--src/interpret/walker.rs125
-rw-r--r--src/main.rs5
-rw-r--r--src/types/bag.rs123
-rw-r--r--src/types/mod.rs42
8 files changed, 632 insertions, 347 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(&parameter.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(&parameter.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) => {
diff --git a/src/main.rs b/src/main.rs
index 9128cdb..0df0483 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,6 +3,7 @@ use std::{env, fs, path::Path};
mod interpret;
mod lex;
mod parse;
+mod types;
use lex::lexer::Lexer;
@@ -27,7 +28,7 @@ fn file(filename: impl AsRef<Path>) {
let mut parser = Parser::new(lexer);
let node = parser.parse().expect("Failed parsing.");
- let mut walker = Walker::new();
+ let mut walker = Walker::root();
walker.walk(&node);
}
@@ -35,7 +36,7 @@ fn file(filename: impl AsRef<Path>) {
fn repl() {
const PROMPT: &str = "🐇: ";
- let mut walker = Walker::new();
+ let mut walker = Walker::root();
let mut input_buffer;
diff --git a/src/types/bag.rs b/src/types/bag.rs
new file mode 100644
index 0000000..30202fd
--- /dev/null
+++ b/src/types/bag.rs
@@ -0,0 +1,123 @@
+use std::{cell::RefCell, collections::HashMap};
+
+use super::{RefValueMap, Type, TypeVariant};
+
+#[derive(Clone)]
+pub struct TypeBag {
+ global_associated_values: &'static GlobalAssociatedValues,
+ atomic_types: AtomicTypes,
+}
+
+impl TypeBag {
+ pub fn new() -> Self {
+ // Hehe don't mind me
+ let leaked_values: &'static GlobalAssociatedValues =
+ Box::leak(Box::new(GlobalAssociatedValues::new()));
+ let atomic_types = AtomicTypes::new(&leaked_values);
+
+ TypeBag {
+ global_associated_values: leaked_values,
+ atomic_types,
+ }
+ }
+
+ pub fn create_type(&self, variant: TypeVariant) -> Type {
+ let global_associated_values_for_type = match variant {
+ TypeVariant::Fn { .. } => &self.global_associated_values.fn_values,
+ TypeVariant::Array(_) => &self.global_associated_values.array_values,
+ TypeVariant::Tuple(_) => &self.global_associated_values.tuple_values,
+ TypeVariant::Data { .. } => &self.global_associated_values.data_values,
+ TypeVariant::Str
+ | TypeVariant::Int
+ | TypeVariant::Float
+ | TypeVariant::Bool
+ | TypeVariant::Void => panic!("There should only be one type {:?}.", variant),
+ TypeVariant::Face(_) | TypeVariant::Var(_) => todo!("Implement abstract types."),
+ };
+
+ Type {
+ variant: Box::new(variant),
+ global_associated_values: global_associated_values_for_type,
+ }
+ }
+
+ pub fn str(&self) -> Type {
+ self.atomic_types.str_type.clone()
+ }
+
+ pub fn int(&self) -> Type {
+ self.atomic_types.int_type.clone()
+ }
+
+ pub fn float(&self) -> Type {
+ self.atomic_types.float_type.clone()
+ }
+
+ pub fn bool(&self) -> Type {
+ self.atomic_types.bool_type.clone()
+ }
+
+ pub fn void(&self) -> Type {
+ self.atomic_types.void_type.clone()
+ }
+}
+
+struct GlobalAssociatedValues {
+ str_values: RefValueMap,
+ int_values: RefValueMap,
+ float_values: RefValueMap,
+ bool_values: RefValueMap,
+ void_values: RefValueMap,
+ fn_values: RefValueMap,
+ array_values: RefValueMap,
+ tuple_values: RefValueMap,
+ data_values: RefValueMap,
+}
+
+impl GlobalAssociatedValues {
+ fn new() -> Self {
+ GlobalAssociatedValues {
+ str_values: Self::create_value_map(),
+ int_values: Self::create_value_map(),
+ float_values: Self::create_value_map(),
+ bool_values: Self::create_value_map(),
+ void_values: Self::create_value_map(),
+ fn_values: Self::create_value_map(),
+ array_values: Self::create_value_map(),
+ tuple_values: Self::create_value_map(),
+ data_values: Self::create_value_map(),
+ }
+ }
+
+ fn create_value_map() -> RefValueMap {
+ RefCell::new(HashMap::new())
+ }
+}
+
+#[derive(Clone)]
+struct AtomicTypes {
+ str_type: Type,
+ int_type: Type,
+ float_type: Type,
+ bool_type: Type,
+ void_type: Type,
+}
+
+impl AtomicTypes {
+ fn new(values: &'static GlobalAssociatedValues) -> Self {
+ AtomicTypes {
+ str_type: Self::create_single_type(TypeVariant::Str, &values.str_values),
+ int_type: Self::create_single_type(TypeVariant::Int, &values.int_values),
+ float_type: Self::create_single_type(TypeVariant::Float, &values.float_values),
+ bool_type: Self::create_single_type(TypeVariant::Bool, &values.bool_values),
+ void_type: Self::create_single_type(TypeVariant::Void, &values.void_values),
+ }
+ }
+
+ fn create_single_type(variant: TypeVariant, values: &'static RefValueMap) -> Type {
+ Type {
+ variant: Box::new(variant),
+ global_associated_values: values,
+ }
+ }
+}
diff --git a/src/types/mod.rs b/src/types/mod.rs
new file mode 100644
index 0000000..f3257eb
--- /dev/null
+++ b/src/types/mod.rs
@@ -0,0 +1,42 @@
+pub mod bag;
+
+use std::cell::RefCell;
+use std::collections::HashMap;
+
+use crate::interpret::value::ValueMap;
+use crate::parse::ast::nodes::Identifier;
+
+#[derive(Debug, Clone)]
+pub struct Type {
+ variant: Box<TypeVariant>,
+ global_associated_values: &'static RefValueMap,
+}
+
+#[derive(Debug, Clone)]
+pub enum TypeVariant {
+ // Concrete types
+ Str,
+ Int,
+ Float,
+ Bool,
+ Void,
+ Fn {
+ parameters: TypeMap,
+ returns: Type,
+ },
+ Array(Type),
+ Tuple(Vec<Type>),
+ Data {
+ data: TypeMap,
+ associated_values: RefValueMap,
+ },
+ // TODO: Implement abstract types.
+ // These should also definitely have `associated_values`,
+ // but as they're not implemented yet...
+ Face(TypeMap),
+ Var(TypeMap),
+}
+
+type TypeMap = HashMap<Identifier, Type>;
+
+type RefValueMap = RefCell<ValueMap>; \ No newline at end of file