diff --git a/src/datapack/command/execute.rs b/src/datapack/command/execute.rs new file mode 100644 index 0000000..db2d746 --- /dev/null +++ b/src/datapack/command/execute.rs @@ -0,0 +1,113 @@ +use std::ops::{BitAnd, BitOr, Not}; + +use serde::{Deserialize, Serialize}; + +use super::Command; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Execute { + Align(String, Box), + Anchored(String, Box), + As(String, Box), + At(String, Box), + AsAt(String, Box), + Facing(String, Box), + In(String, Box), + On(String, Box), + Positioned(String, Box), + Rotated(String, Box), + Store(String, Box), + Summon(String, Box), + If(Condition, Box), + Run(String, Box), +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Condition { + Atom(String), + Not(Box), + And(Box, Box), + Or(Box, Box), +} +impl Condition { + pub fn normalize(self) -> Self { + match self { + Self::Atom(_) => self, + Self::Not(c) => match *c { + Self::Atom(c) => Self::Not(Box::new(Self::Atom(c))), + Self::Not(c) => c.normalize(), + Self::And(c1, c2) => ((!*c1).normalize()) | ((!*c2).normalize()), + Self::Or(c1, c2) => ((!*c1).normalize()) & ((!*c2).normalize()), + }, + Self::And(c1, c2) => c1.normalize() & c2.normalize(), + Self::Or(c1, c2) => c1.normalize() | c2.normalize(), + } + } +} + +impl Not for Condition { + type Output = Self; + + fn not(self) -> Self { + Condition::Not(Box::new(self)) + } +} +impl BitAnd for Condition { + type Output = Self; + + fn bitand(self, rhs: Self) -> Self { + Condition::And(Box::new(self), Box::new(rhs)) + } +} +impl BitOr for Condition { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + Condition::Or(Box::new(self), Box::new(rhs)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_condition() { + let c1 = Condition::Atom("foo".to_string()); + let c2 = Condition::Atom("bar".to_string()); + let c3 = Condition::Atom("baz".to_string()); + + assert_eq!( + (c1.clone() & c2.clone()).normalize(), + c1.clone() & c2.clone() + ); + assert_eq!( + (c1.clone() & c2.clone() & c3.clone()).normalize(), + c1.clone() & c2.clone() & c3.clone() + ); + assert_eq!( + (c1.clone() | c2.clone()).normalize(), + c1.clone() | c2.clone() + ); + assert_eq!( + (c1.clone() | c2.clone() | c3.clone()).normalize(), + c1.clone() | c2.clone() | c3.clone() + ); + assert_eq!( + (c1.clone() & c2.clone() | c3.clone()).normalize(), + c1.clone() & c2.clone() | c3.clone() + ); + assert_eq!( + (c1.clone() | c2.clone() & c3.clone()).normalize(), + c1.clone() | c2.clone() & c3.clone() + ); + assert_eq!( + (c1.clone() & c2.clone() | c3.clone() & c1.clone()).normalize(), + c1.clone() & c2.clone() | c3.clone() & c1.clone() + ); + assert_eq!( + (!(c1.clone() | c2.clone())).normalize(), + !c1.clone() & !c2.clone() + ); + } +} diff --git a/src/datapack/command.rs b/src/datapack/command/mod.rs similarity index 92% rename from src/datapack/command.rs rename to src/datapack/command/mod.rs index a3c431f..b9e6734 100644 --- a/src/datapack/command.rs +++ b/src/datapack/command/mod.rs @@ -1,5 +1,8 @@ //! Represents a command that can be included in a function. +mod execute; +pub use execute::Execute; + use serde::{Deserialize, Serialize}; use crate::util::compile::{CompileOptions, MutCompilerState, MutFunctionCompilerState}; @@ -11,6 +14,8 @@ pub enum Command { Raw(String), /// Message to be printed only in debug mode Debug(String), + /// Execute command + Execute(Execute), } impl Command { @@ -32,6 +37,7 @@ impl Command { match self { Self::Raw(command) => command.clone(), Self::Debug(message) => compile_debug(message, options), + Self::Execute(_) => todo!(), } } }