Add parent contexts and core library
This commit is contained in:
parent
83f856385b
commit
2e7acbeb64
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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),
|
||||
),
|
||||
),
|
||||
]))
|
||||
})
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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(()),
|
||||
|
@ -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())),
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user