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 pub(crate) fn span_mut(&mut self) -> &mut Option<Span> {
563 match self {
564 Stmt::Expr { span, .. }
565 | Stmt::Assign { span, .. }
566 | Stmt::If { span, .. }
567 | Stmt::For { span, .. }
568 | Stmt::While { span, .. }
569 | Stmt::DoWhile { span, .. }
570 | Stmt::Switch { span, .. }
571 | Stmt::Delete { span, .. }
572 | Stmt::Break { span }
573 | Stmt::Return { span }
574 | Stmt::Continue { span }
575 | Stmt::Goto { span, .. }
576 | Stmt::Label { span, .. }
577 | Stmt::CallSubroutine { span, .. }
578 | Stmt::Pass { span } => span,
579 }
580 }
581}
582
583#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
586#[serde(tag = "kind", rename_all = "camelCase")]
587pub enum SwitchArm {
588 Case {
589 value: Box<Expr>,
590 #[serde(default)]
591 body: Vec<Stmt>,
592 #[serde(skip_serializing_if = "Option::is_none")]
593 span: Option<Span>,
594 },
595 Default {
596 #[serde(default)]
597 body: Vec<Stmt>,
598 #[serde(skip_serializing_if = "Option::is_none")]
599 span: Option<Span>,
600 },
601}
602
603#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
605#[serde(tag = "kind", rename_all = "camelCase")]
606pub enum Expr {
607 Number {
608 value: f64,
609 text: String,
610 #[serde(skip_serializing_if = "Option::is_none")]
611 span: Option<Span>,
612 },
613 String {
614 value: String,
615 #[serde(skip_serializing_if = "Option::is_none")]
616 span: Option<Span>,
617 },
618 Bool {
619 value: bool,
620 #[serde(skip_serializing_if = "Option::is_none")]
621 span: Option<Span>,
622 },
623 Null {
624 #[serde(skip_serializing_if = "Option::is_none")]
625 span: Option<Span>,
626 },
627 Array {
628 #[serde(default)]
629 elements: Vec<Expr>,
630 #[serde(skip_serializing_if = "Option::is_none")]
631 span: Option<Span>,
632 },
633 Dict {
634 #[serde(default)]
635 entries: Vec<DictEntry>,
636 #[serde(skip_serializing_if = "Option::is_none")]
637 span: Option<Span>,
638 },
639 Comprehension {
640 element: Box<Expr>,
641 variable: String,
642 #[serde(skip_serializing_if = "Option::is_none")]
643 variable_span: Option<Span>,
644 #[serde(default, skip_serializing_if = "Option::is_none")]
645 index: Option<String>,
646 #[serde(default, skip_serializing_if = "Option::is_none")]
647 index_span: Option<Span>,
648 iterable: Box<Expr>,
649 #[serde(default, skip_serializing_if = "Option::is_none")]
650 condition: Option<Box<Expr>>,
651 #[serde(skip_serializing_if = "Option::is_none")]
652 span: Option<Span>,
653 },
654 Lambda {
655 #[serde(default)]
656 params: Vec<String>,
657 #[serde(default)]
658 param_spans: Vec<Option<Span>>,
659 body: Box<Expr>,
660 #[serde(skip_serializing_if = "Option::is_none")]
661 span: Option<Span>,
662 },
663 StringModifier {
664 modifier: String,
665 value: String,
666 #[serde(skip_serializing_if = "Option::is_none")]
667 span: Option<Span>,
668 },
669 Local {
670 name: String,
671 #[serde(skip_serializing_if = "Option::is_none")]
672 span: Option<Span>,
673 },
674 Vector {
675 x: Box<Expr>,
676 y: Box<Expr>,
677 z: Box<Expr>,
678 #[serde(skip_serializing_if = "Option::is_none")]
679 span: Option<Span>,
680 },
681 Enum {
682 #[serde(rename = "type")]
683 value_type: String,
684 value: String,
685 #[serde(default)]
690 literal: bool,
691 #[serde(skip_serializing_if = "Option::is_none")]
692 span: Option<Span>,
693 },
694 GlobalVar {
695 name: String,
696 #[serde(skip_serializing_if = "Option::is_none")]
697 span: Option<Span>,
698 },
699 PlayerVar {
700 player: Box<Expr>,
701 name: String,
702 #[serde(default, skip_serializing_if = "Option::is_none")]
705 member_span: Option<Span>,
706 #[serde(skip_serializing_if = "Option::is_none")]
707 span: Option<Span>,
708 },
709 HostPlayer {
710 #[serde(skip_serializing_if = "Option::is_none")]
711 span: Option<Span>,
712 },
713 Member {
717 receiver: Box<Expr>,
718 member: String,
719 #[serde(default, skip_serializing_if = "Option::is_none")]
720 member_span: Option<Span>,
721 #[serde(skip_serializing_if = "Option::is_none")]
722 span: Option<Span>,
723 },
724 EventPlayer {
725 #[serde(skip_serializing_if = "Option::is_none")]
726 span: Option<Span>,
727 },
728 Constant {
729 name: String,
730 #[serde(skip_serializing_if = "Option::is_none")]
731 span: Option<Span>,
732 },
733 Call {
734 name: String,
735 #[serde(default)]
736 args: Vec<Expr>,
737 #[serde(default, skip_serializing_if = "Option::is_none")]
738 debug_source: Option<String>,
739 #[serde(skip_serializing_if = "Option::is_none")]
740 span: Option<Span>,
741 },
742 ReceiverCall {
743 receiver: Box<Expr>,
744 name: String,
745 #[serde(default)]
746 args: Vec<Expr>,
747 #[serde(skip_serializing_if = "Option::is_none")]
748 span: Option<Span>,
749 },
750 MacroCall {
751 name: String,
752 #[serde(default)]
753 args: Vec<Expr>,
754 #[serde(skip_serializing_if = "Option::is_none")]
755 span: Option<Span>,
756 },
757 MacroParam {
758 name: String,
759 #[serde(skip_serializing_if = "Option::is_none")]
760 span: Option<Span>,
761 },
762 Type {
765 name: String,
766 #[serde(default)]
767 args: Vec<Expr>,
768 #[serde(skip_serializing_if = "Option::is_none")]
769 span: Option<Span>,
770 },
771 Binary {
772 op: String,
773 left: Box<Expr>,
774 right: Box<Expr>,
775 #[serde(skip_serializing_if = "Option::is_none")]
776 span: Option<Span>,
777 },
778 Conditional {
779 then_value: Box<Expr>,
780 condition: Box<Expr>,
781 else_value: Box<Expr>,
782 #[serde(skip_serializing_if = "Option::is_none")]
783 span: Option<Span>,
784 },
785 Unary {
786 op: String,
787 operand: Box<Expr>,
788 #[serde(skip_serializing_if = "Option::is_none")]
789 span: Option<Span>,
790 },
791 Index {
792 array: Box<Expr>,
793 index: Box<Expr>,
794 #[serde(skip_serializing_if = "Option::is_none")]
795 span: Option<Span>,
796 },
797 Format {
798 text: String,
799 #[serde(default)]
800 args: Vec<Expr>,
801 #[serde(skip_serializing_if = "Option::is_none")]
802 span: Option<Span>,
803 },
804}
805
806#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
808pub struct DictEntry {
809 pub key: Box<Expr>,
810 pub value: Box<Expr>,
811 #[serde(skip_serializing_if = "Option::is_none")]
812 pub span: Option<Span>,
813}
814
815impl Expr {
816 pub fn span(&self) -> Option<&Span> {
818 match self {
819 Expr::Number { span, .. }
820 | Expr::String { span, .. }
821 | Expr::Bool { span, .. }
822 | Expr::Null { span }
823 | Expr::Array { span, .. }
824 | Expr::Dict { span, .. }
825 | Expr::Comprehension { span, .. }
826 | Expr::Lambda { span, .. }
827 | Expr::StringModifier { span, .. }
828 | Expr::Local { span, .. }
829 | Expr::Vector { span, .. }
830 | Expr::Enum { span, .. }
831 | Expr::GlobalVar { span, .. }
832 | Expr::PlayerVar { span, .. }
833 | Expr::HostPlayer { span }
834 | Expr::Member { span, .. }
835 | Expr::EventPlayer { span }
836 | Expr::Constant { span, .. }
837 | Expr::Call { span, .. }
838 | Expr::ReceiverCall { span, .. }
839 | Expr::MacroCall { span, .. }
840 | Expr::MacroParam { span, .. }
841 | Expr::Type { span, .. }
842 | Expr::Binary { span, .. }
843 | Expr::Conditional { span, .. }
844 | Expr::Unary { span, .. }
845 | Expr::Index { span, .. }
846 | Expr::Format { span, .. } => span.as_ref(),
847 }
848 }
849
850 pub(crate) fn span_mut(&mut self) -> &mut Option<Span> {
851 match self {
852 Expr::Number { span, .. }
853 | Expr::String { span, .. }
854 | Expr::Bool { span, .. }
855 | Expr::Null { span }
856 | Expr::Array { span, .. }
857 | Expr::Dict { span, .. }
858 | Expr::Comprehension { span, .. }
859 | Expr::Lambda { span, .. }
860 | Expr::StringModifier { span, .. }
861 | Expr::Local { span, .. }
862 | Expr::Vector { span, .. }
863 | Expr::Enum { span, .. }
864 | Expr::GlobalVar { span, .. }
865 | Expr::PlayerVar { span, .. }
866 | Expr::HostPlayer { span }
867 | Expr::Member { span, .. }
868 | Expr::EventPlayer { span }
869 | Expr::Constant { span, .. }
870 | Expr::Call { span, .. }
871 | Expr::ReceiverCall { span, .. }
872 | Expr::MacroCall { span, .. }
873 | Expr::MacroParam { span, .. }
874 | Expr::Type { span, .. }
875 | Expr::Binary { span, .. }
876 | Expr::Conditional { span, .. }
877 | Expr::Unary { span, .. }
878 | Expr::Index { span, .. }
879 | Expr::Format { span, .. } => span,
880 }
881 }
882
883 pub fn kind_name(&self) -> &'static str {
885 match self {
886 Expr::Number { .. } => "number",
887 Expr::String { .. } => "string",
888 Expr::Bool { .. } => "bool",
889 Expr::Null { .. } => "null",
890 Expr::Array { .. } => "array",
891 Expr::Dict { .. } => "dict",
892 Expr::Comprehension { .. } => "comprehension",
893 Expr::Lambda { .. } => "lambda",
894 Expr::StringModifier { .. } => "stringModifier",
895 Expr::Local { .. } => "local",
896 Expr::Vector { .. } => "vector",
897 Expr::Enum { .. } => "enum",
898 Expr::GlobalVar { .. } => "globalVar",
899 Expr::PlayerVar { .. } => "playerVar",
900 Expr::HostPlayer { .. } => "hostPlayer",
901 Expr::Member { .. } => "member",
902 Expr::EventPlayer { .. } => "eventPlayer",
903 Expr::Constant { .. } => "constant",
904 Expr::Call { .. } => "call",
905 Expr::ReceiverCall { .. } => "receiverCall",
906 Expr::MacroCall { .. } => "macroCall",
907 Expr::MacroParam { .. } => "macroParam",
908 Expr::Type { .. } => "type",
909 Expr::Binary { .. } => "binary",
910 Expr::Conditional { .. } => "conditional",
911 Expr::Unary { .. } => "unary",
912 Expr::Index { .. } => "index",
913 Expr::Format { .. } => "format",
914 }
915 }
916}