Add parent contexts and core library

This commit is contained in:
Jeff 2024-08-20 11:40:37 -04:00
parent 83f856385b
commit 2e7acbeb64
7 changed files with 124 additions and 27 deletions

View File

@ -16,8 +16,7 @@ use crate::{
LoopExpression, MapExpression, Node, OperatorExpression, RangeExpression, Span, Statement, LoopExpression, MapExpression, Node, OperatorExpression, RangeExpression, Span, Statement,
StructDefinition, StructExpression, TupleAccessExpression, StructDefinition, StructExpression, TupleAccessExpression,
}, },
context::ContextError, parse, Context, ContextError, DustError, Expression, Identifier, StructType, Type,
parse, Context, DustError, Expression, Identifier, StructType, Type,
}; };
/// Analyzes the abstract syntax tree for errors. /// Analyzes the abstract syntax tree for errors.

View File

@ -13,6 +13,7 @@ pub type Associations = HashMap<Identifier, (ContextData, Span)>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Context { pub struct Context {
associations: Arc<RwLock<Associations>>, associations: Arc<RwLock<Associations>>,
parent: Option<Box<Context>>,
} }
impl Context { impl Context {
@ -23,6 +24,7 @@ impl Context {
pub fn with_data(data: Associations) -> Self { pub fn with_data(data: Associations) -> Self {
Self { Self {
associations: Arc::new(RwLock::new(data)), associations: Arc::new(RwLock::new(data)),
parent: None,
} }
} }
@ -31,6 +33,13 @@ impl Context {
Ok(Self::with_data(other.associations.read()?.clone())) 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. /// Returns the number of associated identifiers in the context.
pub fn association_count(&self) -> Result<usize, ContextError> { pub fn association_count(&self) -> Result<usize, ContextError> {
Ok(self.associations.read()?.len()) Ok(self.associations.read()?.len())
@ -53,23 +62,30 @@ impl Context {
/// Returns the type associated with the given identifier. /// Returns the type associated with the given identifier.
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ContextError> { pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, ContextError> {
let r#type = match self.associations.read()?.get(identifier) { match self.associations.read()?.get(identifier) {
Some((ContextData::VariableType(r#type), _)) => r#type.clone(), Some((ContextData::VariableType(r#type), _)) => return Ok(Some(r#type.clone())),
Some((ContextData::VariableValue(value), _)) => value.r#type(), Some((ContextData::VariableValue(value), _)) => return Ok(Some(value.r#type())),
Some((ContextData::ConstructorType(struct_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. /// Returns the ContextData associated with the identifier.
pub fn get_data(&self, identifier: &Identifier) -> Result<Option<ContextData>, ContextError> { pub fn get_data(&self, identifier: &Identifier) -> Result<Option<ContextData>, ContextError> {
match self.associations.read()?.get(identifier) { if let Some((variable_data, _)) = self.associations.read()?.get(identifier) {
Some((variable_data, _)) => Ok(Some(variable_data.clone())), Ok(Some(variable_data.clone()))
_ => Ok(None), } else if let Some(parent) = &self.parent {
parent.get_data(identifier)
} else {
Ok(None)
} }
} }
@ -78,9 +94,14 @@ impl Context {
&self, &self,
identifier: &Identifier, identifier: &Identifier,
) -> Result<Option<Value>, ContextError> { ) -> Result<Option<Value>, ContextError> {
match self.associations.read().unwrap().get(identifier) { if let Some((ContextData::VariableValue(value), _)) =
Some((ContextData::VariableValue(value), _)) => Ok(Some(value.clone())), self.associations.read()?.get(identifier)
_ => Ok(None), {
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, &self,
identifier: &Identifier, identifier: &Identifier,
) -> Result<Option<Constructor>, ContextError> { ) -> Result<Option<Constructor>, ContextError> {
match self.associations.read().unwrap().get(identifier) { if let Some((ContextData::Constructor(constructor), _)) =
Some((ContextData::Constructor(constructor), _)) => Ok(Some(constructor.clone())), self.associations.read()?.get(identifier)
_ => Ok(None), {
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(); env_logger::builder().is_test(true).try_init().unwrap();
let source = " let source = "
x = 5 let x = 5;
y = 10 let y = 10;
z = x + y let z = x + y;
z z
"; ";
let context = Context::new(); let context = Context::new();
@ -319,8 +345,8 @@ mod tests {
#[test] #[test]
fn garbage_collector_does_not_break_loops() { fn garbage_collector_does_not_break_loops() {
let source = " let source = "
y = 1 let y = 1;
z = 0 let mut z = 0;
while z < 10 { while z < 10 {
z = z + y z = z + y
} }

View File

@ -4,7 +4,7 @@ use crate::{BuiltInFunction, Context, ContextData, Function, Identifier, Value};
static CORE_LIBRARY: OnceLock<Context> = OnceLock::new(); static CORE_LIBRARY: OnceLock<Context> = OnceLock::new();
pub fn core_library() -> &'static Context { pub fn core_library<'a>() -> &'a Context {
CORE_LIBRARY.get_or_init(|| { CORE_LIBRARY.get_or_init(|| {
Context::with_data(HashMap::from([ Context::with_data(HashMap::from([
( (
@ -25,6 +25,24 @@ pub fn core_library() -> &'static Context {
(0, 0), (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),
),
),
])) ]))
}) })
} }

View File

@ -35,6 +35,7 @@ pub use ast::{AbstractSyntaxTree, Expression, Span, Statement};
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};
pub use constructor::Constructor; pub use constructor::Constructor;
pub use context::{Context, ContextData, ContextError}; pub use context::{Context, ContextData, ContextError};
pub use core_library::core_library;
pub use dust_error::DustError; pub use dust_error::DustError;
pub use identifier::Identifier; pub use identifier::Identifier;
pub use lexer::{lex, LexError, Lexer}; pub use lexer::{lex, LexError, Lexer};

View File

@ -79,6 +79,8 @@ impl Type {
(Type::Any, _) (Type::Any, _)
| (_, Type::Any) | (_, Type::Any)
| (Type::Boolean, Type::Boolean) | (Type::Boolean, Type::Boolean)
| (Type::Byte, Type::Byte)
| (Type::Character, Type::Character)
| (Type::Float, Type::Float) | (Type::Float, Type::Float)
| (Type::Integer, Type::Integer) | (Type::Integer, Type::Integer)
| (Type::String, Type::String) => return Ok(()), | (Type::String, Type::String) => return Ok(()),

View File

@ -327,6 +327,16 @@ impl Value {
left.add(&right) 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())), _ => Err(ValueError::CannotAdd(self.clone(), other.clone())),
} }
} }
@ -383,6 +393,16 @@ impl Value {
left.subtract(&right) 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())), _ => Err(ValueError::CannotSubtract(self.clone(), other.clone())),
} }
} }
@ -431,6 +451,16 @@ impl Value {
left.multiply(&right) 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())), _ => Err(ValueError::CannotMultiply(self.clone(), other.clone())),
} }
} }
@ -479,6 +509,16 @@ impl Value {
left.divide(&right) 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())), _ => Err(ValueError::CannotDivide(self.clone(), other.clone())),
} }
} }
@ -525,6 +565,16 @@ impl Value {
left.modulo(&right) 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())), _ => Err(ValueError::CannotModulo(self.clone(), other.clone())),
} }
} }

View File

@ -20,8 +20,9 @@ use crate::{
OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement, OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement,
StructDefinition, StructExpression, StructDefinition, StructExpression,
}, },
parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, ContextError, core_library, parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData,
DustError, Expression, Function, Identifier, ParseError, StructType, Type, Value, ValueError, ContextError, DustError, Expression, Function, Identifier, ParseError, StructType, Type, Value,
ValueError,
}; };
/// Run the source code and return the result. /// Run the source code and return the result.
@ -35,7 +36,7 @@ use crate::{
/// assert_eq!(result, Ok(Some(Value::Integer(42)))); /// assert_eq!(result, Ok(Some(Value::Integer(42))));
/// ``` /// ```
pub fn run(source: &str) -> Result<Option<Value>, DustError> { pub fn run(source: &str) -> Result<Option<Value>, DustError> {
let context = Context::new(); let context = core_library().create_child();
run_with_context(source, context) run_with_context(source, context)
} }