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
120#[derive(Debug, Clone, Default)]
123struct ValueProvenance {
124 span: Option<Span>,
125 identifier: Option<Span>,
128 identity: NodeIdentity,
130 children: Vec<ValueProvenance>,
131}
132
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135#[non_exhaustive]
136pub enum SourceMappingError {
137 UnknownFile(FileId),
138 InvalidSpan(Span),
139 InvalidRule(usize),
140 InvalidCondition {
141 rule: usize,
142 condition: usize,
143 },
144 InvalidAction {
145 rule: usize,
146 action: usize,
147 },
148 InvalidActionArgument {
149 rule: usize,
150 action: usize,
151 argument: usize,
152 },
153 InvalidGlobalVariable(usize),
154 InvalidPlayerVariable(usize),
155 InvalidSubroutine(usize),
156}
157
158impl std::fmt::Display for SourceMappingError {
159 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 match self {
161 Self::UnknownFile(file) => {
162 write!(formatter, "source span references unknown file {file}")
163 }
164 Self::InvalidSpan(span) => write!(formatter, "invalid source span {span:?}"),
165 Self::InvalidRule(rule) => write!(formatter, "invalid rule index {rule}"),
166 Self::InvalidCondition { rule, condition } => {
167 write!(
168 formatter,
169 "invalid condition index {condition} in rule {rule}"
170 )
171 }
172 Self::InvalidAction { rule, action } => {
173 write!(formatter, "invalid action index {action} in rule {rule}")
174 }
175 Self::InvalidActionArgument {
176 rule,
177 action,
178 argument,
179 } => write!(
180 formatter,
181 "invalid argument index {argument} in action {action} of rule {rule}"
182 ),
183 Self::InvalidGlobalVariable(variable) => {
184 write!(formatter, "invalid global variable index {variable}")
185 }
186 Self::InvalidPlayerVariable(variable) => {
187 write!(formatter, "invalid player variable index {variable}")
188 }
189 Self::InvalidSubroutine(subroutine) => {
190 write!(formatter, "invalid subroutine index {subroutine}")
191 }
192 }
193 }
194}
195
196impl std::error::Error for SourceMappingError {}
197
198impl Program {
199 pub fn new() -> Self {
200 Self::default()
201 }
202
203 pub fn add_file(&mut self, mut file: SourceFile) -> FileId {
205 let id = FileId::from_index(self.files.len());
206 file.bind_file(id);
207 self.files.push(file);
208 id
209 }
210
211 pub fn global_variable(&mut self, variable: Variable) -> &mut Self {
212 self.global_variables.push(variable);
213 self
214 }
215
216 pub fn player_variable(&mut self, variable: Variable) -> &mut Self {
217 self.player_variables.push(variable);
218 self
219 }
220
221 pub fn subroutine(&mut self, subroutine: Subroutine) -> &mut Self {
222 self.subroutines.push(subroutine);
223 self
224 }
225
226 pub fn rule(&mut self, rule: Rule) -> &mut Self {
227 self.rules.push(rule);
228 self
229 }
230
231 pub fn source(&self, file: FileId) -> Option<&SourceDocument> {
233 self.files.get(file.index()).and_then(SourceFile::source)
234 }
235
236 pub fn set_file_source(&mut self, file: FileId, source: impl Into<String>) -> bool {
239 let Some(entry) = self.files.get_mut(file.index()) else {
240 return false;
241 };
242 entry.set_source(source);
243 true
244 }
245
246 pub fn set_rule_span(
248 &mut self,
249 rule: usize,
250 span: Option<Span>,
251 ) -> std::result::Result<(), SourceMappingError> {
252 self.validate_span(span)?;
253 self.rule_provenance_mut(rule)?.span = span;
254 Ok(())
255 }
256
257 pub fn set_condition_span(
259 &mut self,
260 rule: usize,
261 condition: usize,
262 span: Option<Span>,
263 ) -> std::result::Result<(), SourceMappingError> {
264 self.set_child_span(
265 rule,
266 condition,
267 span,
268 |rule| rule.conditions.len(),
269 |rule, index| condition_identity(&rule.conditions[index]),
270 |rule, index| SourceMappingError::InvalidCondition {
271 rule,
272 condition: index,
273 },
274 |rule_data| &mut rule_data.conditions,
275 )
276 }
277
278 pub fn set_action_span(
280 &mut self,
281 rule: usize,
282 action: usize,
283 span: Option<Span>,
284 ) -> std::result::Result<(), SourceMappingError> {
285 self.set_child_span(
286 rule,
287 action,
288 span,
289 |rule| rule.actions.len(),
290 |rule, index| action_identity(&rule.actions[index]),
291 |rule, index| SourceMappingError::InvalidAction {
292 rule,
293 action: index,
294 },
295 |rule_data| &mut rule_data.actions,
296 )
297 }
298
299 #[allow(clippy::too_many_arguments)]
305 fn set_child_span<T: SpanSlot + Default>(
306 &mut self,
307 rule: usize,
308 index: usize,
309 span: Option<Span>,
310 count: impl Fn(&crate::Rule) -> usize,
311 identity: impl Fn(&crate::Rule, usize) -> NodeIdentity,
312 invalid: impl Fn(usize, usize) -> SourceMappingError,
313 slots: impl Fn(&mut RuleProvenance) -> &mut Vec<T>,
314 ) -> std::result::Result<(), SourceMappingError> {
315 self.validate_span(span)?;
316 let public = self
317 .rules
318 .get(rule)
319 .ok_or(SourceMappingError::InvalidRule(rule))?;
320 let child_count = count(public);
321 if index >= child_count {
322 return Err(invalid(rule, index));
323 }
324 let identity = identity(public, index);
325 let rule_data = self.rule_provenance_mut(rule)?;
326 fit(slots(rule_data), child_count);
327 let record = &mut slots(rule_data)[index];
328 record.reseat(identity);
329 *record.span_slot() = span;
330 Ok(())
331 }
332
333 pub fn set_action_argument_span(
335 &mut self,
336 rule: usize,
337 action: usize,
338 argument: usize,
339 span: Option<Span>,
340 ) -> std::result::Result<(), SourceMappingError> {
341 self.validate_span(span)?;
342 let (identity, argument_count) = {
343 let action_value = self
344 .rules
345 .get(rule)
346 .ok_or(SourceMappingError::InvalidRule(rule))?
347 .actions
348 .get(action)
349 .ok_or(SourceMappingError::InvalidAction { rule, action })?;
350 let argument_values = action_argument_values(action_value);
351 let Some(&argument_value) = argument_values.get(argument) else {
352 return Err(SourceMappingError::InvalidActionArgument {
353 rule,
354 action,
355 argument,
356 });
357 };
358 (value_identity(argument_value), argument_values.len())
359 };
360 let action_data = self.action_provenance_mut(rule, action)?;
361 fit(&mut action_data.arguments, argument_count);
362 let record = &mut action_data.arguments[argument];
363 record.reseat(identity);
364 record.span = span;
365 Ok(())
366 }
367
368 pub fn set_global_variable_spans(
370 &mut self,
371 variable: usize,
372 span: Option<Span>,
373 name_span: Option<Span>,
374 ) -> std::result::Result<(), SourceMappingError> {
375 self.set_declaration_spans(DeclarationTable::GlobalVariables, variable, span, name_span)
376 }
377
378 pub fn set_player_variable_spans(
380 &mut self,
381 variable: usize,
382 span: Option<Span>,
383 name_span: Option<Span>,
384 ) -> std::result::Result<(), SourceMappingError> {
385 self.set_declaration_spans(DeclarationTable::PlayerVariables, variable, span, name_span)
386 }
387
388 pub fn set_subroutine_spans(
390 &mut self,
391 subroutine: usize,
392 span: Option<Span>,
393 name_span: Option<Span>,
394 ) -> std::result::Result<(), SourceMappingError> {
395 self.set_declaration_spans(DeclarationTable::Subroutines, subroutine, span, name_span)
396 }
397
398 fn set_declaration_spans(
399 &mut self,
400 table: DeclarationTable,
401 index: usize,
402 span: Option<Span>,
403 name_span: Option<Span>,
404 ) -> std::result::Result<(), SourceMappingError> {
405 self.validate_span(span)?;
406 self.validate_span(name_span)?;
407 let count = table.count(self);
408 if index >= count {
409 return Err(table.invalid(index));
410 }
411 let identity = table.identity(self, index);
412 let slots = table.slots(self.provenance_mut());
413 fit(slots, count);
414 slots[index] = DeclarationProvenance {
415 span,
416 name_span,
417 identity,
418 };
419 Ok(())
420 }
421
422 pub fn rule_span(&self, rule: usize) -> Option<crate::source::Span> {
430 self.rule_provenance(rule)?.span
431 }
432
433 pub fn condition_span(&self, rule: usize, condition: usize) -> Option<crate::source::Span> {
435 self.condition_provenance(rule, condition)?.span
436 }
437
438 pub fn action_span(&self, rule: usize, action: usize) -> Option<crate::source::Span> {
440 self.action_provenance(rule, action)?.span
441 }
442
443 pub fn action_argument_span(
445 &self,
446 rule: usize,
447 action: usize,
448 argument: usize,
449 ) -> Option<crate::source::Span> {
450 self.action_argument_provenance(rule, action, argument)?
451 .span
452 }
453
454 pub fn global_variable_name_span(&self, variable: usize) -> Option<Span> {
461 self.declaration_name_span(
462 |provenance| &provenance.global_variables,
463 &self.global_variables,
464 variable,
465 )
466 }
467
468 pub fn player_variable_name_span(&self, variable: usize) -> Option<Span> {
471 self.declaration_name_span(
472 |provenance| &provenance.player_variables,
473 &self.player_variables,
474 variable,
475 )
476 }
477
478 pub fn subroutine_name_span(&self, subroutine: usize) -> Option<Span> {
481 self.declaration_name_span(
482 |provenance| &provenance.subroutines,
483 &self.subroutines,
484 subroutine,
485 )
486 }
487
488 pub fn action_identifier_span(&self, rule: usize, action: usize) -> Option<Span> {
500 self.action_provenance(rule, action)?.identifier
501 }
502
503 pub fn rule_name_span(&self, rule: usize) -> Option<Span> {
506 self.rule_provenance(rule)?.name
507 }
508
509 pub fn rule_event_name_span(&self, rule: usize) -> Option<Span> {
513 self.rule_provenance(rule)?.event_name
514 }
515
516 pub fn condition_value_span(
531 &self,
532 rule: usize,
533 condition: usize,
534 path: &[usize],
535 ) -> Option<crate::source::Span> {
536 let record = self.condition_value_record(rule, condition, path)?;
537 record.identifier.or(record.span)
538 }
539
540 fn condition_value_record(
545 &self,
546 rule: usize,
547 condition: usize,
548 path: &[usize],
549 ) -> Option<&ValueProvenance> {
550 let record = self.condition_record(rule, condition)?;
551 let value = &self.rules[rule].conditions[condition].value;
552 let identity = condition_identity(&self.rules[rule].conditions[condition]);
553 value_provenance_at(record, value, path, identity)
554 }
555
556 pub(crate) fn condition_value_node_span(
561 &self,
562 rule: usize,
563 condition: usize,
564 path: &[usize],
565 ) -> Option<crate::source::Span> {
566 self.condition_value_record(rule, condition, path)?.span
567 }
568
569 pub fn action_argument_value_span(
579 &self,
580 rule: usize,
581 action: usize,
582 argument: usize,
583 path: &[usize],
584 ) -> Option<crate::source::Span> {
585 let record = self.action_argument_value_record(rule, action, argument, path)?;
586 record.identifier.or(record.span)
587 }
588
589 fn action_argument_value_record(
593 &self,
594 rule: usize,
595 action: usize,
596 argument: usize,
597 path: &[usize],
598 ) -> Option<&ValueProvenance> {
599 let record = self.argument_record(rule, action, argument)?;
600 let value = action_argument_values(&self.rules[rule].actions[action])[argument];
601 value_provenance_at(record, value, path, value_identity(value))
602 }
603
604 pub(crate) fn action_argument_value_node_span(
609 &self,
610 rule: usize,
611 action: usize,
612 argument: usize,
613 path: &[usize],
614 ) -> Option<crate::source::Span> {
615 self.action_argument_value_record(rule, action, argument, path)?
616 .span
617 }
618
619 pub fn edit_source(
622 &self,
623 span: crate::source::Span,
624 replacement: impl Into<String>,
625 ) -> std::result::Result<crate::source::SourceEdit, crate::source::SourceEditError> {
626 self.source(span.file)
627 .ok_or(crate::source::SourceEditError::InvalidRange)?
628 .edit_span(span, replacement)
629 }
630
631 pub fn validate(&self) -> std::result::Result<(), WorkshopError> {
636 let storage = self.to_wir()?;
637 storage
638 .validate()
639 .map_err(|error| WorkshopError::malformed(error.to_string(), error.span()))?;
640 if let Some(settings) = &self.settings {
641 if let Some(error) = crate::settings::check_emission(settings).into_iter().next() {
642 return Err(error);
643 }
644 }
645 Ok(())
646 }
647
648 pub fn settings_diagnostics(&self) -> Vec<crate::settings::SettingsDiagnostic> {
658 self.settings
659 .as_ref()
660 .map(crate::settings::check_emission_diagnostics)
661 .unwrap_or_default()
662 }
663
664 pub fn semantic_issues(
674 &self,
675 catalog: &crate::catalog::Catalog,
676 ) -> Vec<crate::rules::SemanticIssue> {
677 crate::analysis::semantic::inspect(self, catalog)
678 }
679
680 pub fn dump(&self) -> String {
682 self.to_wir().map_or_else(
683 |error| format!("invalid program: {error}"),
684 |program| program.dump(),
685 )
686 }
687
688 fn rule_record(&self, rule: usize) -> Option<&RuleProvenance> {
694 let recorded = &self.provenance.as_deref()?.rules;
695 if recorded.len() != self.rules.len() {
696 return None;
697 }
698 recorded.get(rule)
699 }
700
701 fn rule_provenance(&self, rule: usize) -> Option<&RuleProvenance> {
705 self.rule_record(rule)
706 .filter(|record| record.identity == rule_identity(&self.rules[rule]))
707 }
708
709 fn action_record(&self, rule: usize, action: usize) -> Option<&ActionProvenance> {
710 let recorded = self.rule_record(rule)?;
711 if recorded.actions.len() != self.rules[rule].actions.len() {
712 return None;
713 }
714 recorded.actions.get(action)
715 }
716
717 fn action_provenance(&self, rule: usize, action: usize) -> Option<&ActionProvenance> {
721 self.action_record(rule, action)
722 .filter(|record| record.identity == action_identity(&self.rules[rule].actions[action]))
723 }
724
725 fn argument_record(
726 &self,
727 rule: usize,
728 action: usize,
729 argument: usize,
730 ) -> Option<&ValueProvenance> {
731 let recorded = self.action_record(rule, action)?;
732 let values = action_argument_values(&self.rules[rule].actions[action]);
733 if recorded.arguments.len() != values.len() {
734 return None;
735 }
736 recorded.arguments.get(argument)
737 }
738
739 fn action_argument_provenance(
743 &self,
744 rule: usize,
745 action: usize,
746 argument: usize,
747 ) -> Option<&ValueProvenance> {
748 let record = self.argument_record(rule, action, argument)?;
749 let values = action_argument_values(&self.rules[rule].actions[action]);
750 (record.identity == value_identity(values[argument])).then_some(record)
751 }
752
753 fn condition_record(&self, rule: usize, condition: usize) -> Option<&ValueProvenance> {
754 let recorded = self.rule_record(rule)?;
755 if recorded.conditions.len() != self.rules[rule].conditions.len() {
756 return None;
757 }
758 recorded.conditions.get(condition)
759 }
760
761 fn condition_provenance(&self, rule: usize, condition: usize) -> Option<&ValueProvenance> {
765 self.condition_record(rule, condition).filter(|record| {
766 record.identity == condition_identity(&self.rules[rule].conditions[condition])
767 })
768 }
769
770 fn declaration_name_span<T: std::fmt::Debug>(
771 &self,
772 recorded: impl Fn(&ProgramProvenance) -> &[DeclarationProvenance],
773 nodes: &[T],
774 position: usize,
775 ) -> Option<Span> {
776 let declaration = self.declaration_provenance(recorded, nodes, position);
777 declaration.name_span.or(declaration.span)
778 }
779
780 fn declaration_provenance<T: std::fmt::Debug>(
781 &self,
782 recorded: impl Fn(&ProgramProvenance) -> &[DeclarationProvenance],
783 nodes: &[T],
784 position: usize,
785 ) -> DeclarationProvenance {
786 self.provenance
787 .as_deref()
788 .map(recorded)
789 .filter(|recorded| recorded.len() == nodes.len())
790 .and_then(|recorded| recorded.get(position).zip(nodes.get(position)))
791 .filter(|(record, node)| record.identity == declaration_identity(node))
792 .map(|(record, _)| *record)
793 .unwrap_or_default()
794 }
795
796 fn validate_span(&self, span: Option<Span>) -> std::result::Result<(), SourceMappingError> {
797 let Some(span) = span else {
798 return Ok(());
799 };
800 if !span.is_valid() {
801 return Err(SourceMappingError::InvalidSpan(span));
802 }
803 if self.files.get(span.file.index()).is_none() {
804 return Err(SourceMappingError::UnknownFile(span.file));
805 }
806 Ok(())
807 }
808
809 fn provenance_mut(&mut self) -> &mut ProgramProvenance {
810 self.provenance
811 .get_or_insert_with(|| Box::new(ProgramProvenance::default()))
812 .as_mut()
813 }
814
815 fn rule_provenance_mut(
819 &mut self,
820 rule: usize,
821 ) -> std::result::Result<&mut RuleProvenance, SourceMappingError> {
822 if rule >= self.rules.len() {
823 return Err(SourceMappingError::InvalidRule(rule));
824 }
825 let identity = rule_identity(&self.rules[rule]);
826 let rule_count = self.rules.len();
827 let provenance = self.provenance_mut();
828 fit(&mut provenance.rules, rule_count);
829 let record = &mut provenance.rules[rule];
830 record.reseat(identity);
831 Ok(record)
832 }
833
834 fn action_provenance_mut(
835 &mut self,
836 rule: usize,
837 action: usize,
838 ) -> std::result::Result<&mut ActionProvenance, SourceMappingError> {
839 let public = self
840 .rules
841 .get(rule)
842 .ok_or(SourceMappingError::InvalidRule(rule))?;
843 let action_count = public.actions.len();
844 if action >= action_count {
845 return Err(SourceMappingError::InvalidAction { rule, action });
846 }
847 let identity = action_identity(&public.actions[action]);
848 let rule_data = self.rule_provenance_mut(rule)?;
849 fit(&mut rule_data.actions, action_count);
850 let record = &mut rule_data.actions[action];
851 record.reseat(identity);
852 Ok(record)
853 }
854
855 fn record_identities(&mut self) {
859 let Some(mut provenance) = self.provenance.take() else {
860 return;
861 };
862 identity::record_identities(&mut provenance, self);
863 self.provenance = Some(provenance);
864 }
865}
866
867fn value_provenance_at<'a>(
874 record: &'a ValueProvenance,
875 value: &'a Value,
876 path: &[usize],
877 root_identity: NodeIdentity,
878) -> Option<&'a ValueProvenance> {
879 let mut record = record;
880 let mut value = value;
881 let mut identity = root_identity;
882 for &index in path {
883 let children = value_children(value);
884 if record.children.len() != children.len() {
885 return None;
886 }
887 record = record.children.get(index)?;
888 value = children[index];
889 identity = value_identity(value);
890 }
891 (record.identity == identity).then_some(record)
892}
893
894fn fit<T: Default>(items: &mut Vec<T>, len: usize) {
895 items.truncate(len);
896 items.resize_with(len, T::default);
897}
898
899#[derive(Copy, Clone)]
902enum DeclarationTable {
903 GlobalVariables,
904 PlayerVariables,
905 Subroutines,
906}
907
908impl DeclarationTable {
909 fn count(self, program: &Program) -> usize {
910 match self {
911 Self::GlobalVariables => program.global_variables.len(),
912 Self::PlayerVariables => program.player_variables.len(),
913 Self::Subroutines => program.subroutines.len(),
914 }
915 }
916
917 fn invalid(self, index: usize) -> SourceMappingError {
918 match self {
919 Self::GlobalVariables => SourceMappingError::InvalidGlobalVariable(index),
920 Self::PlayerVariables => SourceMappingError::InvalidPlayerVariable(index),
921 Self::Subroutines => SourceMappingError::InvalidSubroutine(index),
922 }
923 }
924
925 fn identity(self, program: &Program, index: usize) -> NodeIdentity {
926 match self {
927 Self::GlobalVariables => declaration_identity(&program.global_variables[index]),
928 Self::PlayerVariables => declaration_identity(&program.player_variables[index]),
929 Self::Subroutines => declaration_identity(&program.subroutines[index]),
930 }
931 }
932
933 fn slots(self, provenance: &mut ProgramProvenance) -> &mut Vec<DeclarationProvenance> {
934 match self {
935 Self::GlobalVariables => &mut provenance.global_variables,
936 Self::PlayerVariables => &mut provenance.player_variables,
937 Self::Subroutines => &mut provenance.subroutines,
938 }
939 }
940}
941
942#[derive(Debug, Clone, PartialEq, Eq)]
944pub struct Variable {
945 pub name: String,
946 pub index: Option<u32>,
948}
949
950impl Variable {
951 pub fn new(name: impl Into<String>) -> Self {
952 Self {
953 name: name.into(),
954 index: None,
955 }
956 }
957
958 pub fn with_index(name: impl Into<String>, index: u32) -> Self {
959 Self {
960 name: name.into(),
961 index: Some(index),
962 }
963 }
964}
965
966#[derive(Debug, Clone, PartialEq, Eq)]
968pub struct Subroutine {
969 pub name: String,
970 pub index: Option<u32>,
972}
973
974impl Subroutine {
975 pub fn new(name: impl Into<String>) -> Self {
976 Self {
977 name: name.into(),
978 index: None,
979 }
980 }
981
982 pub fn with_index(name: impl Into<String>, index: u32) -> Self {
983 Self {
984 name: name.into(),
985 index: Some(index),
986 }
987 }
988}
989
990#[derive(Debug, Clone)]
992#[non_exhaustive]
993pub struct Rule {
994 pub name: String,
995 pub disabled: bool,
996 pub event: Event,
997 pub conditions: Vec<Condition>,
998 pub actions: Vec<Action>,
999}
1000
1001impl Rule {
1002 pub fn new(name: impl Into<String>, event: Event) -> Self {
1003 Self {
1004 name: name.into(),
1005 disabled: false,
1006 event,
1007 conditions: Vec::new(),
1008 actions: Vec::new(),
1009 }
1010 }
1011
1012 pub fn condition(mut self, condition: impl Into<Condition>) -> Self {
1013 self.conditions.push(condition.into());
1014 self
1015 }
1016
1017 pub fn action(mut self, action: Action) -> Self {
1018 self.actions.push(action);
1019 self
1020 }
1021}
1022
1023#[derive(Debug, Clone)]
1025#[non_exhaustive]
1026pub struct Condition {
1027 pub value: Value,
1028 pub disabled: bool,
1029}
1030
1031impl Condition {
1032 pub fn new(value: Value) -> Self {
1033 Self {
1034 value,
1035 disabled: false,
1036 }
1037 }
1038
1039 pub fn disabled(value: Value) -> Self {
1040 Self {
1041 value,
1042 disabled: true,
1043 }
1044 }
1045}
1046
1047impl From<Value> for Condition {
1048 fn from(value: Value) -> Self {
1049 Self::new(value)
1050 }
1051}
1052
1053pub(crate) fn action_argument_values(action: &Action) -> Vec<&Value> {
1056 match action {
1057 Action::SetGlobalVariable { value, .. } | Action::ModifyGlobalVariable { value, .. } => {
1058 vec![value]
1059 }
1060 Action::SetPlayerVariable { player, value, .. }
1061 | Action::ModifyPlayerVariable { player, value, .. } => vec![player, value],
1062 Action::AssignMember { target, value, .. } => vec![target, value],
1063 Action::If { condition } | Action::ElseIf { condition } | Action::While { condition } => {
1064 vec![condition]
1065 }
1066 Action::ForGlobalVariable {
1067 start, stop, step, ..
1068 } => vec![start, stop, step],
1069 Action::ForPlayerVariable {
1070 player,
1071 start,
1072 stop,
1073 step,
1074 ..
1075 } => vec![player, start, stop, step],
1076 Action::Call { args, .. } => args.iter().collect(),
1077 Action::CallSubroutine { .. } | Action::Else | Action::End => Vec::new(),
1078 Action::Disabled { action } => action_argument_values(action),
1079 }
1080}
1081
1082pub(crate) fn value_children(value: &Value) -> Vec<&Value> {
1085 match value {
1086 Value::Array(values) => values.iter().collect(),
1087 Value::Vector { x, y, z } => vec![x.as_ref(), y.as_ref(), z.as_ref()],
1088 Value::PlayerVariable { player, .. } => vec![player.as_ref()],
1089 Value::Call { args, .. } => args.iter().collect(),
1090 _ => Vec::new(),
1091 }
1092}
1093
1094#[derive(Debug, Clone, PartialEq, Eq)]
1096pub enum Event {
1097 Global,
1098 EachPlayer,
1099 EachPlayerWithFilters {
1100 team: EventTeam,
1101 target: EventTarget,
1102 },
1103 Player {
1104 kind: PlayerEventKind,
1105 team: EventTeam,
1106 target: EventTarget,
1107 },
1108 Subroutine(String),
1109}
1110
1111#[derive(Debug, Clone)]
1114pub enum Action {
1115 SetGlobalVariable {
1116 variable: String,
1117 value: Value,
1118 },
1119 ModifyGlobalVariable {
1120 variable: String,
1121 op: ModifyOp,
1122 value: Value,
1123 },
1124 SetPlayerVariable {
1125 player: Value,
1126 variable: String,
1127 value: Value,
1128 },
1129 ModifyPlayerVariable {
1130 player: Value,
1131 variable: String,
1132 op: ModifyOp,
1133 value: Value,
1134 },
1135 AssignMember {
1136 target: Value,
1137 op: Option<ModifyOp>,
1138 value: Value,
1139 },
1140 CallSubroutine {
1141 subroutine: String,
1142 },
1143 If {
1144 condition: Value,
1145 },
1146 ElseIf {
1147 condition: Value,
1148 },
1149 Else,
1150 While {
1151 condition: Value,
1152 },
1153 ForGlobalVariable {
1154 variable: String,
1155 start: Value,
1156 stop: Value,
1157 step: Value,
1158 },
1159 ForPlayerVariable {
1160 player: Value,
1161 variable: String,
1162 start: Value,
1163 stop: Value,
1164 step: Value,
1165 },
1166 End,
1167 Disabled {
1168 action: Box<Action>,
1169 },
1170 Call {
1171 name: String,
1172 args: Vec<Value>,
1173 },
1174}
1175
1176impl Action {
1177 pub fn disabled(action: Action) -> Self {
1179 Self::Disabled {
1180 action: Box::new(action),
1181 }
1182 }
1183
1184 pub fn call(name: impl Into<String>, args: impl IntoIterator<Item = Value>) -> Self {
1186 Self::Call {
1187 name: name.into(),
1188 args: args.into_iter().collect(),
1189 }
1190 }
1191}
1192
1193#[derive(Debug, Clone)]
1195pub enum Value {
1196 Number(f64),
1197 String(String),
1198 LocalizedString(String),
1199 Bool(bool),
1200 Null,
1201 Array(Vec<Value>),
1202 Vector {
1203 x: Box<Value>,
1204 y: Box<Value>,
1205 z: Box<Value>,
1206 },
1207 Enum {
1208 value_type: String,
1209 value: String,
1210 },
1211 GlobalVariable(String),
1212 PlayerVariable {
1213 player: Box<Value>,
1214 variable: String,
1215 },
1216 Subroutine(String),
1217 EventPlayer,
1218 Call {
1219 name: String,
1220 args: Vec<Value>,
1221 },
1222}
1223
1224impl Value {
1225 pub fn number(value: f64) -> Self {
1227 Self::Number(value)
1228 }
1229
1230 pub fn string(value: impl Into<String>) -> Self {
1232 Self::String(value.into())
1233 }
1234
1235 pub fn global_variable(name: impl Into<String>) -> Self {
1236 Self::GlobalVariable(name.into())
1237 }
1238
1239 pub fn player_variable(player: Value, name: impl Into<String>) -> Self {
1240 Self::PlayerVariable {
1241 player: Box::new(player),
1242 variable: name.into(),
1243 }
1244 }
1245
1246 pub fn call(name: impl Into<String>, args: impl IntoIterator<Item = Value>) -> Self {
1248 Self::Call {
1249 name: name.into(),
1250 args: args.into_iter().collect(),
1251 }
1252 }
1253}
1254
1255impl From<bool> for Value {
1256 fn from(value: bool) -> Self {
1257 Self::Bool(value)
1258 }
1259}
1260
1261impl From<f64> for Value {
1262 fn from(value: f64) -> Self {
1263 Self::Number(value)
1264 }
1265}
1266
1267impl From<f32> for Value {
1268 fn from(value: f32) -> Self {
1269 Self::Number(f64::from(value))
1270 }
1271}
1272
1273macro_rules! impl_integer_value {
1274 ($($type:ty),+ $(,)?) => {
1275 $(
1276 impl From<$type> for Value {
1277 fn from(value: $type) -> Self {
1278 Self::Number(value as f64)
1279 }
1280 }
1281 )+
1282 };
1283}
1284
1285impl_integer_value!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
1286
1287impl From<String> for Value {
1288 fn from(value: String) -> Self {
1289 Self::String(value)
1290 }
1291}
1292
1293impl From<&str> for Value {
1294 fn from(value: &str) -> Self {
1295 Self::String(value.to_string())
1296 }
1297}
1298
1299impl<T: Into<Value>> From<Vec<T>> for Value {
1300 fn from(values: Vec<T>) -> Self {
1301 Self::Array(values.into_iter().map(Into::into).collect())
1302 }
1303}
1304
1305impl<T: Into<Value>, const N: usize> From<[T; N]> for Value {
1306 fn from(values: [T; N]) -> Self {
1307 Self::Array(values.into_iter().map(Into::into).collect())
1308 }
1309}