diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index 001e5d8..17b2eee 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -16,8 +16,7 @@ use crate::{ LoopExpression, MapExpression, Node, OperatorExpression, RangeExpression, Span, Statement, StructDefinition, StructExpression, TupleAccessExpression, }, - context::ContextError, - parse, Context, DustError, Expression, Identifier, StructType, Type, + parse, Context, ContextError, DustError, Expression, Identifier, StructType, Type, }; /// Analyzes the abstract syntax tree for errors. diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs index ce4c67e..f0aa1f1 100644 --- a/dust-lang/src/context.rs +++ b/dust-lang/src/context.rs @@ -13,6 +13,7 @@ pub type Associations = HashMap; #[derive(Debug, Clone)] pub struct Context { associations: Arc>, + parent: Option>, } impl Context { @@ -23,6 +24,7 @@ impl Context { pub fn with_data(data: Associations) -> Self { Self { associations: Arc::new(RwLock::new(data)), + parent: None, } } @@ -31,6 +33,13 @@ impl Context { Ok(Self::with_data(other.associations.read()?.clone())) } + pub fn create_child(&self) -> Self { + Self { + associations: Arc::new(RwLock::new(HashMap::new())), + parent: Some(Box::new(self.clone())), + } + } + /// Returns the number of associated identifiers in the context. pub fn association_count(&self) -> Result { Ok(self.associations.read()?.len()) @@ -53,23 +62,30 @@ impl Context { /// Returns the type associated with the given identifier. pub fn get_type(&self, identifier: &Identifier) -> Result, ContextError> { - let r#type = match self.associations.read()?.get(identifier) { - Some((ContextData::VariableType(r#type), _)) => r#type.clone(), - Some((ContextData::VariableValue(value), _)) => value.r#type(), + match self.associations.read()?.get(identifier) { + Some((ContextData::VariableType(r#type), _)) => return Ok(Some(r#type.clone())), + Some((ContextData::VariableValue(value), _)) => return Ok(Some(value.r#type())), Some((ContextData::ConstructorType(struct_type), _)) => { - Type::Struct(struct_type.clone()) + return Ok(Some(Type::Struct(struct_type.clone()))) } - _ => return Ok(None), - }; + _ => {} + } - Ok(Some(r#type)) + if let Some(parent) = &self.parent { + parent.get_type(identifier) + } else { + Ok(None) + } } /// Returns the ContextData associated with the identifier. pub fn get_data(&self, identifier: &Identifier) -> Result, ContextError> { - match self.associations.read()?.get(identifier) { - Some((variable_data, _)) => Ok(Some(variable_data.clone())), - _ => Ok(None), + if let Some((variable_data, _)) = self.associations.read()?.get(identifier) { + Ok(Some(variable_data.clone())) + } else if let Some(parent) = &self.parent { + parent.get_data(identifier) + } else { + Ok(None) } } @@ -78,9 +94,14 @@ impl Context { &self, identifier: &Identifier, ) -> Result, ContextError> { - match self.associations.read().unwrap().get(identifier) { - Some((ContextData::VariableValue(value), _)) => Ok(Some(value.clone())), - _ => Ok(None), + if let Some((ContextData::VariableValue(value), _)) = + self.associations.read()?.get(identifier) + { + Ok(Some(value.clone())) + } else if let Some(parent) = &self.parent { + parent.get_variable_value(identifier) + } else { + Ok(None) } } @@ -89,9 +110,14 @@ impl Context { &self, identifier: &Identifier, ) -> Result, ContextError> { - match self.associations.read().unwrap().get(identifier) { - Some((ContextData::Constructor(constructor), _)) => Ok(Some(constructor.clone())), - _ => Ok(None), + if let Some((ContextData::Constructor(constructor), _)) = + self.associations.read()?.get(identifier) + { + Ok(Some(constructor.clone())) + } else if let Some(parent) = &self.parent { + parent.get_constructor(identifier) + } else { + Ok(None) } } @@ -304,9 +330,9 @@ mod tests { env_logger::builder().is_test(true).try_init().unwrap(); let source = " - x = 5 - y = 10 - z = x + y + let x = 5; + let y = 10; + let z = x + y; z "; let context = Context::new(); @@ -319,8 +345,8 @@ mod tests { #[test] fn garbage_collector_does_not_break_loops() { let source = " - y = 1 - z = 0 + let y = 1; + let mut z = 0; while z < 10 { z = z + y } diff --git a/dust-lang/src/core_library.rs b/dust-lang/src/core_library.rs index 1b167b6..8b687db 100644 --- a/dust-lang/src/core_library.rs +++ b/dust-lang/src/core_library.rs @@ -4,7 +4,7 @@ use crate::{BuiltInFunction, Context, ContextData, Function, Identifier, Value}; static CORE_LIBRARY: OnceLock = OnceLock::new(); -pub fn core_library() -> &'static Context { +pub fn core_library<'a>() -> &'a Context { CORE_LIBRARY.get_or_init(|| { Context::with_data(HashMap::from([ ( @@ -25,6 +25,24 @@ pub fn core_library() -> &'static Context { (0, 0), ), ), + ( + Identifier::new("is_odd"), + ( + ContextData::VariableValue(Value::Function(Function::BuiltIn( + BuiltInFunction::IsOdd, + ))), + (0, 0), + ), + ), + ( + Identifier::new("length"), + ( + ContextData::VariableValue(Value::Function(Function::BuiltIn( + BuiltInFunction::Length, + ))), + (0, 0), + ), + ), ])) }) } diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index c078cac..9724948 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -35,6 +35,7 @@ pub use ast::{AbstractSyntaxTree, Expression, Span, Statement}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; pub use constructor::Constructor; pub use context::{Context, ContextData, ContextError}; +pub use core_library::core_library; pub use dust_error::DustError; pub use identifier::Identifier; pub use lexer::{lex, LexError, Lexer}; diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index b4a65c2..64bae35 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -79,6 +79,8 @@ impl Type { (Type::Any, _) | (_, Type::Any) | (Type::Boolean, Type::Boolean) + | (Type::Byte, Type::Byte) + | (Type::Character, Type::Character) | (Type::Float, Type::Float) | (Type::Integer, Type::Integer) | (Type::String, Type::String) => return Ok(()), diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index a8f049b..6818f82 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -327,6 +327,16 @@ impl Value { left.add(&right) } + (Value::Mutable(left), right) => { + let left = left.read().unwrap(); + + left.add(right) + } + (left, Value::Mutable(right)) => { + let right = right.read().unwrap(); + + left.add(&right) + } _ => Err(ValueError::CannotAdd(self.clone(), other.clone())), } } @@ -383,6 +393,16 @@ impl Value { left.subtract(&right) } + (Value::Mutable(left), right) => { + let left = left.read().unwrap(); + + left.subtract(right) + } + (left, Value::Mutable(right)) => { + let right = right.read().unwrap(); + + left.subtract(&right) + } _ => Err(ValueError::CannotSubtract(self.clone(), other.clone())), } } @@ -431,6 +451,16 @@ impl Value { left.multiply(&right) } + (Value::Mutable(left), right) => { + let left = left.read().unwrap(); + + left.multiply(right) + } + (left, Value::Mutable(right)) => { + let right = right.read().unwrap(); + + left.multiply(&right) + } _ => Err(ValueError::CannotMultiply(self.clone(), other.clone())), } } @@ -479,6 +509,16 @@ impl Value { left.divide(&right) } + (Value::Mutable(left), right) => { + let left = left.read().unwrap(); + + left.divide(right) + } + (left, Value::Mutable(right)) => { + let right = right.read().unwrap(); + + left.divide(&right) + } _ => Err(ValueError::CannotDivide(self.clone(), other.clone())), } } @@ -525,6 +565,16 @@ impl Value { left.modulo(&right) } + (Value::Mutable(left), right) => { + let left = left.read().unwrap(); + + left.modulo(right) + } + (left, Value::Mutable(right)) => { + let right = right.read().unwrap(); + + left.modulo(&right) + } _ => Err(ValueError::CannotModulo(self.clone(), other.clone())), } } diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 71351c8..58aaabf 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -20,8 +20,9 @@ use crate::{ OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition, StructExpression, }, - parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, ContextError, - DustError, Expression, Function, Identifier, ParseError, StructType, Type, Value, ValueError, + core_library, parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, + ContextError, DustError, Expression, Function, Identifier, ParseError, StructType, Type, Value, + ValueError, }; /// Run the source code and return the result. @@ -35,7 +36,7 @@ use crate::{ /// assert_eq!(result, Ok(Some(Value::Integer(42)))); /// ``` pub fn run(source: &str) -> Result, DustError> { - let context = Context::new(); + let context = core_library().create_child(); run_with_context(source, context) }