Add and pass test

This commit is contained in:
Jeff 2024-03-06 18:15:25 -05:00
parent 4db3ae7cb8
commit bff5ba81a3
5 changed files with 78 additions and 18 deletions

View File

@ -29,10 +29,14 @@ impl<'src> AbstractTree for Assignment<'src> {
} }
fn validate(&self, context: &Context) -> Result<(), ValidationError> { fn validate(&self, context: &Context) -> Result<(), ValidationError> {
if let Some(expected) = &self.r#type { let statement_type = self.statement.expected_type(context)?;
let statement_type = self.statement.expected_type(context)?;
if let Some(expected) = &self.r#type {
expected.check(&statement_type)?; expected.check(&statement_type)?;
context.set_type(self.identifier.clone(), expected.clone())?;
} else {
context.set_type(self.identifier.clone(), statement_type)?;
} }
Ok(()) Ok(())
@ -41,7 +45,7 @@ impl<'src> AbstractTree for Assignment<'src> {
fn run(self, context: &Context) -> Result<Value, RuntimeError> { fn run(self, context: &Context) -> Result<Value, RuntimeError> {
let value = self.statement.run(context)?; let value = self.statement.run(context)?;
context.set(self.identifier, value)?; context.set_value(self.identifier, value)?;
Ok(Value::none()) Ok(Value::none())
} }
@ -69,7 +73,7 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
context.get(&Identifier::new("foobar")), context.get_value(&Identifier::new("foobar")),
Ok(Some(Value::integer(42))) Ok(Some(Value::integer(42)))
) )
} }

View File

@ -26,15 +26,15 @@ impl Identifier {
impl AbstractTree for Identifier { impl AbstractTree for Identifier {
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
if let Some(value) = context.get(self)? { if let Some(r#type) = context.get_type(self)? {
Ok(value.r#type()) Ok(r#type)
} else { } else {
Err(ValidationError::VariableNotFound(self.clone())) Err(ValidationError::VariableNotFound(self.clone()))
} }
} }
fn validate(&self, context: &Context) -> Result<(), ValidationError> { fn validate(&self, context: &Context) -> Result<(), ValidationError> {
if let Some(_) = context.get(self)? { if let Some(_) = context.get_data(self)? {
Ok(()) Ok(())
} else { } else {
Err(ValidationError::VariableNotFound(self.clone())) Err(ValidationError::VariableNotFound(self.clone()))
@ -42,7 +42,10 @@ impl AbstractTree for Identifier {
} }
fn run(self, context: &Context) -> Result<Value, RuntimeError> { fn run(self, context: &Context) -> Result<Value, RuntimeError> {
let value = context.get(&self)?.unwrap_or_else(Value::none).clone(); let value = context
.get_value(&self)?
.unwrap_or_else(Value::none)
.clone();
Ok(value) Ok(value)
} }

View File

@ -3,10 +3,20 @@ use std::{
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}; };
use crate::{abstract_tree::Identifier, error::RwLockPoisonError, Value}; use crate::{
abstract_tree::{Identifier, Type},
error::RwLockPoisonError,
Value,
};
pub struct Context { pub struct Context {
inner: Arc<RwLock<BTreeMap<Identifier, Value>>>, inner: Arc<RwLock<BTreeMap<Identifier, ValueData>>>,
}
#[derive(Clone, Debug)]
pub enum ValueData {
Type(Type),
Value(Value),
} }
impl Context { impl Context {
@ -16,20 +26,47 @@ impl Context {
} }
} }
pub fn with_values(values: BTreeMap<Identifier, Value>) -> Self { pub fn with_data(data: BTreeMap<Identifier, ValueData>) -> Self {
Self { Self {
inner: Arc::new(RwLock::new(values)), inner: Arc::new(RwLock::new(data)),
} }
} }
pub fn get(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> { pub fn get_data(
let value = self.inner.read()?.get(identifier).cloned(); &self,
identifier: &Identifier,
Ok(value) ) -> Result<Option<ValueData>, RwLockPoisonError> {
Ok(self.inner.read()?.get(identifier).cloned())
} }
pub fn set(&self, identifier: Identifier, value: Value) -> Result<(), RwLockPoisonError> { pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockPoisonError> {
self.inner.write()?.insert(identifier, value); if let Some(ValueData::Type(r#type)) = self.inner.read()?.get(identifier) {
Ok(Some(r#type.clone()))
} else {
Ok(None)
}
}
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) {
Ok(Some(value.clone()))
} else {
Ok(None)
}
}
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), RwLockPoisonError> {
self.inner
.write()?
.insert(identifier, ValueData::Type(r#type));
Ok(())
}
pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), RwLockPoisonError> {
self.inner
.write()?
.insert(identifier, ValueData::Value(value));
Ok(()) Ok(())
} }

View File

@ -12,6 +12,13 @@ use lexer::lex;
pub use parser::{parse, parser, DustParser}; pub use parser::{parse, parser, DustParser};
pub use value::Value; pub use value::Value;
pub fn interpret(source: &str) -> Result<Value, Vec<Error>> {
let context = Context::new();
let mut interpreter = Interpreter::new(context);
interpreter.run(source)
}
pub struct Interpreter { pub struct Interpreter {
context: Context, context: Context,
} }

9
tests/variables.rs Normal file
View File

@ -0,0 +1,9 @@
use dust_lang::*;
#[test]
fn set_and_get_variable() {
assert_eq!(
interpret("foobar = true foobar"),
Ok(Value::boolean(true))
);
}