1use std::collections::BTreeMap;
10
11use serde::{Deserialize, Serialize};
12
13pub const PROTOCOL_NAME: &str = "wright/opy-hir";
15pub const PROTOCOL_MAJOR: u32 = 2;
17pub const PROTOCOL_VERSION: &str = "2.0.0";
19
20const DEFAULT_VAR_SLOTS: u32 = 128;
31
32pub fn default_var_index(name: &str) -> Option<u32> {
40 if name.is_empty() || name.len() > 2 {
41 return None;
42 }
43 let mut value: u32 = 0;
44 for byte in name.bytes() {
45 if !byte.is_ascii_uppercase() {
46 return None;
47 }
48 value = value * 26 + u32::from(byte - b'A' + 1);
49 }
50 let index = value - 1;
51 (index < DEFAULT_VAR_SLOTS).then_some(index)
52}
53
54#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
56pub struct Protocol {
57 pub name: String,
58 pub version: String,
59}
60
61#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
63pub struct Generator {
64 pub name: String,
65 pub version: String,
66 pub frontend: String,
67}
68
69#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
71pub struct SourceFile {
72 pub id: u32,
73 pub path: String,
74}
75
76#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
78pub struct Define {
79 pub name: String,
80 #[serde(default)]
81 pub is_function: bool,
82 #[serde(default)]
84 pub is_member: bool,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub span: Option<Span>,
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
91pub struct Span {
92 pub file: u32,
93 pub start: Position,
94 pub end: Position,
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
99pub struct Position {
100 pub line: u32,
101 pub col: u32,
102}
103
104#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
106pub struct Program {
107 pub protocol: Protocol,
108 pub generator: Generator,
109 pub files: Vec<SourceFile>,
110 #[serde(default)]
111 pub defines: Vec<Define>,
112 #[serde(default)]
113 pub declarations: Vec<Declaration>,
114 #[serde(default)]
115 pub rules: Vec<RuleEntry>,
116 #[serde(default, skip_serializing_if = "Option::is_none")]
118 pub settings: Option<Settings>,
119 #[serde(default)]
123 pub preprocessing: PreprocessingState,
124}
125
126#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
128pub struct PreprocessingState {
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub main_file: Option<DirectiveValue>,
131 pub allow_macro_redeclaration: bool,
132 #[serde(default)]
133 pub rule_prefix: Option<DirectiveValue>,
134 #[serde(default)]
135 pub rule_prefix_template: Option<DirectiveValue>,
136 #[serde(default)]
137 pub translations: Option<TranslationState>,
138 #[serde(default)]
139 pub optimization: OptimizationState,
140 #[serde(default)]
141 pub replacements: Vec<DirectiveValue>,
142 #[serde(default)]
143 pub suppressed_warnings: Vec<String>,
144 #[serde(default)]
145 pub directives: Vec<DirectiveRecord>,
146 #[serde(skip)]
150 pub(crate) source_file_initial_optimization: BTreeMap<u32, OptimizationState>,
151}
152
153#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
155pub struct DirectiveValue {
156 pub value: String,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub span: Option<Span>,
159}
160
161#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
163pub struct TranslationEntry {
164 pub msgid: String,
165 #[serde(default, skip_serializing_if = "Option::is_none")]
166 pub context: Option<String>,
167 #[serde(default)]
168 pub translations: BTreeMap<String, String>,
169}
170
171#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
173pub struct TranslationState {
174 pub languages: Vec<String>,
175 #[serde(default)]
176 pub entries: Vec<TranslationEntry>,
177 #[serde(skip_serializing_if = "Option::is_none")]
178 pub span: Option<Span>,
179}
180
181#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
183pub struct OptimizationState {
184 pub enabled: bool,
185 pub for_size: bool,
186 pub for_size_aggressive: bool,
187 pub strict: bool,
188}
189
190impl Default for OptimizationState {
191 fn default() -> Self {
192 Self {
193 enabled: true,
194 for_size: false,
195 for_size_aggressive: false,
196 strict: false,
197 }
198 }
199}
200
201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
204pub struct DirectiveRecord {
205 pub name: String,
206 #[serde(skip_serializing_if = "Option::is_none")]
207 pub value: Option<String>,
208 pub scope_col: u32,
209 #[serde(default)]
210 pub scope_depth: u32,
211 #[serde(default)]
212 pub state: PreprocessingSnapshot,
213 #[serde(skip_serializing_if = "Option::is_none")]
214 pub span: Option<Span>,
215}
216
217#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
218pub struct PreprocessingSnapshot {
219 pub allow_macro_redeclaration: bool,
220 pub optimization: OptimizationState,
221 #[serde(default)]
222 pub rule_prefix: Option<String>,
223 #[serde(default)]
224 pub rule_prefix_template: Option<String>,
225 #[serde(default)]
226 pub translations: Option<Vec<String>>,
227 #[serde(default)]
228 pub replacements: Vec<String>,
229}
230
231#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
233pub struct Settings {
234 #[serde(skip_serializing_if = "Option::is_none")]
235 pub span: Option<Span>,
236 #[serde(default)]
237 pub children: Vec<SettingsNode>,
238}
239
240#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
242#[serde(tag = "kind", rename_all = "camelCase")]
243pub enum SettingsNode {
244 Group {
245 name: String,
246 #[serde(default)]
247 children: Vec<SettingsNode>,
248 #[serde(skip_serializing_if = "Option::is_none")]
249 span: Option<Span>,
250 },
251 Number {
252 name: String,
253 value: f64,
254 #[serde(skip_serializing_if = "Option::is_none")]
255 span: Option<Span>,
256 },
257 Bool {
258 name: String,
259 value: bool,
260 #[serde(skip_serializing_if = "Option::is_none")]
261 span: Option<Span>,
262 },
263 String {
264 name: String,
265 value: String,
266 #[serde(skip_serializing_if = "Option::is_none")]
267 span: Option<Span>,
268 },
269 Raw {
271 name: String,
272 value: String,
273 #[serde(skip_serializing_if = "Option::is_none")]
274 span: Option<Span>,
275 },
276 List {
277 name: String,
278 #[serde(default)]
279 elements: Vec<SettingsListElement>,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 span: Option<Span>,
282 },
283}
284
285impl SettingsNode {
286 pub fn span(&self) -> Option<&Span> {
288 match self {
289 SettingsNode::Group { span, .. }
290 | SettingsNode::Number { span, .. }
291 | SettingsNode::Bool { span, .. }
292 | SettingsNode::String { span, .. }
293 | SettingsNode::Raw { span, .. }
294 | SettingsNode::List { span, .. } => span.as_ref(),
295 }
296 }
297}
298
299#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
301pub struct SettingsListElement {
302 pub value: String,
303 #[serde(skip_serializing_if = "Option::is_none")]
304 pub span: Option<Span>,
305}
306
307#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
309#[serde(tag = "kind", rename_all = "camelCase")]
310pub enum Declaration {
311 GlobalVariable {
312 name: String,
313 #[serde(default)]
314 index: Option<u32>,
315 #[serde(skip_serializing_if = "Option::is_none")]
316 span: Option<Span>,
317 #[serde(default, skip_serializing_if = "Option::is_none")]
319 name_span: Option<Span>,
320 #[serde(default)]
321 initializer: Option<Box<Expr>>,
322 },
323 PlayerVariable {
324 name: String,
325 #[serde(default)]
326 index: Option<u32>,
327 #[serde(skip_serializing_if = "Option::is_none")]
328 span: Option<Span>,
329 #[serde(default, skip_serializing_if = "Option::is_none")]
331 name_span: Option<Span>,
332 #[serde(default)]
333 initializer: Option<Box<Expr>>,
334 },
335 Subroutine {
336 name: String,
337 #[serde(default)]
338 index: Option<u32>,
339 #[serde(skip_serializing_if = "Option::is_none")]
340 span: Option<Span>,
341 #[serde(default, skip_serializing_if = "Option::is_none")]
343 name_span: Option<Span>,
344 },
345 Constant {
346 name: String,
347 #[serde(skip_serializing_if = "Option::is_none")]
348 span: Option<Span>,
349 value: Box<Expr>,
350 },
351 Macro {
352 name: String,
353 #[serde(default)]
354 args: Vec<String>,
355 #[serde(skip_serializing_if = "Option::is_none")]
356 span: Option<Span>,
357 #[serde(default)]
358 body: Vec<Stmt>,
359 },
360}
361
362#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
364#[serde(untagged)]
365pub enum RuleEntry {
366 Rule(Rule),
368 SubroutineDef {
370 #[serde(rename = "kind")]
371 kind: String,
372 name: String,
373 #[serde(default, skip_serializing_if = "String::is_empty")]
374 source_name: String,
375 #[serde(skip_serializing_if = "Option::is_none")]
376 span: Option<Span>,
377 #[serde(default, skip_serializing_if = "Option::is_none")]
379 name_span: Option<Span>,
380 #[serde(default)]
381 body: Vec<Stmt>,
382 #[serde(default)]
383 annotations: Vec<Annotation>,
384 },
385}
386
387#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
389pub struct Rule {
390 pub name: String,
391 #[serde(skip_serializing_if = "Option::is_none")]
392 pub span: Option<Span>,
393 #[serde(default, skip_serializing_if = "Option::is_none")]
395 pub name_span: Option<Span>,
396 #[serde(default)]
397 pub disabled: bool,
398 #[serde(default)]
399 pub delimiter: bool,
400 #[serde(default, skip_serializing_if = "Option::is_none")]
401 pub new_page: Option<String>,
402 #[serde(default)]
403 pub annotations: Vec<Annotation>,
404 pub event: Event,
405 #[serde(default)]
406 pub conditions: Vec<Expr>,
407 #[serde(default)]
408 pub actions: Vec<Stmt>,
409}
410
411#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
413pub struct Annotation {
414 pub name: String,
415 #[serde(default)]
416 pub args: Vec<AnnotationArg>,
417 #[serde(skip_serializing_if = "Option::is_none")]
418 pub span: Option<Span>,
419}
420
421#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
422pub struct AnnotationArg {
423 pub text: String,
424 #[serde(skip_serializing_if = "Option::is_none")]
425 pub span: Option<Span>,
426}
427
428#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
430pub struct Event {
431 pub name: String,
432 #[serde(default)]
433 pub args: Vec<Expr>,
434 #[serde(skip_serializing_if = "Option::is_none")]
435 pub span: Option<Span>,
436}
437
438#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
440#[serde(tag = "kind", rename_all = "camelCase")]
441pub enum Stmt {
442 Expr {
443 expr: Box<Expr>,
444 #[serde(skip_serializing_if = "Option::is_none")]
445 span: Option<Span>,
446 },
447 Assign {
448 target: Box<Expr>,
449 value: Box<Expr>,
450 #[serde(skip_serializing_if = "Option::is_none")]
451 span: Option<Span>,
452 },
453 If {
454 branches: Vec<IfBranch>,
455 #[serde(default)]
456 r#else: Option<Vec<Stmt>>,
457 #[serde(skip_serializing_if = "Option::is_none")]
458 span: Option<Span>,
459 },
460 For {
461 variable: Box<Expr>,
462 iterable: Box<Expr>,
463 #[serde(default)]
464 body: Vec<Stmt>,
465 #[serde(skip_serializing_if = "Option::is_none")]
466 span: Option<Span>,
467 },
468 While {
469 condition: Box<Expr>,
470 #[serde(default)]
471 body: Vec<Stmt>,
472 #[serde(skip_serializing_if = "Option::is_none")]
473 span: Option<Span>,
474 },
475 DoWhile {
476 condition: Box<Expr>,
477 #[serde(default)]
478 body: Vec<Stmt>,
479 #[serde(skip_serializing_if = "Option::is_none")]
480 span: Option<Span>,
481 },
482 Switch {
483 value: Box<Expr>,
484 #[serde(default)]
485 arms: Vec<SwitchArm>,
486 #[serde(skip_serializing_if = "Option::is_none")]
487 span: Option<Span>,
488 },
489 Delete {
490 target: Box<Expr>,
491 #[serde(skip_serializing_if = "Option::is_none")]
492 span: Option<Span>,
493 },
494 Break {
495 #[serde(skip_serializing_if = "Option::is_none")]
496 span: Option<Span>,
497 },
498 Return {
499 #[serde(skip_serializing_if = "Option::is_none")]
500 span: Option<Span>,
501 },
502 Continue {
503 #[serde(skip_serializing_if = "Option::is_none")]
504 span: Option<Span>,
505 },
506 Goto {
507 #[serde(default, skip_serializing_if = "Option::is_none")]
508 label: Option<String>,
509 #[serde(default, skip_serializing_if = "Option::is_none")]
510 offset: Option<Box<Expr>>,
511 #[serde(default)]
512 rule_start: bool,
513 #[serde(skip_serializing_if = "Option::is_none")]
514 span: Option<Span>,
515 },
516 Label {
517 name: String,
518 #[serde(skip_serializing_if = "Option::is_none")]
519 span: Option<Span>,
520 },
521 CallSubroutine {
522 name: String,
523 #[serde(skip_serializing_if = "Option::is_none")]
524 span: Option<Span>,
525 },
526 Pass {
527 #[serde(skip_serializing_if = "Option::is_none")]
528 span: Option<Span>,
529 },
530}
531
532#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
534pub struct IfBranch {
535 pub condition: Box<Expr>,
536 #[serde(default)]
537 pub body: Vec<Stmt>,
538}
539
540impl Stmt {
541 pub fn span(&self) -> Option<&Span> {
543 match self {
544 Stmt::Expr { span, .. }
545 | Stmt::Assign { span, .. }
546 | Stmt::If { span, .. }
547 | Stmt::For { span, .. }
548 | Stmt::While { span, .. }
549 | Stmt::DoWhile { span, .. }
550 | Stmt::Switch { span, .. }
551 | Stmt::Delete { span, .. }
552 | Stmt::Break { span }
553 | Stmt::Return { span }
554 | Stmt::Continue { span }
555 | Stmt::Goto { span, .. }
556 | Stmt::Label { span, .. }
557 | Stmt::CallSubroutine { span, .. }
558 | Stmt::Pass { span } => span.as_ref(),
559 }
560 }
561}
562
563#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
566#[serde(tag = "kind", rename_all = "camelCase")]
567pub enum SwitchArm {
568 Case {
569 value: Box<Expr>,
570 #[serde(default)]
571 body: Vec<Stmt>,
572 #[serde(skip_serializing_if = "Option::is_none")]
573 span: Option<Span>,
574 },
575 Default {
576 #[serde(default)]
577 body: Vec<Stmt>,
578 #[serde(skip_serializing_if = "Option::is_none")]
579 span: Option<Span>,
580 },
581}
582
583#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
585#[serde(tag = "kind", rename_all = "camelCase")]
586pub enum Expr {
587 Number {
588 value: f64,
589 text: String,
590 #[serde(skip_serializing_if = "Option::is_none")]
591 span: Option<Span>,
592 },
593 String {
594 value: String,
595 #[serde(skip_serializing_if = "Option::is_none")]
596 span: Option<Span>,
597 },
598 Bool {
599 value: bool,
600 #[serde(skip_serializing_if = "Option::is_none")]
601 span: Option<Span>,
602 },
603 Null {
604 #[serde(skip_serializing_if = "Option::is_none")]
605 span: Option<Span>,
606 },
607 Array {
608 #[serde(default)]
609 elements: Vec<Expr>,
610 #[serde(skip_serializing_if = "Option::is_none")]
611 span: Option<Span>,
612 },
613 Dict {
614 #[serde(default)]
615 entries: Vec<DictEntry>,
616 #[serde(skip_serializing_if = "Option::is_none")]
617 span: Option<Span>,
618 },
619 Comprehension {
620 element: Box<Expr>,
621 variable: String,
622 #[serde(skip_serializing_if = "Option::is_none")]
623 variable_span: Option<Span>,
624 #[serde(default, skip_serializing_if = "Option::is_none")]
625 index: Option<String>,
626 #[serde(default, skip_serializing_if = "Option::is_none")]
627 index_span: Option<Span>,
628 iterable: Box<Expr>,
629 #[serde(default, skip_serializing_if = "Option::is_none")]
630 condition: Option<Box<Expr>>,
631 #[serde(skip_serializing_if = "Option::is_none")]
632 span: Option<Span>,
633 },
634 Lambda {
635 #[serde(default)]
636 params: Vec<String>,
637 #[serde(default)]
638 param_spans: Vec<Option<Span>>,
639 body: Box<Expr>,
640 #[serde(skip_serializing_if = "Option::is_none")]
641 span: Option<Span>,
642 },
643 StringModifier {
644 modifier: String,
645 value: String,
646 #[serde(skip_serializing_if = "Option::is_none")]
647 span: Option<Span>,
648 },
649 Local {
650 name: String,
651 #[serde(skip_serializing_if = "Option::is_none")]
652 span: Option<Span>,
653 },
654 Vector {
655 x: Box<Expr>,
656 y: Box<Expr>,
657 z: Box<Expr>,
658 #[serde(skip_serializing_if = "Option::is_none")]
659 span: Option<Span>,
660 },
661 Enum {
662 #[serde(rename = "type")]
663 value_type: String,
664 value: String,
665 #[serde(skip_serializing_if = "Option::is_none")]
666 span: Option<Span>,
667 },
668 GlobalVar {
669 name: String,
670 #[serde(skip_serializing_if = "Option::is_none")]
671 span: Option<Span>,
672 },
673 PlayerVar {
674 player: Box<Expr>,
675 name: String,
676 #[serde(default, skip_serializing_if = "Option::is_none")]
679 member_span: Option<Span>,
680 #[serde(skip_serializing_if = "Option::is_none")]
681 span: Option<Span>,
682 },
683 HostPlayer {
684 #[serde(skip_serializing_if = "Option::is_none")]
685 span: Option<Span>,
686 },
687 Member {
691 receiver: Box<Expr>,
692 member: String,
693 #[serde(default, skip_serializing_if = "Option::is_none")]
694 member_span: Option<Span>,
695 #[serde(skip_serializing_if = "Option::is_none")]
696 span: Option<Span>,
697 },
698 EventPlayer {
699 #[serde(skip_serializing_if = "Option::is_none")]
700 span: Option<Span>,
701 },
702 Constant {
703 name: String,
704 #[serde(skip_serializing_if = "Option::is_none")]
705 span: Option<Span>,
706 },
707 Call {
708 name: String,
709 #[serde(default)]
710 args: Vec<Expr>,
711 #[serde(default, skip_serializing_if = "Option::is_none")]
712 debug_source: Option<String>,
713 #[serde(skip_serializing_if = "Option::is_none")]
714 span: Option<Span>,
715 },
716 ReceiverCall {
717 receiver: Box<Expr>,
718 name: String,
719 #[serde(default)]
720 args: Vec<Expr>,
721 #[serde(skip_serializing_if = "Option::is_none")]
722 span: Option<Span>,
723 },
724 MacroCall {
725 name: String,
726 #[serde(default)]
727 args: Vec<Expr>,
728 #[serde(skip_serializing_if = "Option::is_none")]
729 span: Option<Span>,
730 },
731 MacroParam {
732 name: String,
733 #[serde(skip_serializing_if = "Option::is_none")]
734 span: Option<Span>,
735 },
736 Type {
739 name: String,
740 #[serde(default)]
741 args: Vec<Expr>,
742 #[serde(skip_serializing_if = "Option::is_none")]
743 span: Option<Span>,
744 },
745 Binary {
746 op: String,
747 left: Box<Expr>,
748 right: Box<Expr>,
749 #[serde(skip_serializing_if = "Option::is_none")]
750 span: Option<Span>,
751 },
752 Conditional {
753 then_value: Box<Expr>,
754 condition: Box<Expr>,
755 else_value: Box<Expr>,
756 #[serde(skip_serializing_if = "Option::is_none")]
757 span: Option<Span>,
758 },
759 Unary {
760 op: String,
761 operand: Box<Expr>,
762 #[serde(skip_serializing_if = "Option::is_none")]
763 span: Option<Span>,
764 },
765 Index {
766 array: Box<Expr>,
767 index: Box<Expr>,
768 #[serde(skip_serializing_if = "Option::is_none")]
769 span: Option<Span>,
770 },
771 Format {
772 text: String,
773 #[serde(default)]
774 args: Vec<Expr>,
775 #[serde(skip_serializing_if = "Option::is_none")]
776 span: Option<Span>,
777 },
778}
779
780#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
782pub struct DictEntry {
783 pub key: Box<Expr>,
784 pub value: Box<Expr>,
785 #[serde(skip_serializing_if = "Option::is_none")]
786 pub span: Option<Span>,
787}
788
789impl Expr {
790 pub fn span(&self) -> Option<&Span> {
792 match self {
793 Expr::Number { span, .. }
794 | Expr::String { span, .. }
795 | Expr::Bool { span, .. }
796 | Expr::Null { span }
797 | Expr::Array { span, .. }
798 | Expr::Dict { span, .. }
799 | Expr::Comprehension { span, .. }
800 | Expr::Lambda { span, .. }
801 | Expr::StringModifier { span, .. }
802 | Expr::Local { span, .. }
803 | Expr::Vector { span, .. }
804 | Expr::Enum { span, .. }
805 | Expr::GlobalVar { span, .. }
806 | Expr::PlayerVar { span, .. }
807 | Expr::HostPlayer { span }
808 | Expr::Member { span, .. }
809 | Expr::EventPlayer { span }
810 | Expr::Constant { span, .. }
811 | Expr::Call { span, .. }
812 | Expr::ReceiverCall { span, .. }
813 | Expr::MacroCall { span, .. }
814 | Expr::MacroParam { span, .. }
815 | Expr::Type { span, .. }
816 | Expr::Binary { span, .. }
817 | Expr::Conditional { span, .. }
818 | Expr::Unary { span, .. }
819 | Expr::Index { span, .. }
820 | Expr::Format { span, .. } => span.as_ref(),
821 }
822 }
823
824 pub fn kind_name(&self) -> &'static str {
826 match self {
827 Expr::Number { .. } => "number",
828 Expr::String { .. } => "string",
829 Expr::Bool { .. } => "bool",
830 Expr::Null { .. } => "null",
831 Expr::Array { .. } => "array",
832 Expr::Dict { .. } => "dict",
833 Expr::Comprehension { .. } => "comprehension",
834 Expr::Lambda { .. } => "lambda",
835 Expr::StringModifier { .. } => "stringModifier",
836 Expr::Local { .. } => "local",
837 Expr::Vector { .. } => "vector",
838 Expr::Enum { .. } => "enum",
839 Expr::GlobalVar { .. } => "globalVar",
840 Expr::PlayerVar { .. } => "playerVar",
841 Expr::HostPlayer { .. } => "hostPlayer",
842 Expr::Member { .. } => "member",
843 Expr::EventPlayer { .. } => "eventPlayer",
844 Expr::Constant { .. } => "constant",
845 Expr::Call { .. } => "call",
846 Expr::ReceiverCall { .. } => "receiverCall",
847 Expr::MacroCall { .. } => "macroCall",
848 Expr::MacroParam { .. } => "macroParam",
849 Expr::Type { .. } => "type",
850 Expr::Binary { .. } => "binary",
851 Expr::Conditional { .. } => "conditional",
852 Expr::Unary { .. } => "unary",
853 Expr::Index { .. } => "index",
854 Expr::Format { .. } => "format",
855 }
856 }
857}