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