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