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,
|
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.
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
),
|
||||||
|
),
|
||||||
]))
|
]))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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};
|
||||||
|
@ -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(()),
|
||||||
|
@ -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())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user