1use self::identity::{
4 NodeIdentity, action_identity, condition_identity, declaration_identity, rule_identity,
5 value_identity,
6};
7use crate::core::error::WorkshopError;
8use crate::settings::Settings;
9use crate::source::{FileId, SourceDocument, SourceFile, Span};
10
11mod conversion;
12mod identity;
13pub(crate) mod shared;
14mod source_map;
15pub use shared::{EventTarget, EventTeam, ModifyOp, PlayerEventKind};
16pub use source_map::{MAPPED_TEXT_V1, MappedText, SourceMap, SourceMapError, TEXT_V1};
17
18#[derive(Debug, Clone, Default)]
20pub struct Program {
21 pub settings: Option<Settings>,
22 pub global_variables: Vec<Variable>,
23 pub player_variables: Vec<Variable>,
24 pub subroutines: Vec<Subroutine>,
25 pub rules: Vec<Rule>,
26 files: Vec<SourceFile>,
27 provenance: Option<Box<ProgramProvenance>>,
28}
29
30#[derive(Debug, Clone, Default)]
31struct ProgramProvenance {
32 global_variables: Vec<DeclarationProvenance>,
33 player_variables: Vec<DeclarationProvenance>,
34 subroutines: Vec<DeclarationProvenance>,
35 rules: Vec<RuleProvenance>,
36}
37
38#[derive(Debug, Clone, Copy, Default)]
39struct DeclarationProvenance {
40 span: Option<Span>,
41 name_span: Option<Span>,
42 identity: NodeIdentity,
44}
45
46#[derive(Debug, Clone, Default)]
47struct RuleProvenance {
48 span: Option<crate::source::Span>,
49 name: Option<Span>,
51 event_name: Option<Span>,
53 identity: NodeIdentity,
55 conditions: Vec<ValueProvenance>,
56 actions: Vec<ActionProvenance>,
57}
58
59impl RuleProvenance {
60 fn reseat(&mut self, identity: NodeIdentity) {
64 if self.identity != identity {
65 self.span = None;
66 self.name = None;
67 self.event_name = None;
68 }
69 self.identity = identity;
70 }
71}
72
73#[derive(Debug, Clone, Default)]
74struct ActionProvenance {
75 span: Option<Span>,
76 identifier: Option<Span>,
79 identity: NodeIdentity,
81 arguments: Vec<ValueProvenance>,
82}
83
84trait SpanSlot {
87 fn span_slot(&mut self) -> &mut Option<Span>;
88 fn reseat(&mut self, identity: NodeIdentity);
92}
93
94impl SpanSlot for ValueProvenance {
95 fn span_slot(&mut self) -> &mut Option<Span> {
96 &mut self.span
97 }
98 fn reseat(&mut self, identity: NodeIdentity) {
99 if self.identity != identity {
100 self.span = None;
101 self.identifier = None;
102 }
103 self.identity = identity;
104 }
105}
106
107impl SpanSlot for ActionProvenance {
108 fn span_slot(&mut self) -> &mut Option<Span> {
109 &mut self.span
110 }
111 fn reseat(&mut self, identity: NodeIdentity) {
112 if self.identity != identity {
113 self.span = None;
114 self.identifier = None;
115 }
116 self.identity = identity;
117 }
118}
119
120fn prune_spans_outside(
127 provenance: &mut ProgramProvenance,
128 file: FileId,
129 document: &SourceDocument,
130) {
131 fn prune_slot(slot: &mut Option<Span>, file: FileId, document: &SourceDocument) {
132 if let Some(span) = slot {
133 if span.file == file && document.byte_range(*span).is_none() {
134 *slot = None;
135 }
136 }
137 }
138 fn prune_value(record: &mut ValueProvenance, file: FileId, document: &SourceDocument) {
139 prune_slot(&mut record.span, file, document);
140 prune_slot(&mut record.identifier, file, document);
141 for child in &mut record.children {
142 prune_value(child, file, document);
143 }
144 }
145 for declaration in provenance
146 .global_variables
147 .iter_mut()
148 .chain(&mut provenance.player_variables)
149 .chain(&mut provenance.subroutines)
150 {
151 prune_slot(&mut declaration.span, file, document);
152 prune_slot(&mut declaration.name_span, file, document);
153 }
154 for rule in &mut provenance.rules {
155 prune_slot(&mut rule.span, file, document);
156 prune_slot(&mut rule.name, file, document);
157 prune_slot(&mut rule.event_name, file, document);
158 for condition in &mut rule.conditions {
159 prune_value(condition, file, document);
160 }
161 for action in &mut rule.actions {
162 prune_slot(&mut action.span, file, document);
163 prune_slot(&mut action.identifier, file, document);
164 for argument in &mut action.arguments {
165 prune_value(argument, file, document);
166 }
167 }
168 }
169}
170
171#[derive(Debug, Clone, Default)]
172struct ValueProvenance {
173 span: Option<Span>,
174 identifier: Option<Span>,
177 identity: NodeIdentity,
179 children: Vec<ValueProvenance>,
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184#[non_exhaustive]
185pub enum SourceMappingError {
186 UnknownFile(FileId),
187 InvalidSpan(Span),
188 InvalidRule(usize),
189 InvalidCondition {
190 rule: usize,
191 condition: usize,
192 },
193 InvalidAction {
194 rule: usize,
195 action: usize,
196 },
197 InvalidActionArgument {
198 rule: usize,
199 action: usize,
200 argument: usize,
201 },
202 InvalidGlobalVariable(usize),
203 InvalidPlayerVariable(usize),
204 InvalidSubroutine(usize),
205}
206
207impl std::fmt::Display for SourceMappingError {
208 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 match self {
210 Self::UnknownFile(file) => {
211 write!(formatter, "source span references unknown file {file}")
212 }
213 Self::InvalidSpan(span) => write!(formatter, "invalid source span {span:?}"),
214 Self::InvalidRule(rule) => write!(formatter, "invalid rule index {rule}"),
215 Self::InvalidCondition { rule, condition } => {
216 write!(
217 formatter,
218 "invalid condition index {condition} in rule {rule}"
219 )
220 }
221 Self::InvalidAction { rule, action } => {
222 write!(formatter, "invalid action index {action} in rule {rule}")
223 }
224 Self::InvalidActionArgument {
225 rule,
226 action,
227 argument,
228 } => write!(
229 formatter,
230 "invalid argument index {argument} in action {action} of rule {rule}"
231 ),
232 Self::InvalidGlobalVariable(variable) => {
233 write!(formatter, "invalid global variable index {variable}")
234 }
235 Self::InvalidPlayerVariable(variable) => {
236 write!(formatter, "invalid player variable index {variable}")
237 }
238 Self::InvalidSubroutine(subroutine) => {
239 write!(formatter, "invalid subroutine index {subroutine}")
240 }
241 }
242 }
243}
244
245impl std::error::Error for SourceMappingError {}
246
247impl Program {
248 pub fn new() -> Self {
249 Self::default()
250 }
251
252 pub fn add_file(&mut self, mut file: SourceFile) -> FileId {
254 let id = FileId::from_index(self.files.len());
255 file.bind_file(id);
256 self.files.push(file);
257 id
258 }
259
260 pub fn global_variable(&mut self, variable: Variable) -> &mut Self {
261 self.global_variables.push(variable);
262 self
263 }
264
265 pub fn player_variable(&mut self, variable: Variable) -> &mut Self {
266 self.player_variables.push(variable);
267 self
268 }
269
270 pub fn subroutine(&mut self, subroutine: Subroutine) -> &mut Self {
271 self.subroutines.push(subroutine);
272 self
273 }
274
275 pub fn rule(&mut self, rule: Rule) -> &mut Self {
276 self.rules.push(rule);
277 self
278 }
279
280 pub fn source(&self, file: FileId) -> Option<&SourceDocument> {
282 self.files.get(file.index()).and_then(SourceFile::source)
283 }
284
285 pub fn set_file_source(&mut self, file: FileId, source: impl Into<String>) -> bool {
297 let Some(entry) = self.files.get_mut(file.index()) else {
298 return false;
299 };
300 entry.set_source(source);
301 if let (Some(provenance), Some(document)) = (
302 self.provenance.as_mut(),
303 self.files.get(file.index()).and_then(SourceFile::source),
304 ) {
305 prune_spans_outside(provenance, file, document);
306 }
307 true
308 }
309
310 pub fn set_rule_span(
312 &mut self,
313 rule: usize,
314 span: Option<Span>,
315 ) -> std::result::Result<(), SourceMappingError> {
316 self.validate_span(span)?;
317 self.rule_provenance_mut(rule)?.span = span;
318 Ok(())
319 }
320
321 pub fn set_condition_span(
323 &mut self,
324 rule: usize,
325 condition: usize,
326 span: Option<Span>,
327 ) -> std::result::Result<(), SourceMappingError> {
328 self.set_child_span(
329 rule,
330 condition,
331 span,
332 |rule| rule.conditions.len(),
333 |rule, index| condition_identity(&rule.conditions[index]),
334 |rule, index| SourceMappingError::InvalidCondition {
335 rule,
336 condition: index,
337 },
338 |rule_data| &mut rule_data.conditions,
339 )
340 }
341
342 pub fn set_action_span(
344 &mut self,
345 rule: usize,
346 action: usize,
347 span: Option<Span>,
348 ) -> std::result::Result<(), SourceMappingError> {
349 self.set_child_span(
350 rule,
351 action,
352 span,
353 |rule| rule.actions.len(),
354 |rule, index| action_identity(&rule.actions[index]),
355 |rule, index| SourceMappingError::InvalidAction {
356 rule,
357 action: index,
358 },
359 |rule_data| &mut rule_data.actions,
360 )
361 }
362
363 #[allow(clippy::too_many_arguments)]
369 fn set_child_span<T: SpanSlot + Default>(
370 &mut self,
371 rule: usize,
372 index: usize,
373 span: Option<Span>,
374 count: impl Fn(&crate::Rule) -> usize,
375 identity: impl Fn(&crate::Rule, usize) -> NodeIdentity,
376 invalid: impl Fn(usize, usize) -> SourceMappingError,
377 slots: impl Fn(&mut RuleProvenance) -> &mut Vec<T>,
378 ) -> std::result::Result<(), SourceMappingError> {
379 self.validate_span(span)?;
380 let public = self
381 .rules
382 .get(rule)
383 .ok_or(SourceMappingError::InvalidRule(rule))?;
384 let child_count = count(public);
385 if index >= child_count {
386 return Err(invalid(rule, index));
387 }
388 let identity = identity(public, index);
389 let rule_data = self.rule_provenance_mut(rule)?;
390 fit(slots(rule_data), child_count);
391 let record = &mut slots(rule_data)[index];
392 record.reseat(identity);
393 *record.span_slot() = span;
394 Ok(())
395 }
396
397 pub fn set_action_argument_span(
399 &mut self,
400 rule: usize,
401 action: usize,
402 argument: usize,
403 span: Option<Span>,
404 ) -> std::result::Result<(), SourceMappingError> {
405 self.validate_span(span)?;
406 let (identity, argument_count) = {
407 let action_value = self
408 .rules
409 .get(rule)
410 .ok_or(SourceMappingError::InvalidRule(rule))?
411 .actions
412 .get(action)
413 .ok_or(SourceMappingError::InvalidAction { rule, action })?;
414 let argument_values = action_argument_values(action_value);
415 let Some(&argument_value) = argument_values.get(argument) else {
416 return Err(SourceMappingError::InvalidActionArgument {
417 rule,
418 action,
419 argument,
420 });
421 };
422 (value_identity(argument_value), argument_values.len())
423 };
424 let action_data = self.action_provenance_mut(rule, action)?;
425 fit(&mut action_data.arguments, argument_count);
426 let record = &mut action_data.arguments[argument];
427 record.reseat(identity);
428 record.span = span;
429 Ok(())
430 }
431
432 pub fn set_global_variable_spans(
434 &mut self,
435 variable: usize,
436 span: Option<Span>,
437 name_span: Option<Span>,
438 ) -> std::result::Result<(), SourceMappingError> {
439 self.set_declaration_spans(DeclarationTable::GlobalVariables, variable, span, name_span)
440 }
441
442 pub fn set_player_variable_spans(
444 &mut self,
445 variable: usize,
446 span: Option<Span>,
447 name_span: Option<Span>,
448 ) -> std::result::Result<(), SourceMappingError> {
449 self.set_declaration_spans(DeclarationTable::PlayerVariables, variable, span, name_span)
450 }
451
452 pub fn set_subroutine_spans(
454 &mut self,
455 subroutine: usize,
456 span: Option<Span>,
457 name_span: Option<Span>,
458 ) -> std::result::Result<(), SourceMappingError> {
459 self.set_declaration_spans(DeclarationTable::Subroutines, subroutine, span, name_span)
460 }
461
462 fn set_declaration_spans(
463 &mut self,
464 table: DeclarationTable,
465 index: usize,
466 span: Option<Span>,
467 name_span: Option<Span>,
468 ) -> std::result::Result<(), SourceMappingError> {
469 self.validate_span(span)?;
470 self.validate_span(name_span)?;
471 let count = table.count(self);
472 if index >= count {
473 return Err(table.invalid(index));
474 }
475 let identity = table.identity(self, index);
476 let slots = table.slots(self.provenance_mut());
477 fit(slots, count);
478 slots[index] = DeclarationProvenance {
479 span,
480 name_span,
481 identity,
482 };
483 Ok(())
484 }
485
486 pub fn rule_span(&self, rule: usize) -> Option<crate::source::Span> {
494 self.rule_provenance(rule)?.span
495 }
496
497 pub fn condition_span(&self, rule: usize, condition: usize) -> Option<crate::source::Span> {
499 self.condition_provenance(rule, condition)?.span
500 }
501
502 pub fn action_span(&self, rule: usize, action: usize) -> Option<crate::source::Span> {
504 self.action_provenance(rule, action)?.span
505 }
506
507 pub fn action_argument_span(
509 &self,
510 rule: usize,
511 action: usize,
512 argument: usize,
513 ) -> Option<crate::source::Span> {
514 self.action_argument_provenance(rule, action, argument)?
515 .span
516 }
517
518 pub fn global_variable_name_span(&self, variable: usize) -> Option<Span> {
525 self.declaration_name_span(
526 |provenance| &provenance.global_variables,
527 &self.global_variables,
528 variable,
529 )
530 }
531
532 pub fn player_variable_name_span(&self, variable: usize) -> Option<Span> {
535 self.declaration_name_span(
536 |provenance| &provenance.player_variables,
537 &self.player_variables,
538 variable,
539 )
540 }
541
542 pub fn subroutine_name_span(&self, subroutine: usize) -> Option<Span> {
545 self.declaration_name_span(
546 |provenance| &provenance.subroutines,
547 &self.subroutines,
548 subroutine,
549 )
550 }
551
552 pub fn action_identifier_span(&self, rule: usize, action: usize) -> Option<Span> {
564 self.action_provenance(rule, action)?.identifier
565 }
566
567 pub fn rule_name_span(&self, rule: usize) -> Option<Span> {
570 self.rule_provenance(rule)?.name
571 }
572
573 pub fn rule_event_name_span(&self, rule: usize) -> Option<Span> {
577 self.rule_provenance(rule)?.event_name
578 }
579
580 pub fn condition_value_span(
595 &self,
596 rule: usize,
597 condition: usize,
598 path: &[usize],
599 ) -> Option<crate::source::Span> {
600 let record = self.condition_value_record(rule, condition, path)?;
601 record.identifier.or(record.span)
602 }
603
604 fn condition_value_record(
609 &self,
610 rule: usize,
611 condition: usize,
612 path: &[usize],
613 ) -> Option<&ValueProvenance> {
614 let record = self.condition_record(rule, condition)?;
615 let value = &self.rules[rule].conditions[condition].value;
616 let identity = condition_identity(&self.rules[rule].conditions[condition]);
617 value_provenance_at(record, value, path, identity)
618 }
619
620 pub(crate) fn condition_value_node_span(
625 &self,
626 rule: usize,
627 condition: usize,
628 path: &[usize],
629 ) -> Option<crate::source::Span> {
630 self.condition_value_record(rule, condition, path)?.span
631 }
632
633 pub fn action_argument_value_span(
643 &self,
644 rule: usize,
645 action: usize,
646 argument: usize,
647 path: &[usize],
648 ) -> Option<crate::source::Span> {
649 let record = self.action_argument_value_record(rule, action, argument, path)?;
650 record.identifier.or(record.span)
651 }
652
653 fn action_argument_value_record(
657 &self,
658 rule: usize,
659 action: usize,
660 argument: usize,
661 path: &[usize],
662 ) -> Option<&ValueProvenance> {
663 let record = self.argument_record(rule, action, argument)?;
664 let value = action_argument_values(&self.rules[rule].actions[action])[argument];
665 value_provenance_at(record, value, path, value_identity(value))
666 }
667
668 pub(crate) fn action_argument_value_node_span(
673 &self,
674 rule: usize,
675 action: usize,
676 argument: usize,
677 path: &[usize],
678 ) -> Option<crate::source::Span> {
679 self.action_argument_value_record(rule, action, argument, path)?
680 .span
681 }
682
683 pub fn edit_source(
686 &self,
687 span: crate::source::Span,
688 replacement: impl Into<String>,
689 ) -> std::result::Result<crate::source::SourceEdit, crate::source::SourceEditError> {
690 self.source(span.file)
691 .ok_or(crate::source::SourceEditError::InvalidRange)?
692 .edit_span(span, replacement)
693 }
694
695 pub fn validate(&self) -> std::result::Result<(), WorkshopError> {
700 let storage = self.to_wir()?;
701 storage
702 .validate()
703 .map_err(|error| WorkshopError::malformed(error.to_string(), error.span()))?;
704 if let Some(settings) = &self.settings {
705 if let Some(error) = crate::settings::check_emission(settings).into_iter().next() {
706 return Err(error);
707 }
708 }
709 Ok(())
710 }
711
712 pub fn settings_diagnostics(&self) -> Vec<crate::settings::SettingsDiagnostic> {
722 self.settings
723 .as_ref()
724 .map(crate::settings::check_emission_diagnostics)
725 .unwrap_or_default()
726 }
727
728 pub fn semantic_issues(
738 &self,
739 catalog: &crate::catalog::Catalog,
740 ) -> Vec<crate::rules::SemanticIssue> {
741 crate::analysis::semantic::inspect(self, catalog)
742 }
743
744 pub fn dump(&self) -> String {
746 self.to_wir().map_or_else(
747 |error| format!("invalid program: {error}"),
748 |program| program.dump(),
749 )
750 }
751
752 fn rule_record(&self, rule: usize) -> Option<&RuleProvenance> {
758 let recorded = &self.provenance.as_deref()?.rules;
759 if recorded.len() != self.rules.len() {
760 return None;
761 }
762 recorded.get(rule)
763 }
764
765 fn rule_provenance(&self, rule: usize) -> Option<&RuleProvenance> {
769 self.rule_record(rule)
770 .filter(|record| record.identity == rule_identity(&self.rules[rule]))
771 }
772
773 fn action_record(&self, rule: usize, action: usize) -> Option<&ActionProvenance> {
774 let recorded = self.rule_record(rule)?;
775 if recorded.actions.len() != self.rules[rule].actions.len() {
776 return None;
777 }
778 recorded.actions.get(action)
779 }
780
781 fn action_provenance(&self, rule: usize, action: usize) -> Option<&ActionProvenance> {
785 self.action_record(rule, action)
786 .filter(|record| record.identity == action_identity(&self.rules[rule].actions[action]))
787 }
788
789 fn argument_record(
790 &self,
791 rule: usize,
792 action: usize,
793 argument: usize,
794 ) -> Option<&ValueProvenance> {
795 let recorded = self.action_record(rule, action)?;
796 let values = action_argument_values(&self.rules[rule].actions[action]);
797 if recorded.arguments.len() != values.len() {
798 return None;
799 }
800 recorded.arguments.get(argument)
801 }
802
803 fn action_argument_provenance(
807 &self,
808 rule: usize,
809 action: usize,
810 argument: usize,
811 ) -> Option<&ValueProvenance> {
812 let record = self.argument_record(rule, action, argument)?;
813 let values = action_argument_values(&self.rules[rule].actions[action]);
814 (record.identity == value_identity(values[argument])).then_some(record)
815 }
816
817 fn condition_record(&self, rule: usize, condition: usize) -> Option<&ValueProvenance> {
818 let recorded = self.rule_record(rule)?;
819 if recorded.conditions.len() != self.rules[rule].conditions.len() {
820 return None;
821 }
822 recorded.conditions.get(condition)
823 }
824
825 fn condition_provenance(&self, rule: usize, condition: usize) -> Option<&ValueProvenance> {
829 self.condition_record(rule, condition).filter(|record| {
830 record.identity == condition_identity(&self.rules[rule].conditions[condition])
831 })
832 }
833
834 fn declaration_name_span<T: std::fmt::Debug>(
835 &self,
836 recorded: impl Fn(&ProgramProvenance) -> &[DeclarationProvenance],
837 nodes: &[T],
838 position: usize,
839 ) -> Option<Span> {
840 let declaration = self.declaration_provenance(recorded, nodes, position);
841 declaration.name_span.or(declaration.span)
842 }
843
844 fn declaration_provenance<T: std::fmt::Debug>(
845 &self,
846 recorded: impl Fn(&ProgramProvenance) -> &[DeclarationProvenance],
847 nodes: &[T],
848 position: usize,
849 ) -> DeclarationProvenance {
850 self.provenance
851 .as_deref()
852 .map(recorded)
853 .filter(|recorded| recorded.len() == nodes.len())
854 .and_then(|recorded| recorded.get(position).zip(nodes.get(position)))
855 .filter(|(record, node)| record.identity == declaration_identity(node))
856 .map(|(record, _)| *record)
857 .unwrap_or_default()
858 }
859
860 fn validate_span(&self, span: Option<Span>) -> std::result::Result<(), SourceMappingError> {
861 let Some(span) = span else {
862 return Ok(());
863 };
864 if !span.is_valid() {
865 return Err(SourceMappingError::InvalidSpan(span));
866 }
867 if self.files.get(span.file.index()).is_none() {
868 return Err(SourceMappingError::UnknownFile(span.file));
869 }
870 Ok(())
871 }
872
873 fn provenance_mut(&mut self) -> &mut ProgramProvenance {
874 self.provenance
875 .get_or_insert_with(|| Box::new(ProgramProvenance::default()))
876 .as_mut()
877 }
878
879 fn rule_provenance_mut(
883 &mut self,
884 rule: usize,
885 ) -> std::result::Result<&mut RuleProvenance, SourceMappingError> {
886 if rule >= self.rules.len() {
887 return Err(SourceMappingError::InvalidRule(rule));
888 }
889 let identity = rule_identity(&self.rules[rule]);
890 let rule_count = self.rules.len();
891 let provenance = self.provenance_mut();
892 fit(&mut provenance.rules, rule_count);
893 let record = &mut provenance.rules[rule];
894 record.reseat(identity);
895 Ok(record)
896 }
897
898 fn action_provenance_mut(
899 &mut self,
900 rule: usize,
901 action: usize,
902 ) -> std::result::Result<&mut ActionProvenance, SourceMappingError> {
903 let public = self
904 .rules
905 .get(rule)
906 .ok_or(SourceMappingError::InvalidRule(rule))?;
907 let action_count = public.actions.len();
908 if action >= action_count {
909 return Err(SourceMappingError::InvalidAction { rule, action });
910 }
911 let identity = action_identity(&public.actions[action]);
912 let rule_data = self.rule_provenance_mut(rule)?;
913 fit(&mut rule_data.actions, action_count);
914 let record = &mut rule_data.actions[action];
915 record.reseat(identity);
916 Ok(record)
917 }
918
919 fn record_identities(&mut self) {
923 let Some(mut provenance) = self.provenance.take() else {
924 return;
925 };
926 identity::record_identities(&mut provenance, self);
927 self.provenance = Some(provenance);
928 }
929}
930
931fn value_provenance_at<'a>(
938 record: &'a ValueProvenance,
939 value: &'a Value,
940 path: &[usize],
941 root_identity: NodeIdentity,
942) -> Option<&'a ValueProvenance> {
943 let mut record = record;
944 let mut value = value;
945 let mut identity = root_identity;
946 for &index in path {
947 let children = value_children(value);
948 if record.children.len() != children.len() {
949 return None;
950 }
951 record = record.children.get(index)?;
952 value = children[index];
953 identity = value_identity(value);
954 }
955 (record.identity == identity).then_some(record)
956}
957
958fn fit<T: Default>(items: &mut Vec<T>, len: usize) {
959 items.truncate(len);
960 items.resize_with(len, T::default);
961}
962
963#[derive(Copy, Clone)]
966enum DeclarationTable {
967 GlobalVariables,
968 PlayerVariables,
969 Subroutines,
970}
971
972impl DeclarationTable {
973 fn count(self, program: &Program) -> usize {
974 match self {
975 Self::GlobalVariables => program.global_variables.len(),
976 Self::PlayerVariables => program.player_variables.len(),
977 Self::Subroutines => program.subroutines.len(),
978 }
979 }
980
981 fn invalid(self, index: usize) -> SourceMappingError {
982 match self {
983 Self::GlobalVariables => SourceMappingError::InvalidGlobalVariable(index),
984 Self::PlayerVariables => SourceMappingError::InvalidPlayerVariable(index),
985 Self::Subroutines => SourceMappingError::InvalidSubroutine(index),
986 }
987 }
988
989 fn identity(self, program: &Program, index: usize) -> NodeIdentity {
990 match self {
991 Self::GlobalVariables => declaration_identity(&program.global_variables[index]),
992 Self::PlayerVariables => declaration_identity(&program.player_variables[index]),
993 Self::Subroutines => declaration_identity(&program.subroutines[index]),
994 }
995 }
996
997 fn slots(self, provenance: &mut ProgramProvenance) -> &mut Vec<DeclarationProvenance> {
998 match self {
999 Self::GlobalVariables => &mut provenance.global_variables,
1000 Self::PlayerVariables => &mut provenance.player_variables,
1001 Self::Subroutines => &mut provenance.subroutines,
1002 }
1003 }
1004}
1005
1006#[derive(Debug, Clone, PartialEq, Eq)]
1008pub struct Variable {
1009 pub name: String,
1010 pub index: Option<u32>,
1012}
1013
1014impl Variable {
1015 pub fn new(name: impl Into<String>) -> Self {
1016 Self {
1017 name: name.into(),
1018 index: None,
1019 }
1020 }
1021
1022 pub fn with_index(name: impl Into<String>, index: u32) -> Self {
1023 Self {
1024 name: name.into(),
1025 index: Some(index),
1026 }
1027 }
1028}
1029
1030#[derive(Debug, Clone, PartialEq, Eq)]
1032pub struct Subroutine {
1033 pub name: String,
1034 pub index: Option<u32>,
1036}
1037
1038impl Subroutine {
1039 pub fn new(name: impl Into<String>) -> Self {
1040 Self {
1041 name: name.into(),
1042 index: None,
1043 }
1044 }
1045
1046 pub fn with_index(name: impl Into<String>, index: u32) -> Self {
1047 Self {
1048 name: name.into(),
1049 index: Some(index),
1050 }
1051 }
1052}
1053
1054#[derive(Debug, Clone)]
1056#[non_exhaustive]
1057pub struct Rule {
1058 pub name: String,
1059 pub disabled: bool,
1060 pub event: Event,
1061 pub conditions: Vec<Condition>,
1062 pub actions: Vec<Action>,
1063}
1064
1065impl Rule {
1066 pub fn new(name: impl Into<String>, event: Event) -> Self {
1067 Self {
1068 name: name.into(),
1069 disabled: false,
1070 event,
1071 conditions: Vec::new(),
1072 actions: Vec::new(),
1073 }
1074 }
1075
1076 pub fn condition(mut self, condition: impl Into<Condition>) -> Self {
1077 self.conditions.push(condition.into());
1078 self
1079 }
1080
1081 pub fn action(mut self, action: Action) -> Self {
1082 self.actions.push(action);
1083 self
1084 }
1085}
1086
1087#[derive(Debug, Clone)]
1089#[non_exhaustive]
1090pub struct Condition {
1091 pub value: Value,
1092 pub disabled: bool,
1093}
1094
1095impl Condition {
1096 pub fn new(value: Value) -> Self {
1097 Self {
1098 value,
1099 disabled: false,
1100 }
1101 }
1102
1103 pub fn disabled(value: Value) -> Self {
1104 Self {
1105 value,
1106 disabled: true,
1107 }
1108 }
1109}
1110
1111impl From<Value> for Condition {
1112 fn from(value: Value) -> Self {
1113 Self::new(value)
1114 }
1115}
1116
1117pub(crate) fn action_argument_values(action: &Action) -> Vec<&Value> {
1120 match action {
1121 Action::SetGlobalVariable { value, .. } | Action::ModifyGlobalVariable { value, .. } => {
1122 vec![value]
1123 }
1124 Action::SetPlayerVariable { player, value, .. }
1125 | Action::ModifyPlayerVariable { player, value, .. } => vec![player, value],
1126 Action::AssignMember { target, value, .. } => vec![target, value],
1127 Action::If { condition } | Action::ElseIf { condition } | Action::While { condition } => {
1128 vec![condition]
1129 }
1130 Action::ForGlobalVariable {
1131 start, stop, step, ..
1132 } => vec![start, stop, step],
1133 Action::ForPlayerVariable {
1134 player,
1135 start,
1136 stop,
1137 step,
1138 ..
1139 } => vec![player, start, stop, step],
1140 Action::Call { args, .. } => args.iter().collect(),
1141 Action::CallSubroutine { .. } | Action::Else | Action::End => Vec::new(),
1142 Action::Disabled { action } => action_argument_values(action),
1143 }
1144}
1145
1146pub(crate) fn value_children(value: &Value) -> Vec<&Value> {
1149 match value {
1150 Value::Array(values) => values.iter().collect(),
1151 Value::Vector { x, y, z } => vec![x.as_ref(), y.as_ref(), z.as_ref()],
1152 Value::PlayerVariable { player, .. } => vec![player.as_ref()],
1153 Value::Call { args, .. } => args.iter().collect(),
1154 _ => Vec::new(),
1155 }
1156}
1157
1158#[derive(Debug, Clone, PartialEq, Eq)]
1160pub enum Event {
1161 Global,
1162 EachPlayer,
1163 EachPlayerWithFilters {
1164 team: EventTeam,
1165 target: EventTarget,
1166 },
1167 Player {
1168 kind: PlayerEventKind,
1169 team: EventTeam,
1170 target: EventTarget,
1171 },
1172 Subroutine(String),
1173}
1174
1175#[derive(Debug, Clone)]
1178pub enum Action {
1179 SetGlobalVariable {
1180 variable: String,
1181 value: Value,
1182 },
1183 ModifyGlobalVariable {
1184 variable: String,
1185 op: ModifyOp,
1186 value: Value,
1187 },
1188 SetPlayerVariable {
1189 player: Value,
1190 variable: String,
1191 value: Value,
1192 },
1193 ModifyPlayerVariable {
1194 player: Value,
1195 variable: String,
1196 op: ModifyOp,
1197 value: Value,
1198 },
1199 AssignMember {
1200 target: Value,
1201 op: Option<ModifyOp>,
1202 value: Value,
1203 },
1204 CallSubroutine {
1205 subroutine: String,
1206 },
1207 If {
1208 condition: Value,
1209 },
1210 ElseIf {
1211 condition: Value,
1212 },
1213 Else,
1214 While {
1215 condition: Value,
1216 },
1217 ForGlobalVariable {
1218 variable: String,
1219 start: Value,
1220 stop: Value,
1221 step: Value,
1222 },
1223 ForPlayerVariable {
1224 player: Value,
1225 variable: String,
1226 start: Value,
1227 stop: Value,
1228 step: Value,
1229 },
1230 End,
1231 Disabled {
1232 action: Box<Action>,
1233 },
1234 Call {
1235 name: String,
1236 args: Vec<Value>,
1237 },
1238}
1239
1240impl Action {
1241 pub fn disabled(action: Action) -> Self {
1243 Self::Disabled {
1244 action: Box::new(action),
1245 }
1246 }
1247
1248 pub fn call(name: impl Into<String>, args: impl IntoIterator<Item = Value>) -> Self {
1250 Self::Call {
1251 name: name.into(),
1252 args: args.into_iter().collect(),
1253 }
1254 }
1255}
1256
1257#[derive(Debug, Clone)]
1259pub enum Value {
1260 Number(f64),
1261 String(String),
1262 LocalizedString(String),
1263 Bool(bool),
1264 Null,
1265 Array(Vec<Value>),
1266 Vector {
1267 x: Box<Value>,
1268 y: Box<Value>,
1269 z: Box<Value>,
1270 },
1271 Enum {
1272 value_type: String,
1273 value: String,
1274 },
1275 GlobalVariable(String),
1276 PlayerVariable {
1277 player: Box<Value>,
1278 variable: String,
1279 },
1280 Subroutine(String),
1281 EventPlayer,
1282 Call {
1283 name: String,
1284 args: Vec<Value>,
1285 },
1286}
1287
1288impl Value {
1289 pub fn number(value: f64) -> Self {
1291 Self::Number(value)
1292 }
1293
1294 pub fn string(value: impl Into<String>) -> Self {
1296 Self::String(value.into())
1297 }
1298
1299 pub fn global_variable(name: impl Into<String>) -> Self {
1300 Self::GlobalVariable(name.into())
1301 }
1302
1303 pub fn player_variable(player: Value, name: impl Into<String>) -> Self {
1304 Self::PlayerVariable {
1305 player: Box::new(player),
1306 variable: name.into(),
1307 }
1308 }
1309
1310 pub fn call(name: impl Into<String>, args: impl IntoIterator<Item = Value>) -> Self {
1312 Self::Call {
1313 name: name.into(),
1314 args: args.into_iter().collect(),
1315 }
1316 }
1317}
1318
1319impl From<bool> for Value {
1320 fn from(value: bool) -> Self {
1321 Self::Bool(value)
1322 }
1323}
1324
1325impl From<f64> for Value {
1326 fn from(value: f64) -> Self {
1327 Self::Number(value)
1328 }
1329}
1330
1331impl From<f32> for Value {
1332 fn from(value: f32) -> Self {
1333 Self::Number(f64::from(value))
1334 }
1335}
1336
1337macro_rules! impl_integer_value {
1338 ($($type:ty),+ $(,)?) => {
1339 $(
1340 impl From<$type> for Value {
1341 fn from(value: $type) -> Self {
1342 Self::Number(value as f64)
1343 }
1344 }
1345 )+
1346 };
1347}
1348
1349impl_integer_value!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
1350
1351impl From<String> for Value {
1352 fn from(value: String) -> Self {
1353 Self::String(value)
1354 }
1355}
1356
1357impl From<&str> for Value {
1358 fn from(value: &str) -> Self {
1359 Self::String(value.to_string())
1360 }
1361}
1362
1363impl<T: Into<Value>> From<Vec<T>> for Value {
1364 fn from(values: Vec<T>) -> Self {
1365 Self::Array(values.into_iter().map(Into::into).collect())
1366 }
1367}
1368
1369impl<T: Into<Value>, const N: usize> From<[T; N]> for Value {
1370 fn from(values: [T; N]) -> Self {
1371 Self::Array(values.into_iter().map(Into::into).collect())
1372 }
1373}