1use crate::core::error::WorkshopError;
4use crate::settings::Settings;
5use crate::source::{FileId, SourceDocument, SourceFile, Span};
6
7mod conversion;
8pub(crate) mod shared;
9mod source_map;
10pub use shared::{EventTarget, EventTeam, ModifyOp, PlayerEventKind};
11pub use source_map::{MAPPED_TEXT_V1, MappedText, SourceMap, SourceMapError, TEXT_V1};
12
13#[derive(Debug, Clone, Default)]
15pub struct Program {
16 pub settings: Option<Settings>,
17 pub global_variables: Vec<Variable>,
18 pub player_variables: Vec<Variable>,
19 pub subroutines: Vec<Subroutine>,
20 pub rules: Vec<Rule>,
21 files: Vec<SourceFile>,
22 provenance: Option<Box<ProgramProvenance>>,
23}
24
25#[derive(Debug, Clone, Default)]
26struct ProgramProvenance {
27 global_variables: Vec<DeclarationProvenance>,
28 player_variables: Vec<DeclarationProvenance>,
29 subroutines: Vec<DeclarationProvenance>,
30 rules: Vec<RuleProvenance>,
31}
32
33#[derive(Debug, Clone, Copy, Default)]
34struct DeclarationProvenance {
35 span: Option<Span>,
36 name_span: Option<Span>,
37}
38
39#[derive(Debug, Clone, Default)]
40struct RuleProvenance {
41 span: Option<crate::source::Span>,
42 name: Option<Span>,
44 event_name: Option<Span>,
46 conditions: Vec<ValueProvenance>,
47 actions: Vec<ActionProvenance>,
48}
49
50#[derive(Debug, Clone, Default)]
51struct ActionProvenance {
52 span: Option<Span>,
53 identifier: Option<Span>,
56 arguments: Vec<ValueProvenance>,
57}
58
59trait SpanSlot {
62 fn span_slot(&mut self) -> &mut Option<Span>;
63}
64
65impl SpanSlot for ValueProvenance {
66 fn span_slot(&mut self) -> &mut Option<Span> {
67 &mut self.span
68 }
69}
70
71impl SpanSlot for ActionProvenance {
72 fn span_slot(&mut self) -> &mut Option<Span> {
73 &mut self.span
74 }
75}
76
77#[derive(Debug, Clone, Default)]
80struct ValueProvenance {
81 span: Option<Span>,
82 identifier: Option<Span>,
85 children: Vec<ValueProvenance>,
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90#[non_exhaustive]
91pub enum SourceMappingError {
92 UnknownFile(FileId),
93 InvalidSpan(Span),
94 InvalidRule(usize),
95 InvalidCondition {
96 rule: usize,
97 condition: usize,
98 },
99 InvalidAction {
100 rule: usize,
101 action: usize,
102 },
103 InvalidActionArgument {
104 rule: usize,
105 action: usize,
106 argument: usize,
107 },
108 InvalidGlobalVariable(usize),
109 InvalidPlayerVariable(usize),
110 InvalidSubroutine(usize),
111}
112
113impl std::fmt::Display for SourceMappingError {
114 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 match self {
116 Self::UnknownFile(file) => {
117 write!(formatter, "source span references unknown file {file}")
118 }
119 Self::InvalidSpan(span) => write!(formatter, "invalid source span {span:?}"),
120 Self::InvalidRule(rule) => write!(formatter, "invalid rule index {rule}"),
121 Self::InvalidCondition { rule, condition } => {
122 write!(
123 formatter,
124 "invalid condition index {condition} in rule {rule}"
125 )
126 }
127 Self::InvalidAction { rule, action } => {
128 write!(formatter, "invalid action index {action} in rule {rule}")
129 }
130 Self::InvalidActionArgument {
131 rule,
132 action,
133 argument,
134 } => write!(
135 formatter,
136 "invalid argument index {argument} in action {action} of rule {rule}"
137 ),
138 Self::InvalidGlobalVariable(variable) => {
139 write!(formatter, "invalid global variable index {variable}")
140 }
141 Self::InvalidPlayerVariable(variable) => {
142 write!(formatter, "invalid player variable index {variable}")
143 }
144 Self::InvalidSubroutine(subroutine) => {
145 write!(formatter, "invalid subroutine index {subroutine}")
146 }
147 }
148 }
149}
150
151impl std::error::Error for SourceMappingError {}
152
153impl Program {
154 pub fn new() -> Self {
155 Self::default()
156 }
157
158 pub fn add_file(&mut self, mut file: SourceFile) -> FileId {
160 let id = FileId::from_index(self.files.len());
161 file.bind_file(id);
162 self.files.push(file);
163 id
164 }
165
166 pub fn global_variable(&mut self, variable: Variable) -> &mut Self {
167 self.global_variables.push(variable);
168 self
169 }
170
171 pub fn player_variable(&mut self, variable: Variable) -> &mut Self {
172 self.player_variables.push(variable);
173 self
174 }
175
176 pub fn subroutine(&mut self, subroutine: Subroutine) -> &mut Self {
177 self.subroutines.push(subroutine);
178 self
179 }
180
181 pub fn rule(&mut self, rule: Rule) -> &mut Self {
182 self.rules.push(rule);
183 self
184 }
185
186 pub fn source(&self, file: FileId) -> Option<&SourceDocument> {
188 self.files.get(file.index()).and_then(SourceFile::source)
189 }
190
191 pub fn set_rule_span(
193 &mut self,
194 rule: usize,
195 span: Option<Span>,
196 ) -> std::result::Result<(), SourceMappingError> {
197 self.validate_span(span)?;
198 self.rule_provenance_mut(rule)?.span = span;
199 Ok(())
200 }
201
202 pub fn set_condition_span(
204 &mut self,
205 rule: usize,
206 condition: usize,
207 span: Option<Span>,
208 ) -> std::result::Result<(), SourceMappingError> {
209 self.set_child_span(
210 rule,
211 condition,
212 span,
213 |rule| rule.conditions.len(),
214 |rule, index| SourceMappingError::InvalidCondition {
215 rule,
216 condition: index,
217 },
218 |rule_data| &mut rule_data.conditions,
219 )
220 }
221
222 pub fn set_action_span(
224 &mut self,
225 rule: usize,
226 action: usize,
227 span: Option<Span>,
228 ) -> std::result::Result<(), SourceMappingError> {
229 self.set_child_span(
230 rule,
231 action,
232 span,
233 |rule| rule.actions.len(),
234 |rule, index| SourceMappingError::InvalidAction {
235 rule,
236 action: index,
237 },
238 |rule_data| &mut rule_data.actions,
239 )
240 }
241
242 fn set_child_span<T: SpanSlot + Default>(
246 &mut self,
247 rule: usize,
248 index: usize,
249 span: Option<Span>,
250 count: impl Fn(&crate::Rule) -> usize,
251 invalid: impl Fn(usize, usize) -> SourceMappingError,
252 slots: impl Fn(&mut RuleProvenance) -> &mut Vec<T>,
253 ) -> std::result::Result<(), SourceMappingError> {
254 self.validate_span(span)?;
255 let child_count = self
256 .rules
257 .get(rule)
258 .ok_or(SourceMappingError::InvalidRule(rule))
259 .map(count)?;
260 if index >= child_count {
261 return Err(invalid(rule, index));
262 }
263 let rule_data = self.rule_provenance_mut(rule)?;
264 fit(slots(rule_data), child_count);
265 *slots(rule_data)[index].span_slot() = span;
266 Ok(())
267 }
268
269 pub fn set_action_argument_span(
271 &mut self,
272 rule: usize,
273 action: usize,
274 argument: usize,
275 span: Option<Span>,
276 ) -> std::result::Result<(), SourceMappingError> {
277 self.validate_span(span)?;
278 let action_value = self
279 .rules
280 .get(rule)
281 .ok_or(SourceMappingError::InvalidRule(rule))?
282 .actions
283 .get(action)
284 .ok_or(SourceMappingError::InvalidAction { rule, action })?;
285 let argument_count = action_argument_count(action_value);
286 if argument >= argument_count {
287 return Err(SourceMappingError::InvalidActionArgument {
288 rule,
289 action,
290 argument,
291 });
292 }
293 let action_data = self.action_provenance_mut(rule, action)?;
294 action_data
295 .arguments
296 .resize_with(argument + 1, ValueProvenance::default);
297 action_data.arguments[argument].span = span;
298 Ok(())
299 }
300
301 pub fn set_global_variable_spans(
303 &mut self,
304 variable: usize,
305 span: Option<Span>,
306 name_span: Option<Span>,
307 ) -> std::result::Result<(), SourceMappingError> {
308 self.set_declaration_spans(DeclarationTable::GlobalVariables, variable, span, name_span)
309 }
310
311 pub fn set_player_variable_spans(
313 &mut self,
314 variable: usize,
315 span: Option<Span>,
316 name_span: Option<Span>,
317 ) -> std::result::Result<(), SourceMappingError> {
318 self.set_declaration_spans(DeclarationTable::PlayerVariables, variable, span, name_span)
319 }
320
321 pub fn set_subroutine_spans(
323 &mut self,
324 subroutine: usize,
325 span: Option<Span>,
326 name_span: Option<Span>,
327 ) -> std::result::Result<(), SourceMappingError> {
328 self.set_declaration_spans(DeclarationTable::Subroutines, subroutine, span, name_span)
329 }
330
331 fn set_declaration_spans(
332 &mut self,
333 table: DeclarationTable,
334 index: usize,
335 span: Option<Span>,
336 name_span: Option<Span>,
337 ) -> std::result::Result<(), SourceMappingError> {
338 self.validate_span(span)?;
339 self.validate_span(name_span)?;
340 let count = table.count(self);
341 if index >= count {
342 return Err(table.invalid(index));
343 }
344 let slots = table.slots(self.provenance_mut());
345 fit(slots, count);
346 slots[index] = DeclarationProvenance { span, name_span };
347 Ok(())
348 }
349
350 pub fn rule_span(&self, rule: usize) -> Option<crate::source::Span> {
356 self.rule_provenance(rule)?.span
357 }
358
359 pub fn condition_span(&self, rule: usize, condition: usize) -> Option<crate::source::Span> {
361 self.condition_provenance(rule, condition)?.span
362 }
363
364 pub fn action_span(&self, rule: usize, action: usize) -> Option<crate::source::Span> {
366 self.action_provenance(rule, action)?.span
367 }
368
369 pub fn action_argument_span(
371 &self,
372 rule: usize,
373 action: usize,
374 argument: usize,
375 ) -> Option<crate::source::Span> {
376 self.action_provenance(rule, action)?
377 .arguments
378 .get(argument)?
379 .span
380 }
381
382 pub fn global_variable_name_span(&self, variable: usize) -> Option<Span> {
389 self.declaration_name_span(
390 |provenance| &provenance.global_variables,
391 self.global_variables.len(),
392 variable,
393 )
394 }
395
396 pub fn player_variable_name_span(&self, variable: usize) -> Option<Span> {
399 self.declaration_name_span(
400 |provenance| &provenance.player_variables,
401 self.player_variables.len(),
402 variable,
403 )
404 }
405
406 pub fn subroutine_name_span(&self, subroutine: usize) -> Option<Span> {
409 self.declaration_name_span(
410 |provenance| &provenance.subroutines,
411 self.subroutines.len(),
412 subroutine,
413 )
414 }
415
416 pub fn action_identifier_span(&self, rule: usize, action: usize) -> Option<Span> {
428 self.action_provenance(rule, action)?.identifier
429 }
430
431 pub fn rule_name_span(&self, rule: usize) -> Option<Span> {
434 self.rule_provenance(rule)?.name
435 }
436
437 pub fn rule_event_name_span(&self, rule: usize) -> Option<Span> {
441 self.rule_provenance(rule)?.event_name
442 }
443
444 pub fn condition_value_span(
459 &self,
460 rule: usize,
461 condition: usize,
462 path: &[usize],
463 ) -> Option<crate::source::Span> {
464 let mut value = self.condition_provenance(rule, condition)?;
465 for &index in path {
466 value = value.children.get(index)?;
467 }
468 value.identifier.or(value.span)
469 }
470
471 pub fn action_argument_value_span(
481 &self,
482 rule: usize,
483 action: usize,
484 argument: usize,
485 path: &[usize],
486 ) -> Option<crate::source::Span> {
487 let mut value = self
488 .action_provenance(rule, action)?
489 .arguments
490 .get(argument)?;
491 for &index in path {
492 value = value.children.get(index)?;
493 }
494 value.identifier.or(value.span)
495 }
496
497 pub fn edit_source(
500 &self,
501 span: crate::source::Span,
502 replacement: impl Into<String>,
503 ) -> std::result::Result<crate::source::SourceEdit, crate::source::SourceEditError> {
504 self.source(span.file)
505 .ok_or(crate::source::SourceEditError::InvalidRange)?
506 .edit_span(span, replacement)
507 }
508
509 pub fn validate(&self) -> std::result::Result<(), WorkshopError> {
511 let storage = self.to_wir()?;
512 storage
513 .validate()
514 .map_err(|error| WorkshopError::Malformed {
515 message: error.to_string(),
516 span: error.span(),
517 })
518 }
519
520 pub fn semantic_issues(
523 &self,
524 catalog: &crate::catalog::Catalog,
525 ) -> Vec<crate::rules::SemanticIssue> {
526 crate::analysis::semantic::inspect(self, catalog)
527 }
528
529 pub fn dump(&self) -> String {
531 self.to_wir().map_or_else(
532 |error| format!("invalid program: {error}"),
533 |program| program.dump(),
534 )
535 }
536
537 fn rule_provenance(&self, rule: usize) -> Option<&RuleProvenance> {
538 let recorded = &self.provenance.as_deref()?.rules;
539 if recorded.len() != self.rules.len() {
540 return None;
541 }
542 recorded.get(rule)
543 }
544
545 fn action_provenance(&self, rule: usize, action: usize) -> Option<&ActionProvenance> {
546 let recorded = self.rule_provenance(rule)?;
547 if recorded.actions.len() != self.rules[rule].actions.len() {
548 return None;
549 }
550 recorded.actions.get(action)
551 }
552
553 fn condition_provenance(&self, rule: usize, condition: usize) -> Option<&ValueProvenance> {
554 let recorded = self.rule_provenance(rule)?;
555 if recorded.conditions.len() != self.rules[rule].conditions.len() {
556 return None;
557 }
558 recorded.conditions.get(condition)
559 }
560
561 fn declaration_name_span(
562 &self,
563 recorded: impl Fn(&ProgramProvenance) -> &[DeclarationProvenance],
564 count: usize,
565 position: usize,
566 ) -> Option<Span> {
567 let declaration = self.declaration_provenance(recorded, count, position);
568 declaration.name_span.or(declaration.span)
569 }
570
571 fn declaration_provenance(
572 &self,
573 recorded: impl Fn(&ProgramProvenance) -> &[DeclarationProvenance],
574 count: usize,
575 position: usize,
576 ) -> DeclarationProvenance {
577 self.provenance
578 .as_deref()
579 .map(recorded)
580 .filter(|recorded| recorded.len() == count)
581 .and_then(|recorded| recorded.get(position))
582 .copied()
583 .unwrap_or_default()
584 }
585
586 fn validate_span(&self, span: Option<Span>) -> std::result::Result<(), SourceMappingError> {
587 let Some(span) = span else {
588 return Ok(());
589 };
590 if !span.is_valid() {
591 return Err(SourceMappingError::InvalidSpan(span));
592 }
593 if self.files.get(span.file.index()).is_none() {
594 return Err(SourceMappingError::UnknownFile(span.file));
595 }
596 Ok(())
597 }
598
599 fn provenance_mut(&mut self) -> &mut ProgramProvenance {
600 self.provenance
601 .get_or_insert_with(|| Box::new(ProgramProvenance::default()))
602 .as_mut()
603 }
604
605 fn rule_provenance_mut(
606 &mut self,
607 rule: usize,
608 ) -> std::result::Result<&mut RuleProvenance, SourceMappingError> {
609 if rule >= self.rules.len() {
610 return Err(SourceMappingError::InvalidRule(rule));
611 }
612 let rule_count = self.rules.len();
613 let provenance = self.provenance_mut();
614 fit(&mut provenance.rules, rule_count);
615 Ok(&mut provenance.rules[rule])
616 }
617
618 fn action_provenance_mut(
619 &mut self,
620 rule: usize,
621 action: usize,
622 ) -> std::result::Result<&mut ActionProvenance, SourceMappingError> {
623 let action_count = self
624 .rules
625 .get(rule)
626 .ok_or(SourceMappingError::InvalidRule(rule))?
627 .actions
628 .len();
629 if action >= action_count {
630 return Err(SourceMappingError::InvalidAction { rule, action });
631 }
632 let rule_data = self.rule_provenance_mut(rule)?;
633 fit(&mut rule_data.actions, action_count);
634 Ok(&mut rule_data.actions[action])
635 }
636}
637
638fn fit<T: Default>(items: &mut Vec<T>, len: usize) {
639 items.truncate(len);
640 items.resize_with(len, T::default);
641}
642
643#[derive(Copy, Clone)]
646enum DeclarationTable {
647 GlobalVariables,
648 PlayerVariables,
649 Subroutines,
650}
651
652impl DeclarationTable {
653 fn count(self, program: &Program) -> usize {
654 match self {
655 Self::GlobalVariables => program.global_variables.len(),
656 Self::PlayerVariables => program.player_variables.len(),
657 Self::Subroutines => program.subroutines.len(),
658 }
659 }
660
661 fn invalid(self, index: usize) -> SourceMappingError {
662 match self {
663 Self::GlobalVariables => SourceMappingError::InvalidGlobalVariable(index),
664 Self::PlayerVariables => SourceMappingError::InvalidPlayerVariable(index),
665 Self::Subroutines => SourceMappingError::InvalidSubroutine(index),
666 }
667 }
668
669 fn slots(self, provenance: &mut ProgramProvenance) -> &mut Vec<DeclarationProvenance> {
670 match self {
671 Self::GlobalVariables => &mut provenance.global_variables,
672 Self::PlayerVariables => &mut provenance.player_variables,
673 Self::Subroutines => &mut provenance.subroutines,
674 }
675 }
676}
677
678#[derive(Debug, Clone, PartialEq, Eq)]
680pub struct Variable {
681 pub name: String,
682 pub index: Option<u32>,
684}
685
686impl Variable {
687 pub fn new(name: impl Into<String>) -> Self {
688 Self {
689 name: name.into(),
690 index: None,
691 }
692 }
693
694 pub fn with_index(name: impl Into<String>, index: u32) -> Self {
695 Self {
696 name: name.into(),
697 index: Some(index),
698 }
699 }
700}
701
702#[derive(Debug, Clone, PartialEq, Eq)]
704pub struct Subroutine {
705 pub name: String,
706 pub index: Option<u32>,
708}
709
710impl Subroutine {
711 pub fn new(name: impl Into<String>) -> Self {
712 Self {
713 name: name.into(),
714 index: None,
715 }
716 }
717
718 pub fn with_index(name: impl Into<String>, index: u32) -> Self {
719 Self {
720 name: name.into(),
721 index: Some(index),
722 }
723 }
724}
725
726#[derive(Debug, Clone)]
728#[non_exhaustive]
729pub struct Rule {
730 pub name: String,
731 pub disabled: bool,
732 pub event: Event,
733 pub conditions: Vec<Condition>,
734 pub actions: Vec<Action>,
735}
736
737impl Rule {
738 pub fn new(name: impl Into<String>, event: Event) -> Self {
739 Self {
740 name: name.into(),
741 disabled: false,
742 event,
743 conditions: Vec::new(),
744 actions: Vec::new(),
745 }
746 }
747
748 pub fn condition(mut self, condition: impl Into<Condition>) -> Self {
749 self.conditions.push(condition.into());
750 self
751 }
752
753 pub fn action(mut self, action: Action) -> Self {
754 self.actions.push(action);
755 self
756 }
757}
758
759#[derive(Debug, Clone)]
761#[non_exhaustive]
762pub struct Condition {
763 pub value: Value,
764 pub disabled: bool,
765}
766
767impl Condition {
768 pub fn new(value: Value) -> Self {
769 Self {
770 value,
771 disabled: false,
772 }
773 }
774
775 pub fn disabled(value: Value) -> Self {
776 Self {
777 value,
778 disabled: true,
779 }
780 }
781}
782
783impl From<Value> for Condition {
784 fn from(value: Value) -> Self {
785 Self::new(value)
786 }
787}
788
789fn action_argument_values(action: &Action) -> Vec<&Value> {
791 match action {
792 Action::SetGlobalVariable { value, .. } | Action::ModifyGlobalVariable { value, .. } => {
793 vec![value]
794 }
795 Action::SetPlayerVariable { player, value, .. }
796 | Action::ModifyPlayerVariable { player, value, .. } => vec![player, value],
797 Action::AssignMember { target, value, .. } => vec![target, value],
798 Action::If { condition } | Action::ElseIf { condition } | Action::While { condition } => {
799 vec![condition]
800 }
801 Action::ForGlobalVariable {
802 start, stop, step, ..
803 } => vec![start, stop, step],
804 Action::ForPlayerVariable {
805 player,
806 start,
807 stop,
808 step,
809 ..
810 } => vec![player, start, stop, step],
811 Action::Call { args, .. } => args.iter().collect(),
812 Action::CallSubroutine { .. } | Action::Else | Action::End => Vec::new(),
813 Action::Disabled { action } => action_argument_values(action),
814 }
815}
816
817fn value_children(value: &Value) -> Vec<&Value> {
820 match value {
821 Value::Array(values) => values.iter().collect(),
822 Value::Vector { x, y, z } => vec![x.as_ref(), y.as_ref(), z.as_ref()],
823 Value::PlayerVariable { player, .. } => vec![player.as_ref()],
824 Value::Call { args, .. } => args.iter().collect(),
825 _ => Vec::new(),
826 }
827}
828
829fn action_argument_count(action: &Action) -> usize {
830 match action {
831 Action::SetGlobalVariable { .. }
832 | Action::ModifyGlobalVariable { .. }
833 | Action::If { .. }
834 | Action::ElseIf { .. }
835 | Action::While { .. } => 1,
836 Action::SetPlayerVariable { .. } | Action::ModifyPlayerVariable { .. } => 2,
837 Action::AssignMember { .. } => 2,
838 Action::ForGlobalVariable { .. } => 3,
839 Action::ForPlayerVariable { .. } => 4,
840 Action::Call { args, .. } => args.len(),
841 Action::CallSubroutine { .. } | Action::Else | Action::End => 0,
842 Action::Disabled { action } => action_argument_count(action),
843 }
844}
845
846#[derive(Debug, Clone, PartialEq, Eq)]
848pub enum Event {
849 Global,
850 EachPlayer,
851 EachPlayerWithFilters {
852 team: EventTeam,
853 target: EventTarget,
854 },
855 Player {
856 kind: PlayerEventKind,
857 team: EventTeam,
858 target: EventTarget,
859 },
860 Subroutine(String),
861}
862
863#[derive(Debug, Clone)]
866pub enum Action {
867 SetGlobalVariable {
868 variable: String,
869 value: Value,
870 },
871 ModifyGlobalVariable {
872 variable: String,
873 op: ModifyOp,
874 value: Value,
875 },
876 SetPlayerVariable {
877 player: Value,
878 variable: String,
879 value: Value,
880 },
881 ModifyPlayerVariable {
882 player: Value,
883 variable: String,
884 op: ModifyOp,
885 value: Value,
886 },
887 AssignMember {
888 target: Value,
889 op: Option<ModifyOp>,
890 value: Value,
891 },
892 CallSubroutine {
893 subroutine: String,
894 },
895 If {
896 condition: Value,
897 },
898 ElseIf {
899 condition: Value,
900 },
901 Else,
902 While {
903 condition: Value,
904 },
905 ForGlobalVariable {
906 variable: String,
907 start: Value,
908 stop: Value,
909 step: Value,
910 },
911 ForPlayerVariable {
912 player: Value,
913 variable: String,
914 start: Value,
915 stop: Value,
916 step: Value,
917 },
918 End,
919 Disabled {
920 action: Box<Action>,
921 },
922 Call {
923 name: String,
924 args: Vec<Value>,
925 },
926}
927
928impl Action {
929 pub fn disabled(action: Action) -> Self {
931 Self::Disabled {
932 action: Box::new(action),
933 }
934 }
935
936 pub fn call(name: impl Into<String>, args: impl IntoIterator<Item = Value>) -> Self {
938 Self::Call {
939 name: name.into(),
940 args: args.into_iter().collect(),
941 }
942 }
943}
944
945#[derive(Debug, Clone)]
947pub enum Value {
948 Number(f64),
949 String(String),
950 LocalizedString(String),
951 Bool(bool),
952 Null,
953 Array(Vec<Value>),
954 Vector {
955 x: Box<Value>,
956 y: Box<Value>,
957 z: Box<Value>,
958 },
959 Enum {
960 value_type: String,
961 value: String,
962 },
963 GlobalVariable(String),
964 PlayerVariable {
965 player: Box<Value>,
966 variable: String,
967 },
968 Subroutine(String),
969 EventPlayer,
970 Call {
971 name: String,
972 args: Vec<Value>,
973 },
974}
975
976impl Value {
977 pub fn number(value: f64) -> Self {
979 Self::Number(value)
980 }
981
982 pub fn string(value: impl Into<String>) -> Self {
984 Self::String(value.into())
985 }
986
987 pub fn global_variable(name: impl Into<String>) -> Self {
988 Self::GlobalVariable(name.into())
989 }
990
991 pub fn player_variable(player: Value, name: impl Into<String>) -> Self {
992 Self::PlayerVariable {
993 player: Box::new(player),
994 variable: name.into(),
995 }
996 }
997
998 pub fn call(name: impl Into<String>, args: impl IntoIterator<Item = Value>) -> Self {
1000 Self::Call {
1001 name: name.into(),
1002 args: args.into_iter().collect(),
1003 }
1004 }
1005}
1006
1007impl From<bool> for Value {
1008 fn from(value: bool) -> Self {
1009 Self::Bool(value)
1010 }
1011}
1012
1013impl From<f64> for Value {
1014 fn from(value: f64) -> Self {
1015 Self::Number(value)
1016 }
1017}
1018
1019impl From<f32> for Value {
1020 fn from(value: f32) -> Self {
1021 Self::Number(f64::from(value))
1022 }
1023}
1024
1025macro_rules! impl_integer_value {
1026 ($($type:ty),+ $(,)?) => {
1027 $(
1028 impl From<$type> for Value {
1029 fn from(value: $type) -> Self {
1030 Self::Number(value as f64)
1031 }
1032 }
1033 )+
1034 };
1035}
1036
1037impl_integer_value!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
1038
1039impl From<String> for Value {
1040 fn from(value: String) -> Self {
1041 Self::String(value)
1042 }
1043}
1044
1045impl From<&str> for Value {
1046 fn from(value: &str) -> Self {
1047 Self::String(value.to_string())
1048 }
1049}
1050
1051impl<T: Into<Value>> From<Vec<T>> for Value {
1052 fn from(values: Vec<T>) -> Self {
1053 Self::Array(values.into_iter().map(Into::into).collect())
1054 }
1055}
1056
1057impl<T: Into<Value>, const N: usize> From<[T; N]> for Value {
1058 fn from(values: [T; N]) -> Self {
1059 Self::Array(values.into_iter().map(Into::into).collect())
1060 }
1061}