Add and pass test
This commit is contained in:
parent
4db3ae7cb8
commit
bff5ba81a3
@ -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)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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
9
tests/variables.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use dust_lang::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_and_get_variable() {
|
||||||
|
assert_eq!(
|
||||||
|
interpret("foobar = true foobar"),
|
||||||
|
Ok(Value::boolean(true))
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user