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,
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.

View File

@ -13,6 +13,7 @@ pub type Associations = HashMap<Identifier, (ContextData, Span)>;
#[derive(Debug, Clone)]
pub struct Context {
associations: Arc<RwLock<Associations>>,
parent: Option<Box<Context>>,
}
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<usize, ContextError> {
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<Option<Type>, 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<Option<ContextData>, 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<Option<Value>, 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<Option<Constructor>, 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
}

View File

@ -4,7 +4,7 @@ use crate::{BuiltInFunction, Context, ContextData, Function, Identifier, Value};
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(|| {
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),
),
),
]))
})
}

View File

@ -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};

View File

@ -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(()),

View File

@ -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())),
}
}

View File

@ -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<Option<Value>, DustError> {
let context = Context::new();
let context = core_library().create_child();
run_with_context(source, context)
}