Add plumbing and test

This commit is contained in:
Jeff 2024-02-25 14:26:22 -05:00
parent 8ff4b4ba82
commit fb7675a782
7 changed files with 106 additions and 8 deletions

View File

@ -2,7 +2,7 @@ use crate::{error::RuntimeError, Context};
use super::{AbstractTree, Identifier, Statement, Value};
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Assignment {
identifier: Identifier,
statement: Box<Statement>,

View File

@ -2,7 +2,7 @@ use crate::{context::Context, error::RuntimeError};
use super::{AbstractTree, Statement, Value};
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Block {
statements: Vec<Statement>,
}

View File

@ -2,7 +2,7 @@ use crate::{context::Context, error::RuntimeError};
use super::{AbstractTree, Statement, Value};
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Logic {
Equal(Statement, Statement),
NotEqual(Statement, Statement),
@ -16,7 +16,40 @@ pub enum Logic {
}
impl AbstractTree for Logic {
fn run(self, _: &Context) -> Result<Value, RuntimeError> {
todo!()
fn run(self, _context: &Context) -> Result<Value, RuntimeError> {
let boolean = match self {
Logic::Equal(left, right) => left.run(_context)? == right.run(_context)?,
Logic::NotEqual(left, right) => left.run(_context)? != right.run(_context)?,
Logic::Greater(left, right) => left.run(_context)? > right.run(_context)?,
Logic::Less(left, right) => left.run(_context)? < right.run(_context)?,
Logic::GreaterOrEqual(left, right) => left.run(_context)? >= right.run(_context)?,
Logic::LessOrEqual(left, right) => left.run(_context)? <= right.run(_context)?,
Logic::And(left, right) => {
left.run(_context)?.as_boolean()? && right.run(_context)?.as_boolean()?
}
Logic::Or(left, right) => {
left.run(_context)?.as_boolean()? || right.run(_context)?.as_boolean()?
}
Logic::Not(statement) => !statement.run(_context)?.as_boolean()?,
};
Ok(Value::boolean(boolean))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn equal() {
assert!(Logic::Equal(
Statement::Value(Value::integer(42)),
Statement::Value(Value::integer(42)),
)
.run(&Context::new())
.unwrap()
.as_boolean()
.unwrap())
}
}

View File

@ -2,7 +2,7 @@ use crate::{context::Context, error::RuntimeError};
use super::{AbstractTree, Block, Value};
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct Loop {
block: Block,
}

View File

@ -2,7 +2,7 @@ use crate::{context::Context, error::RuntimeError};
use super::{AbstractTree, Assignment, Block, Identifier, Logic, Loop, Value};
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement {
Assignment(Assignment),
Block(Block),

View File

@ -1,4 +1,5 @@
use std::{
cmp::Ordering,
collections::BTreeMap,
ops::Range,
sync::{Arc, OnceLock},
@ -59,6 +60,28 @@ impl Value {
pub fn r#enum(r#enum: EnumInstance) -> Self {
Value(Arc::new(ValueInner::Enum(r#enum)))
}
pub fn as_boolean(&self) -> Result<bool, RuntimeError> {
if let ValueInner::Boolean(boolean) = self.0.as_ref() {
return Ok(*boolean);
}
Err(RuntimeError::ExpectedBoolean)
}
}
impl Eq for Value {}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Value {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.as_ref().cmp(other.0.as_ref())
}
}
#[derive(Clone, Debug, PartialEq)]
@ -73,7 +96,48 @@ pub enum ValueInner {
Enum(EnumInstance),
}
#[derive(Clone, Debug, PartialEq)]
impl Eq for ValueInner {}
impl PartialOrd for ValueInner {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ValueInner {
fn cmp(&self, other: &Self) -> Ordering {
use ValueInner::*;
match (self, other) {
(Boolean(left), Boolean(right)) => left.cmp(right),
(Boolean(_), _) => Ordering::Greater,
(Float(left), Float(right)) => left.total_cmp(right),
(Float(_), _) => Ordering::Greater,
(Integer(left), Integer(right)) => left.cmp(right),
(Integer(_), _) => Ordering::Greater,
(List(left), List(right)) => left.cmp(right),
(List(_), _) => Ordering::Greater,
(Map(left), Map(right)) => left.cmp(right),
(Map(_), _) => Ordering::Greater,
(Range(left), Range(right)) => {
let start_cmp = left.start.cmp(&right.start);
if start_cmp.is_eq() {
left.end.cmp(&right.end)
} else {
start_cmp
}
}
(Range(_), _) => Ordering::Greater,
(String(left), String(right)) => left.cmp(right),
(String(_), _) => Ordering::Greater,
(Enum(left), Enum(right)) => left.cmp(right),
(Enum(_), _) => Ordering::Greater,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct EnumInstance {
type_name: Identifier,
variant: Identifier,

View File

@ -32,6 +32,7 @@ impl<'src> From<RuntimeError> for Error<'src> {
#[derive(Debug, PartialEq)]
pub enum RuntimeError {
RwLockPoison(RwLockPoisonError),
ExpectedBoolean,
}
impl From<RwLockPoisonError> for RuntimeError {