1
0

Add logic tests

This commit is contained in:
Jeff 2024-02-28 18:36:47 -05:00
parent 95d9a720a3
commit 9d5b7b6606
4 changed files with 161 additions and 41 deletions

View File

@ -54,4 +54,115 @@ mod tests {
.as_boolean() .as_boolean()
.unwrap()) .unwrap())
} }
#[test]
fn not_equal() {
assert!(Logic::NotEqual(
Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::Integer(43)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap())
}
#[test]
fn greater() {
assert!(Logic::Greater(
Expression::Value(ValueNode::Integer(43)),
Expression::Value(ValueNode::Integer(42)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap())
}
#[test]
fn less() {
assert!(Logic::Less(
Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::Integer(43)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap())
}
#[test]
fn greater_or_equal() {
assert!(Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::Integer(41)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap());
assert!(Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::Integer(42)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap())
}
#[test]
fn less_or_equal() {
assert!(Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::Integer(43)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap());
assert!(Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::Integer(42)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap())
}
#[test]
fn and() {
assert!(Logic::And(
Expression::Value(ValueNode::Boolean(true)),
Expression::Value(ValueNode::Boolean(true)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap())
}
#[test]
fn or() {
assert!(Logic::Or(
Expression::Value(ValueNode::Boolean(true)),
Expression::Value(ValueNode::Boolean(false)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap())
}
#[test]
fn not() {
assert!(Logic::Not(Expression::Value(ValueNode::Boolean(false)))
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap())
}
} }

View File

@ -10,7 +10,7 @@ pub enum ValueNode<'src> {
Float(f64), Float(f64),
Integer(i64), Integer(i64),
List(Vec<Expression<'src>>), List(Vec<Expression<'src>>),
Map(BTreeMap<Identifier, Expression<'src>>), Map(Vec<(Identifier, Expression<'src>)>),
Range(Range<i64>), Range(Range<i64>),
String(&'src str), String(&'src str),
Enum(Identifier, Identifier), Enum(Identifier, Identifier),
@ -20,13 +20,33 @@ impl<'src> AbstractTree for ValueNode<'src> {
fn run(self, _context: &Context) -> Result<Value, RuntimeError> { fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
let value = match self { let value = match self {
ValueNode::Boolean(boolean) => Value::boolean(boolean), ValueNode::Boolean(boolean) => Value::boolean(boolean),
ValueNode::Float(float) => todo!(), ValueNode::Float(float) => Value::float(float),
ValueNode::Integer(integer) => todo!(), ValueNode::Integer(integer) => Value::integer(integer),
ValueNode::List(expression_list) => todo!(), ValueNode::List(expression_list) => {
ValueNode::Map(property_list) => todo!(), let mut value_list = Vec::with_capacity(expression_list.len());
ValueNode::Range(range) => todo!(),
ValueNode::String(string) => todo!(), for expression in expression_list {
ValueNode::Enum(name, variant) => todo!(), let value = expression.run(_context)?;
value_list.push(value);
}
Value::list(value_list)
}
ValueNode::Map(property_list) => {
let mut property_map = BTreeMap::new();
for (identifier, expression) in property_list {
let value = expression.run(_context)?;
property_map.insert(identifier, value);
}
Value::map(property_map)
}
ValueNode::Range(range) => Value::range(range),
ValueNode::String(string) => Value::string(string),
ValueNode::Enum(name, variant) => Value::r#enum(name, variant),
}; };
Ok(value) Ok(value)

View File

@ -47,11 +47,7 @@ pub fn lexer<'src>() -> impl Parser<
.then(text::int(10)) .then(text::int(10))
.to_slice() .to_slice()
.map(|text: &str| { .map(|text: &str| {
let integer = if let Ok(integer) = text.parse::<i64>() { let integer = text.parse::<i64>().unwrap();
integer
} else {
panic!("Failed to parse {text} as integer.");
};
Token::Integer(integer) Token::Integer(integer)
}); });

View File

@ -1,10 +1,11 @@
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::BTreeMap,
ops::Range, ops::Range,
sync::{Arc, OnceLock}, sync::{Arc, OnceLock},
}; };
use crate::error::RuntimeError; use crate::{abstract_tree::Identifier, error::RuntimeError};
pub static NONE: OnceLock<Value> = OnceLock::new(); pub static NONE: OnceLock<Value> = OnceLock::new();
@ -16,16 +17,6 @@ impl Value {
&self.0 &self.0
} }
pub fn none() -> Self {
NONE.get_or_init(|| {
Value::r#enum(EnumInstance {
type_name: "Option".to_string(),
variant: "None".to_string(),
})
})
.clone()
}
pub fn boolean(boolean: bool) -> Self { pub fn boolean(boolean: bool) -> Self {
Value(Arc::new(ValueInner::Boolean(boolean))) Value(Arc::new(ValueInner::Boolean(boolean)))
} }
@ -42,9 +33,9 @@ impl Value {
Value(Arc::new(ValueInner::List(list))) Value(Arc::new(ValueInner::List(list)))
} }
// pub fn map(map: BTreeMap<Identifier, Value>) -> Self { pub fn map(map: BTreeMap<Identifier, Value>) -> Self {
// Value(Arc::new(ValueInner::Map(map))) Value(Arc::new(ValueInner::Map(map)))
// } }
pub fn range(range: Range<i64>) -> Self { pub fn range(range: Range<i64>) -> Self {
Value(Arc::new(ValueInner::Range(range))) Value(Arc::new(ValueInner::Range(range)))
@ -54,8 +45,8 @@ impl Value {
Value(Arc::new(ValueInner::String(string.to_string()))) Value(Arc::new(ValueInner::String(string.to_string())))
} }
pub fn r#enum(r#enum: EnumInstance) -> Self { pub fn r#enum(name: Identifier, variant: Identifier) -> Self {
Value(Arc::new(ValueInner::Enum(r#enum))) Value(Arc::new(ValueInner::Enum(name, variant)))
} }
pub fn as_boolean(&self) -> Result<bool, RuntimeError> { pub fn as_boolean(&self) -> Result<bool, RuntimeError> {
@ -87,10 +78,10 @@ pub enum ValueInner {
Float(f64), Float(f64),
Integer(i64), Integer(i64),
List(Vec<Value>), List(Vec<Value>),
// Map(BTreeMap<Identifier, Value>), Map(BTreeMap<Identifier, Value>),
Range(Range<i64>), Range(Range<i64>),
String(String), String(String),
Enum(EnumInstance), Enum(Identifier, Identifier),
} }
impl Eq for ValueInner {} impl Eq for ValueInner {}
@ -114,8 +105,8 @@ impl Ord for ValueInner {
(Integer(_), _) => Ordering::Greater, (Integer(_), _) => Ordering::Greater,
(List(left), List(right)) => left.cmp(right), (List(left), List(right)) => left.cmp(right),
(List(_), _) => Ordering::Greater, (List(_), _) => Ordering::Greater,
// (Map(left), Map(right)) => left.cmp(right), (Map(left), Map(right)) => left.cmp(right),
// (Map(_), _) => Ordering::Greater, (Map(_), _) => Ordering::Greater,
(Range(left), Range(right)) => { (Range(left), Range(right)) => {
let start_cmp = left.start.cmp(&right.start); let start_cmp = left.start.cmp(&right.start);
@ -128,14 +119,16 @@ impl Ord for ValueInner {
(Range(_), _) => Ordering::Greater, (Range(_), _) => Ordering::Greater,
(String(left), String(right)) => left.cmp(right), (String(left), String(right)) => left.cmp(right),
(String(_), _) => Ordering::Greater, (String(_), _) => Ordering::Greater,
(Enum(left), Enum(right)) => left.cmp(right), (Enum(name_left, variant_left), Enum(name_right, variant_right)) => {
(Enum(_), _) => Ordering::Greater, let name_cmp = name_left.cmp(name_right);
if name_cmp.is_eq() {
variant_left.cmp(variant_right)
} else {
name_cmp
}
}
(Enum(..), _) => Ordering::Greater,
} }
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct EnumInstance {
type_name: String,
variant: String,
}