use crate::get_compiler;
use std::marker::PhantomData;
pub trait Cast<T> {
fn cast(self) -> T;
}
pub trait True<T>: Cast<T> {}
pub trait Compile: Cast<Self> + Sized {
fn from_string(s: String) -> Self;
fn compile(&self) -> &str;
fn take(self) -> String;
}
pub trait Expr: Compile {}
pub enum Expression {
#[doc(hidden)]
CONST(&'static str),
#[doc(hidden)]
DYN(String),
}
impl Expression {
pub(crate) const fn new(expr: &'static str) -> Expression {
Expression::CONST(expr)
}
}
impl Expr for Expression {}
impl Compile for Expression {
fn from_string(s: String) -> Expression {
Expression::DYN(s)
}
fn compile(&self) -> &str {
match self {
Expression::CONST(value) => value,
Expression::DYN(value) => &value,
}
}
fn take(self) -> String {
match self {
Expression::CONST(value) => value.to_string(),
Expression::DYN(value) => value,
}
}
}
impl Cast<Self> for Expression {
fn cast(self) -> Expression {
self
}
}
impl True<Self> for Expression {}
pub struct Array<T: Expr>(Expression, PhantomData<T>);
impl<T: Expr> Expr for Array<T> {}
impl<T: Expr> Compile for Array<T> {
fn from_string(s: String) -> Array<T> {
Array(Expression::from_string(s), PhantomData)
}
fn compile(&self) -> &str {
self.0.compile()
}
fn take(self) -> String {
self.0.take()
}
}
impl<T: Expr> Array<T> {
pub(crate) const fn new(expr: &'static str) -> Array<T> {
Array(Expression::CONST(expr), PhantomData)
}
}
impl<T: Expr> Cast<Array<T>> for Expression {
fn cast(self) -> Array<T> {
Array::from_string(self.take())
}
}
impl<T: Expr> Cast<Expression> for Array<T> {
fn cast(self) -> Expression {
Expression::from_string(self.take())
}
}
impl<T: Expr> Cast<Self> for Array<T> {
fn cast(self) -> Self {
self
}
}
impl<T: Expr> True<Self> for Array<T> {}
pub struct Variable<T: Expr> {
owner: Option<Player>,
name: &'static str,
_phantom: PhantomData<T>,
}
#[doc(hidden)]
pub struct VariableElement<T: Expr> {
owner: Option<Player>,
name: &'static str,
index: String,
_phantom: PhantomData<T>,
}
pub trait VariableExpr<T: Expr> {
fn owner(&self) -> Option<Player>;
fn name(&self) -> &'static str;
fn access_target(&self) -> String;
fn modify_target(&self) -> String;
}
impl<T: Expr> VariableExpr<T> for Variable<T> {
fn owner(&self) -> Option<Player> {
if let Some(ref player) = self.owner {
return Some(Player::from_string(player.compile().to_string()));
}
None
}
fn name(&self) -> &'static str {
self.name
}
fn access_target(&self) -> String {
if let Some(ref player) = self.owner {
format!("{}.{}", player.compile(), self.name)
} else {
format!("Global.{}", self.name)
}
}
fn modify_target(&self) -> String {
if let Some(ref player) = self.owner {
format!("Modify Player Variable({}, {}", player.compile(), self.name)
} else {
format!("Modify Global Variable({}", self.name)
}
}
}
impl<T: Expr> VariableExpr<T> for VariableElement<T> {
fn owner(&self) -> Option<Player> {
if let Some(ref player) = self.owner {
return Some(Player::from_string(player.compile().to_string()));
}
None
}
fn name(&self) -> &'static str {
self.name
}
fn access_target(&self) -> String {
if let Some(ref player) = self.owner {
format!("{}.{}[{}]", player.compile(), self.name, self.index)
} else {
format!("Global.{}[{}]", self.name, self.index)
}
}
fn modify_target(&self) -> String {
if let Some(ref player) = self.owner {
format!(
"Modify Player Variable At Index({}, {}, {}",
player.compile(),
self.name,
self.index
)
} else {
format!(
"Modify Global Variable At Index({}, {}",
self.name, self.index
)
}
}
}
impl<T: Expr> Variable<T> {
#[doc(hidden)]
pub fn __new__(owner: Option<Player>, name: &'static str) -> Variable<T> {
Variable {
owner,
name,
_phantom: PhantomData,
}
}
}
impl<T: Expr> VariableElement<T> {
pub(crate) fn new(
owner: Option<Player>,
name: &'static str,
index: String,
) -> VariableElement<T> {
VariableElement {
owner,
name,
index,
_phantom: PhantomData,
}
}
}
pub trait VarExpr<T: Expr> {
fn get(self) -> T;
fn set(self, value: impl True<T>);
}
impl<T: Expr, V: VariableExpr<T>> VarExpr<T> for V {
fn get(self) -> T {
T::from_string(self.access_target())
}
fn set(self, value: impl True<T>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{} = {}",
self.access_target(),
value.cast().compile()
));
}
}
impl<T: Expr> Cast<T> for Variable<T> {
fn cast(self) -> T {
self.get()
}
}
impl<T: Expr> Cast<Array<T>> for Variable<T> {
fn cast(self) -> Array<T> {
Array::from_string(self.access_target())
}
}
impl<T: Expr> Cast<T> for VariableElement<T> {
fn cast(self) -> T {
self.get()
}
}
impl<T: Expr> Cast<Array<T>> for VariableElement<T> {
fn cast(self) -> Array<T> {
Array::from_string(self.access_target())
}
}
impl<T: Expr> True<T> for Variable<T> {}
impl<T: Expr> True<Array<T>> for Variable<T> {}
impl<T: Expr> True<T> for VariableElement<T> {}
impl<T: Expr> True<Array<T>> for VariableElement<T> {}
impl Variable<Number> {
pub fn cf_iterate(
self,
range_start: impl True<Number>,
range_stop: impl True<Number>,
step: impl True<Number>,
) {
let compiler = get_compiler();
if self.owner.is_none() {
compiler.push_action(format!(
"For Global Variable({}, {}, {}, {})",
self.name,
range_start.cast().compile(),
range_stop.cast().compile(),
step.cast().compile()
));
} else {
compiler.push_action(format!(
"For Player Variable({}, {}, {}, {}, {})",
self.owner.unwrap().compile(),
self.name,
range_start.cast().compile(),
range_stop.cast().compile(),
step.cast().compile()
));
}
}
}
#[doc(hidden)]
pub trait LinearVariable<T: Expr>: VariableExpr<T> {}
impl LinearVariable<Number> for Variable<Number> {}
impl LinearVariable<Vector> for Variable<Vector> {}
impl LinearVariable<Color> for Variable<Color> {}
pub trait LinearVarExpr<U: LinearVariable<T>, T: Expr> {
fn start_chasing_at_rate(
self,
destination: impl True<T>,
rate: impl True<Number>,
reevaluation: impl True<Reeval_0>,
);
fn start_chasing_over_time(
self,
destination: impl True<T>,
duration: impl True<Number>,
reevaluation: impl True<Reeval_0>,
);
fn stop_chasing(self);
}
impl<U: LinearVariable<T>, T: Expr> LinearVarExpr<U, T> for U {
fn start_chasing_at_rate(
self,
destination: impl True<T>,
rate: impl True<Number>,
reevaluation: impl True<Reeval_0>,
) {
let compiler = get_compiler();
if self.owner().is_none() {
compiler.push_action(format!(
"Start Chasing Global Variable({}, {}, {}, {})",
self.name(),
destination.cast().compile(),
rate.cast().compile(),
reevaluation.cast().compile()
));
} else {
compiler.push_action(format!(
"Start Chasing Player Variable({}, {}, {}, {}, {})",
self.owner().unwrap().compile(),
self.name(),
destination.cast().compile(),
rate.cast().compile(),
reevaluation.cast().compile()
));
}
}
fn start_chasing_over_time(
self,
destination: impl True<T>,
duration: impl True<Number>,
reevaluation: impl True<Reeval_0>,
) {
let compiler = get_compiler();
if self.owner().is_none() {
compiler.push_action(format!(
"Start Chasing Global Variable({}, {}, {}, {})",
self.name(),
destination.cast().compile(),
duration.cast().compile(),
reevaluation.cast().compile()
));
} else {
compiler.push_action(format!(
"Start Chasing Player Variable({}, {}, {}, {}, {})",
self.owner().unwrap().compile(),
self.name(),
destination.cast().compile(),
duration.cast().compile(),
reevaluation.cast().compile()
));
}
}
fn stop_chasing(self) {
let compiler = get_compiler();
if self.owner().is_none() {
compiler.push_action(format!("Stop Chasing Global Variable({})", self.name()));
} else {
compiler.push_action(format!(
"Stop Chasing Player Variable({}, {})",
self.owner().unwrap().compile(),
self.name()
));
}
}
}
impl<T: Expr> Variable<Array<T>> {
pub fn value_at(self, index: impl True<Number>) -> VariableElement<T> {
VariableElement::new(self.owner, self.name, index.cast().compile().to_string())
}
}
pub trait ArrayVarExpr<T: Expr> {
fn append(self, value: impl True<T>);
fn remove_value(self, value: impl True<T>);
fn remove_index(self, index: impl True<Number>);
}
impl<T: Expr, V: VariableExpr<Array<T>>> ArrayVarExpr<T> for V {
fn append(self, value: impl True<T>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Append To Array, {})",
self.modify_target(),
value.cast().compile()
));
}
fn remove_value(self, value: impl True<T>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Remove From Array By Value, {})",
self.modify_target(),
value.cast().compile()
));
}
fn remove_index(self, index: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Remove From Array By Index, {})",
self.modify_target(),
index.cast().compile()
));
}
}
pub trait VectorVarExpr {
fn add(self, value: impl True<Vector>);
fn sub(self, value: impl True<Vector>);
fn mul(self, value: impl True<Vector>);
fn multiply(self, value: impl True<Number>);
fn div(self, value: impl True<Vector>);
fn divide(self, value: impl True<Number>);
}
impl<T: VariableExpr<Vector>> VectorVarExpr for T {
fn add(self, value: impl True<Vector>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Add, {})",
self.modify_target(),
value.cast().compile()
));
}
fn sub(self, value: impl True<Vector>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Subtract, {})",
self.modify_target(),
value.cast().compile()
));
}
fn mul(self, value: impl True<Vector>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Multiply, {})",
self.modify_target(),
value.cast().compile()
));
}
fn multiply(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Multiply, {})",
self.modify_target(),
value.cast().compile()
));
}
fn div(self, value: impl True<Vector>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Divide, {})",
self.modify_target(),
value.cast().compile()
));
}
fn divide(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Divide, {})",
self.modify_target(),
value.cast().compile()
));
}
}
pub trait NumberVarExpr {
fn add(self, value: impl True<Number>);
fn sub(self, value: impl True<Number>);
fn mul(self, value: impl True<Number>);
fn div(self, value: impl True<Number>);
fn rem(self, value: impl True<Number>);
fn pow(self, value: impl True<Number>);
fn min(self, value: impl True<Number>);
fn max(self, value: impl True<Number>);
}
impl<T: VariableExpr<Number>> NumberVarExpr for T {
fn add(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Add, {})",
self.modify_target(),
value.cast().compile()
));
}
fn sub(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Subtract, {})",
self.modify_target(),
value.cast().compile()
));
}
fn mul(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Multiply, {})",
self.modify_target(),
value.cast().compile()
));
}
fn div(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Divide, {})",
self.modify_target(),
value.cast().compile()
));
}
fn rem(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Modulo, {})",
self.modify_target(),
value.cast().compile()
));
}
fn pow(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Raise To Power, {})",
self.modify_target(),
value.cast().compile()
));
}
fn min(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Min, {})",
self.modify_target(),
value.cast().compile()
));
}
fn max(self, value: impl True<Number>) {
let compiler = get_compiler();
compiler.push_action(format!(
"{}, Max, {})",
self.modify_target(),
value.cast().compile()
));
}
}
macro_rules! expr_type {
($ty_name:ident $(=> $($extended:ty),*)? ) => {
pub struct $ty_name(Expression);
impl Expr for $ty_name {}
impl Compile for $ty_name {
fn from_string(s: String) -> $ty_name {
$ty_name(Expression::from_string(s))
}
fn compile(&self) -> &str {
self.0.compile()
}
fn take(self) -> String {
self.0.take()
}
}
impl $ty_name {
pub(crate) const fn new(expr: &'static str) -> $ty_name {
$ty_name(Expression::CONST(expr))
}
}
impl Cast<Self> for $ty_name {
fn cast(self) -> Self {
self
}
}
impl True<Self> for $ty_name {}
impl Cast<$ty_name> for Expression {
fn cast(self) -> $ty_name {
$ty_name::from_string(self.take())
}
}
impl Cast<Expression> for $ty_name {
fn cast(self) -> Expression {
Expression::from_string(self.take())
}
}
$($(
impl Cast<$extended> for $ty_name {
fn cast(self) -> $extended {
<$extended>::from_string(self.take())
}
}
impl Cast<Array<$extended>> for $ty_name {
fn cast(self) -> Array<$extended> {
Array::from_string(self.take())
}
}
)*)?
impl Cast<Array<$ty_name>> for $ty_name {
fn cast(self) -> Array<$ty_name> {
Array::from_string(self.take())
}
}
impl True<Array<$ty_name>> for $ty_name {}
};
}
macro_rules! expr {
($name:ident) => {
pub struct $name(Expression);
impl $name {
pub(crate) const fn new(expr: &'static str) -> $name {
$name(Expression::CONST(expr))
}
}
impl Compile for $name {
fn from_string(s: String) -> $name {
$name(Expression::from_string(s))
}
fn compile(&self) -> &str {
self.0.compile()
}
fn take(self) -> String {
self.0.take()
}
}
impl Cast<$name> for $name {
fn cast(self) -> $name {
self
}
}
impl True<Self> for $name {}
};
}
pub struct Global;
expr!(Subroutine);
expr_type!(Text);
expr_type!(Boolean => Number, Text);
expr_type!(BooleanLiteral => Boolean, Text);
expr_type!(Number => Boolean, Text);
expr_type!(NumberLiteral => Number, Text);
expr_type!(Hero => Text);
expr_type!(HeroLiteral => Text);
expr_type!(Team => Text);
expr_type!(TeamLiteral => Text);
expr_type!(Player => Vector, Entity, Text);
expr_type!(Vector => Text);
expr_type!(Button => Text);
expr_type!(Color => Text);
expr_type!(GameMode => Text);
expr_type!(Map => Text);
expr_type!(Entity => Player, Text);
expr!(Status);
expr!(Interaction);
expr!(BeamEffect);
expr!(LingeringEffect);
expr!(ProjectileType);
expr!(ModifyHealthType);
expr!(SplashSound);
expr!(SplashVisual);
expr!(SplashEffect);
expr!(HudLocation);
expr!(SpectatorVisibility);
expr!(Icon);
expr!(Clipping);
expr!(HealthType);
expr!(Invisibility);
expr!(OutlineType);
expr!(ThrottleBehavior);
expr!(SubroutineBehavior);
expr!(WaitBehavior);
expr!(RelativeSystem);
expr!(BarrierLOS);
expr!(Transformation);
expr!(Statistic);
expr!(LOS_Check);
expr!(Reeval_0);
expr!(Reeval_1);
expr!(Reeval_2);
expr!(Reeval_3);
expr!(Reeval_4);
expr!(Reeval_5);
expr!(Reeval_6);
expr!(Reeval_7);
expr!(Reeval_8);
expr!(Reeval_9);
expr!(Reeval_10);
expr!(Reeval_11);
expr!(Reeval_12);
expr!(Reeval_13);
impl Cast<Text> for &str {
fn cast(self) -> Text {
Text::from_string(format!("Custom String(\"{}\")", self))
}
}
impl True<Text> for &str {}
impl Cast<Boolean> for bool {
fn cast(self) -> Boolean {
Cast::<BooleanLiteral>::cast(self).cast()
}
}
impl True<Boolean> for bool {}
impl True<Boolean> for BooleanLiteral {}
impl Cast<BooleanLiteral> for bool {
fn cast(self) -> BooleanLiteral {
BooleanLiteral::from_string(
match self {
true => "True",
false => "False",
}
.to_string(),
)
}
}
impl True<BooleanLiteral> for bool {}
impl Cast<Text> for bool {
fn cast(self) -> Text {
Cast::<Boolean>::cast(self).cast()
}
}
macro_rules! impl_numeric {
($($ty:ty),*) => {
$(
impl Cast<NumberLiteral> for $ty {
fn cast(self) -> NumberLiteral {
NumberLiteral::from_string(format!("{}", self))
}
}
impl True<NumberLiteral> for $ty {}
impl Cast<Number> for $ty {
fn cast(self) -> Number {
Number::from_string(format!("{}", self))
}
}
impl True<Number> for $ty {}
impl Cast<Text> for $ty {
fn cast(self) -> Text {
Text::from_string(format!("{}", self))
}
}
)*
};
}
impl_numeric!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64);
impl True<Number> for NumberLiteral {}
impl Cast<Hero> for HeroLiteral {
fn cast(self) -> Hero {
Hero::from_string(format!("Hero({})", self.take()))
}
}
impl True<Hero> for HeroLiteral {}
impl Cast<Team> for TeamLiteral {
fn cast(self) -> Team {
Team::from_string(self.take().replace("All", "Team All"))
}
}
impl True<Team> for TeamLiteral {}
impl Cast<SplashEffect> for SplashSound {
fn cast(self) -> SplashEffect {
SplashEffect::from_string(self.take())
}
}
impl True<SplashEffect> for SplashSound {}
impl Cast<SplashEffect> for SplashVisual {
fn cast(self) -> SplashEffect {
SplashEffect::from_string(self.take())
}
}
impl True<SplashEffect> for SplashVisual {}
impl Subroutine {
#[doc(hidden)]
pub fn __new__(name: &'static str) -> Subroutine {
Subroutine(Expression::new(name))
}
}
pub mod exported {
pub use super::{
ArrayVarExpr, Cast, Global, LinearVarExpr, NumberVarExpr, Subroutine, VarExpr,
VectorVarExpr,
};
}
#[allow(non_snake_case)]
pub mod ExprType {
pub use super::{
Array, BarrierLOS, BeamEffect, Boolean, Button, Clipping, Color, Compile, Entity,
Expression, GameMode, HealthType, Hero, HudLocation, Icon, Interaction, Invisibility,
LOS_Check, LingeringEffect, Map, ModifyHealthType, Number, OutlineType, Player,
ProjectileType, Reeval_0, Reeval_1, Reeval_10, Reeval_11, Reeval_12, Reeval_13, Reeval_2,
Reeval_3, Reeval_4, Reeval_5, Reeval_6, Reeval_7, Reeval_8, Reeval_9, RelativeSystem,
SpectatorVisibility, SplashEffect, SplashSound, SplashVisual, Statistic, Status,
SubroutineBehavior, Team, Text, ThrottleBehavior, Transformation, Variable, Vector,
WaitBehavior,
};
}