mod dump;
mod validate;
pub mod error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CensusCapabilityKind {
Variable,
PlayerVariable,
Subroutine,
ControlFlow,
String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CensusCapability {
pub kind: CensusCapabilityKind,
pub name: &'static str,
}
pub const CENSUS_CAPABILITIES: &[CensusCapability] = &[
CensusCapability {
kind: CensusCapabilityKind::Variable,
name: "global",
},
CensusCapability {
kind: CensusCapabilityKind::PlayerVariable,
name: "player",
},
CensusCapability {
kind: CensusCapabilityKind::Subroutine,
name: "declaration-and-call",
},
CensusCapability {
kind: CensusCapabilityKind::ControlFlow,
name: "if",
},
CensusCapability {
kind: CensusCapabilityKind::ControlFlow,
name: "else-if",
},
CensusCapability {
kind: CensusCapabilityKind::ControlFlow,
name: "else",
},
CensusCapability {
kind: CensusCapabilityKind::ControlFlow,
name: "while",
},
CensusCapability {
kind: CensusCapabilityKind::ControlFlow,
name: "for-global-variable",
},
CensusCapability {
kind: CensusCapabilityKind::String,
name: "custom-string",
},
];
use crate::arena::Arena;
use crate::ids::Id;
use crate::source::{SourceFile, Span};
pub type GlobalVarId = Id<WorkshopVariable>;
pub type PlayerVarId = Id<WorkshopVariable>;
pub type SubroutineId = Id<WorkshopSubroutine>;
pub type RuleId = Id<Rule>;
pub type ActionId = Id<Action>;
pub type ValueId = Id<ValueNode>;
#[derive(Debug, Clone)]
pub struct Program {
pub files: Arena<SourceFile>,
pub settings: Option<crate::settings::Settings>,
pub global_variables: Arena<WorkshopVariable>,
pub player_variables: Arena<WorkshopVariable>,
pub subroutines: Arena<WorkshopSubroutine>,
pub rules: Arena<Rule>,
pub values: Arena<ValueNode>,
pub actions: Arena<Action>,
}
impl Default for Program {
fn default() -> Self {
Program {
files: Arena::new(),
settings: None,
global_variables: Arena::new(),
player_variables: Arena::new(),
subroutines: Arena::new(),
rules: Arena::new(),
values: Arena::new(),
actions: Arena::new(),
}
}
}
impl Program {
pub fn validate(&self) -> Result<(), error::IrError> {
validate::validate(self)
}
pub fn semantic_issues(
&self,
catalog: &crate::catalog::Catalog,
) -> Vec<crate::semantic::SemanticIssue> {
crate::semantic::inspect(self, catalog)
}
pub fn dump(&self) -> String {
dump::dump(self)
}
}
#[derive(Debug, Clone)]
pub struct WorkshopVariable {
pub name: String,
pub index: u32,
pub span: Option<Span>,
pub name_span: Option<Span>,
}
#[derive(Debug, Clone)]
pub struct WorkshopSubroutine {
pub name: String,
pub index: u32,
pub span: Option<Span>,
pub name_span: Option<Span>,
}
#[derive(Debug, Clone)]
pub struct Rule {
pub name: String,
pub span: Option<Span>,
pub name_span: Option<Span>,
pub disabled: bool,
pub event: Event,
pub conditions: Vec<ValueId>,
pub actions: Vec<ActionId>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventTeam {
All,
Team1,
Team2,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EventTarget {
All,
Slot(u8),
Hero(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PlayerEventKind {
DealtDamage,
DealtFinalBlow,
DealtHealing,
DealtKnockback,
Died,
EarnedElimination,
Joined,
Left,
ReceivedHealing,
ReceivedKnockback,
TookDamage,
}
impl PlayerEventKind {
pub fn catalog_id(self) -> &'static str {
match self {
PlayerEventKind::DealtDamage => "playerDealtDamage",
PlayerEventKind::DealtFinalBlow => "playerDealtFinalBlow",
PlayerEventKind::DealtHealing => "playerDealtHealing",
PlayerEventKind::DealtKnockback => "playerDealtKnockback",
PlayerEventKind::Died => "playerDied",
PlayerEventKind::EarnedElimination => "playerEarnedElimination",
PlayerEventKind::Joined => "playerJoined",
PlayerEventKind::Left => "playerLeft",
PlayerEventKind::ReceivedHealing => "playerReceivedHealing",
PlayerEventKind::ReceivedKnockback => "playerReceivedKnockback",
PlayerEventKind::TookDamage => "playerTookDamage",
}
}
}
#[derive(Debug, Clone)]
pub enum Event {
Global,
EachPlayer,
EachPlayerWithFilters {
team: EventTeam,
target: EventTarget,
},
Player {
kind: PlayerEventKind,
team: EventTeam,
target: EventTarget,
},
Subroutine(SubroutineId),
}
#[derive(Debug, Clone)]
pub struct ValueNode {
pub value: Value,
pub span: Option<Span>,
}
#[derive(Debug, Clone)]
pub enum Value {
Number {
value: f64,
text: String,
},
String(String),
LocalizedString(String),
Bool(bool),
Null,
Array(Vec<ValueId>),
Vector {
x: ValueId,
y: ValueId,
z: ValueId,
},
Enum {
value_type: String,
value: String,
},
GlobalVariable(GlobalVarId),
PlayerVariable {
player: ValueId,
variable: PlayerVarId,
},
Subroutine(SubroutineId),
EventPlayer,
Call {
name: String,
args: Vec<ValueId>,
},
}
impl ValueNode {
pub fn new(value: Value, span: Option<Span>) -> Self {
ValueNode { value, span }
}
}
#[derive(Debug, Clone)]
pub enum Action {
SetGlobalVariable {
variable: GlobalVarId,
value: ValueId,
span: Option<Span>,
target_span: Option<Span>,
},
ModifyGlobalVariable {
variable: GlobalVarId,
op: ModifyOp,
value: ValueId,
span: Option<Span>,
target_span: Option<Span>,
},
SetPlayerVariable {
player: ValueId,
variable: PlayerVarId,
value: ValueId,
span: Option<Span>,
target_span: Option<Span>,
},
ModifyPlayerVariable {
player: ValueId,
variable: PlayerVarId,
op: ModifyOp,
value: ValueId,
span: Option<Span>,
target_span: Option<Span>,
},
AssignMember {
target: ValueId,
op: Option<ModifyOp>,
value: ValueId,
span: Option<Span>,
},
CallSubroutine {
subroutine: SubroutineId,
span: Option<Span>,
callee_span: Option<Span>,
},
If {
branches: Vec<IfBranch>,
else_body: Option<Vec<ActionId>>,
span: Option<Span>,
},
While {
condition: ValueId,
body: Vec<ActionId>,
span: Option<Span>,
},
ForGlobalVariable {
variable: GlobalVarId,
start: ValueId,
stop: ValueId,
step: ValueId,
body: Vec<ActionId>,
span: Option<Span>,
target_span: Option<Span>,
},
ForPlayerVariable {
player: ValueId,
variable: PlayerVarId,
start: ValueId,
stop: ValueId,
step: ValueId,
body: Vec<ActionId>,
span: Option<Span>,
},
Call {
name: String,
args: Vec<ValueId>,
span: Option<Span>,
},
}
impl Action {
pub fn span(&self) -> Option<Span> {
match self {
Action::SetGlobalVariable { span, .. }
| Action::ModifyGlobalVariable { span, .. }
| Action::SetPlayerVariable { span, .. }
| Action::ModifyPlayerVariable { span, .. }
| Action::AssignMember { span, .. }
| Action::CallSubroutine { span, .. }
| Action::If { span, .. }
| Action::While { span, .. }
| Action::ForGlobalVariable { span, .. }
| Action::ForPlayerVariable { span, .. }
| Action::Call { span, .. } => *span,
}
}
}
#[derive(Debug, Clone)]
pub struct IfBranch {
pub condition: ValueId,
pub body: Vec<ActionId>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModifyOp {
Add,
Subtract,
Multiply,
Divide,
Modulo,
Min,
Max,
RaiseToPower,
AppendToArray,
RemoveFromArray,
RemoveFromArrayByIndex,
}
impl ModifyOp {
pub fn as_str(self) -> &'static str {
match self {
ModifyOp::Add => "Add",
ModifyOp::Subtract => "Subtract",
ModifyOp::Multiply => "Multiply",
ModifyOp::Divide => "Divide",
ModifyOp::Modulo => "Modulo",
ModifyOp::Min => "Min",
ModifyOp::Max => "Max",
ModifyOp::RaiseToPower => "RaiseToPower",
ModifyOp::AppendToArray => "AppendToArray",
ModifyOp::RemoveFromArray => "RemoveFromArray",
ModifyOp::RemoveFromArrayByIndex => "RemoveFromArrayByIndex",
}
}
pub fn catalog_id(self) -> &'static str {
match self {
ModifyOp::Add => "add",
ModifyOp::Subtract => "subtract",
ModifyOp::Multiply => "multiply",
ModifyOp::Divide => "divide",
ModifyOp::Modulo => "modulo",
ModifyOp::Min => "min",
ModifyOp::Max => "max",
ModifyOp::RaiseToPower => "raiseToPower",
ModifyOp::AppendToArray => "appendToArray",
ModifyOp::RemoveFromArray => "removeFromArray",
ModifyOp::RemoveFromArrayByIndex => "removeFromArrayByIndex",
}
}
}