1mod dump;
19mod validate;
20
21pub mod error;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum CensusCapabilityKind {
27 Variable,
28 PlayerVariable,
29 Subroutine,
30 ControlFlow,
31 String,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub struct CensusCapability {
36 pub kind: CensusCapabilityKind,
37 pub name: &'static str,
38}
39
40pub const CENSUS_CAPABILITIES: &[CensusCapability] = &[
41 CensusCapability {
42 kind: CensusCapabilityKind::Variable,
43 name: "global",
44 },
45 CensusCapability {
46 kind: CensusCapabilityKind::PlayerVariable,
47 name: "player",
48 },
49 CensusCapability {
50 kind: CensusCapabilityKind::Subroutine,
51 name: "declaration-and-call",
52 },
53 CensusCapability {
54 kind: CensusCapabilityKind::ControlFlow,
55 name: "if",
56 },
57 CensusCapability {
58 kind: CensusCapabilityKind::ControlFlow,
59 name: "else-if",
60 },
61 CensusCapability {
62 kind: CensusCapabilityKind::ControlFlow,
63 name: "else",
64 },
65 CensusCapability {
66 kind: CensusCapabilityKind::ControlFlow,
67 name: "while",
68 },
69 CensusCapability {
70 kind: CensusCapabilityKind::ControlFlow,
71 name: "for-global-variable",
72 },
73 CensusCapability {
74 kind: CensusCapabilityKind::String,
75 name: "custom-string",
76 },
77];
78
79use crate::arena::Arena;
80use crate::ids::Id;
81use crate::source::{SourceFile, Span};
82
83pub type GlobalVarId = Id<WorkshopVariable>;
85pub type PlayerVarId = Id<WorkshopVariable>;
87pub type SubroutineId = Id<WorkshopSubroutine>;
89pub type RuleId = Id<Rule>;
91pub type ActionId = Id<Action>;
93pub type ValueId = Id<ValueNode>;
95
96#[derive(Debug, Clone)]
98pub struct Program {
99 pub files: Arena<SourceFile>,
102 pub settings: Option<crate::settings::Settings>,
105 pub global_variables: Arena<WorkshopVariable>,
106 pub player_variables: Arena<WorkshopVariable>,
107 pub subroutines: Arena<WorkshopSubroutine>,
108 pub rules: Arena<Rule>,
109 pub values: Arena<ValueNode>,
110 pub actions: Arena<Action>,
111}
112
113impl Default for Program {
114 fn default() -> Self {
115 Program {
116 files: Arena::new(),
117 settings: None,
118 global_variables: Arena::new(),
119 player_variables: Arena::new(),
120 subroutines: Arena::new(),
121 rules: Arena::new(),
122 values: Arena::new(),
123 actions: Arena::new(),
124 }
125 }
126}
127
128impl Program {
129 pub fn validate(&self) -> Result<(), error::IrError> {
134 validate::validate(self)
135 }
136
137 pub fn semantic_issues(
140 &self,
141 catalog: &crate::catalog::Catalog,
142 ) -> Vec<crate::semantic::SemanticIssue> {
143 crate::semantic::inspect(self, catalog)
144 }
145
146 pub fn dump(&self) -> String {
148 dump::dump(self)
149 }
150}
151
152#[derive(Debug, Clone)]
159pub struct WorkshopVariable {
160 pub name: String,
161 pub index: u32,
163 pub span: Option<Span>,
164 pub name_span: Option<Span>,
166}
167
168#[derive(Debug, Clone)]
170pub struct WorkshopSubroutine {
171 pub name: String,
172 pub index: u32,
173 pub span: Option<Span>,
174 pub name_span: Option<Span>,
176}
177
178#[derive(Debug, Clone)]
180pub struct Rule {
181 pub name: String,
182 pub span: Option<Span>,
183 pub name_span: Option<Span>,
185 pub disabled: bool,
186 pub event: Event,
187 pub conditions: Vec<ValueId>,
188 pub actions: Vec<ActionId>,
189}
190
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
193pub enum EventTeam {
194 All,
195 Team1,
196 Team2,
197}
198
199#[derive(Debug, Clone, PartialEq, Eq)]
201pub enum EventTarget {
202 All,
203 Slot(u8),
204 Hero(String),
205}
206
207#[derive(Debug, Clone, Copy, PartialEq, Eq)]
209pub enum PlayerEventKind {
210 DealtDamage,
211 DealtFinalBlow,
212 DealtHealing,
213 DealtKnockback,
214 Died,
215 EarnedElimination,
216 Joined,
217 Left,
218 ReceivedHealing,
219 ReceivedKnockback,
220 TookDamage,
221}
222
223impl PlayerEventKind {
224 pub fn catalog_id(self) -> &'static str {
226 match self {
227 PlayerEventKind::DealtDamage => "playerDealtDamage",
228 PlayerEventKind::DealtFinalBlow => "playerDealtFinalBlow",
229 PlayerEventKind::DealtHealing => "playerDealtHealing",
230 PlayerEventKind::DealtKnockback => "playerDealtKnockback",
231 PlayerEventKind::Died => "playerDied",
232 PlayerEventKind::EarnedElimination => "playerEarnedElimination",
233 PlayerEventKind::Joined => "playerJoined",
234 PlayerEventKind::Left => "playerLeft",
235 PlayerEventKind::ReceivedHealing => "playerReceivedHealing",
236 PlayerEventKind::ReceivedKnockback => "playerReceivedKnockback",
237 PlayerEventKind::TookDamage => "playerTookDamage",
238 }
239 }
240}
241
242#[derive(Debug, Clone)]
244pub enum Event {
245 Global,
247 EachPlayer,
249 EachPlayerWithFilters {
251 team: EventTeam,
252 target: EventTarget,
253 },
254 Player {
256 kind: PlayerEventKind,
257 team: EventTeam,
258 target: EventTarget,
259 },
260 Subroutine(SubroutineId),
262}
263
264#[derive(Debug, Clone)]
266pub struct ValueNode {
267 pub value: Value,
268 pub span: Option<Span>,
269}
270
271#[derive(Debug, Clone)]
273pub enum Value {
274 Number {
277 value: f64,
278 text: String,
279 },
280 String(String),
281 LocalizedString(String),
283 Bool(bool),
284 Null,
285 Array(Vec<ValueId>),
286 Vector {
287 x: ValueId,
288 y: ValueId,
289 z: ValueId,
290 },
291 Enum {
293 value_type: String,
294 value: String,
295 },
296 GlobalVariable(GlobalVarId),
297 PlayerVariable {
298 player: ValueId,
299 variable: PlayerVarId,
300 },
301 Subroutine(SubroutineId),
304 EventPlayer,
305 Call {
307 name: String,
308 args: Vec<ValueId>,
309 },
310}
311
312impl ValueNode {
313 pub fn new(value: Value, span: Option<Span>) -> Self {
315 ValueNode { value, span }
316 }
317}
318
319#[derive(Debug, Clone)]
321pub enum Action {
322 SetGlobalVariable {
323 variable: GlobalVarId,
324 value: ValueId,
325 span: Option<Span>,
326 target_span: Option<Span>,
328 },
329 ModifyGlobalVariable {
330 variable: GlobalVarId,
331 op: ModifyOp,
332 value: ValueId,
333 span: Option<Span>,
334 target_span: Option<Span>,
336 },
337 SetPlayerVariable {
338 player: ValueId,
339 variable: PlayerVarId,
340 value: ValueId,
341 span: Option<Span>,
342 target_span: Option<Span>,
344 },
345 ModifyPlayerVariable {
346 player: ValueId,
347 variable: PlayerVarId,
348 op: ModifyOp,
349 value: ValueId,
350 span: Option<Span>,
351 target_span: Option<Span>,
353 },
354 AssignMember {
358 target: ValueId,
359 op: Option<ModifyOp>,
360 value: ValueId,
361 span: Option<Span>,
362 },
363 CallSubroutine {
364 subroutine: SubroutineId,
365 span: Option<Span>,
366 callee_span: Option<Span>,
368 },
369 If {
370 branches: Vec<IfBranch>,
371 else_body: Option<Vec<ActionId>>,
372 span: Option<Span>,
373 },
374 While {
375 condition: ValueId,
376 body: Vec<ActionId>,
377 span: Option<Span>,
378 },
379 ForGlobalVariable {
380 variable: GlobalVarId,
381 start: ValueId,
382 stop: ValueId,
383 step: ValueId,
384 body: Vec<ActionId>,
385 span: Option<Span>,
386 target_span: Option<Span>,
388 },
389 ForPlayerVariable {
394 player: ValueId,
395 variable: PlayerVarId,
396 start: ValueId,
397 stop: ValueId,
398 step: ValueId,
399 body: Vec<ActionId>,
400 span: Option<Span>,
401 },
402 Debug { value: ValueId, span: Option<Span> },
404 Print {
406 message: ValueId,
407 span: Option<Span>,
408 },
409 Call {
411 name: String,
412 args: Vec<ValueId>,
413 span: Option<Span>,
414 },
415}
416
417impl Action {
418 pub fn span(&self) -> Option<Span> {
420 match self {
421 Action::SetGlobalVariable { span, .. }
422 | Action::ModifyGlobalVariable { span, .. }
423 | Action::SetPlayerVariable { span, .. }
424 | Action::ModifyPlayerVariable { span, .. }
425 | Action::AssignMember { span, .. }
426 | Action::CallSubroutine { span, .. }
427 | Action::If { span, .. }
428 | Action::While { span, .. }
429 | Action::ForGlobalVariable { span, .. }
430 | Action::ForPlayerVariable { span, .. }
431 | Action::Debug { span, .. }
432 | Action::Print { span, .. }
433 | Action::Call { span, .. } => *span,
434 }
435 }
436}
437
438#[derive(Debug, Clone)]
440pub struct IfBranch {
441 pub condition: ValueId,
442 pub body: Vec<ActionId>,
443}
444
445#[derive(Debug, Clone, Copy, PartialEq, Eq)]
447pub enum ModifyOp {
448 Add,
449 Subtract,
450 Multiply,
451 Divide,
452 Modulo,
453 Min,
454 Max,
455 RaiseToPower,
456 AppendToArray,
457 RemoveFromArray,
458 RemoveFromArrayByIndex,
459}
460
461impl ModifyOp {
462 pub fn as_str(self) -> &'static str {
464 match self {
465 ModifyOp::Add => "Add",
466 ModifyOp::Subtract => "Subtract",
467 ModifyOp::Multiply => "Multiply",
468 ModifyOp::Divide => "Divide",
469 ModifyOp::Modulo => "Modulo",
470 ModifyOp::Min => "Min",
471 ModifyOp::Max => "Max",
472 ModifyOp::RaiseToPower => "RaiseToPower",
473 ModifyOp::AppendToArray => "AppendToArray",
474 ModifyOp::RemoveFromArray => "RemoveFromArray",
475 ModifyOp::RemoveFromArrayByIndex => "RemoveFromArrayByIndex",
476 }
477 }
478
479 pub fn catalog_id(self) -> &'static str {
481 match self {
482 ModifyOp::Add => "add",
483 ModifyOp::Subtract => "subtract",
484 ModifyOp::Multiply => "multiply",
485 ModifyOp::Divide => "divide",
486 ModifyOp::Modulo => "modulo",
487 ModifyOp::Min => "min",
488 ModifyOp::Max => "max",
489 ModifyOp::RaiseToPower => "raiseToPower",
490 ModifyOp::AppendToArray => "appendToArray",
491 ModifyOp::RemoveFromArray => "removeFromArray",
492 ModifyOp::RemoveFromArrayByIndex => "removeFromArrayByIndex",
493 }
494 }
495}