1use std::borrow::Borrow;
2use std::fmt::{Debug, Display, Formatter};
3use std::ops::{Bound, RangeBounds};
4use std::str::FromStr;
5
6use crate::block::{BV, Block, BlockItem, Comparator, Eq::*, Field};
7use crate::context::ScopeContext;
8use crate::date::Date;
9use crate::effect::validate_effect_internal;
10use crate::everything::Everything;
11use crate::helpers::{AllowInject, TigerHashSet, dup_assign_error};
12#[cfg(feature = "hoi4")]
13use crate::hoi4::variables::validate_variable;
14use crate::item::Item;
15use crate::lowercase::Lowercase;
16#[cfg(feature = "ck3")]
17use crate::report::fatal;
18use crate::report::{ErrorKey, Severity, report};
19use crate::scopes::Scopes;
20#[cfg(feature = "jomini")]
21use crate::script_value::{validate_script_value, validate_script_value_no_breakdown};
22use crate::special_tokens::SpecialTokens;
23use crate::token::Token;
24use crate::tooltipped::Tooltipped;
25use crate::trigger::{validate_target, validate_target_ok_this, validate_trigger_internal};
26use crate::validate::{ListType, validate_identifier};
27
28pub use self::value_validator::ValueValidator;
29
30mod value_validator;
31
32pub struct Validator<'a> {
41 block: &'a Block,
43 data: &'a Everything,
45 known_fields: Vec<&'a str>,
47 accepted_tokens: bool,
49 accepted_blocks: bool,
51 accepted_block_fields: bool,
53 accepted_value_fields: bool,
55 case_sensitive: bool,
57 allow_questionmark_equals: bool,
59 max_severity: Severity,
64}
65
66impl Debug for Validator<'_> {
67 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
69 f.debug_struct("Validator")
70 .field("block", &self.block)
71 .field("known_fields", &self.known_fields)
72 .field("accepted_tokens", &self.accepted_tokens)
73 .field("accepted_blocks", &self.accepted_blocks)
74 .field("accepted_block_fields", &self.accepted_block_fields)
75 .field("accepted_value_fields", &self.accepted_value_fields)
76 .field("case_sensitive", &self.case_sensitive)
77 .field("allow_questionmark_equals", &self.allow_questionmark_equals)
78 .field("max_severity", &self.max_severity)
79 .finish()
80 }
81}
82
83impl<'a> Validator<'a> {
84 pub fn new(block: &'a Block, data: &'a Everything) -> Self {
87 Validator {
88 block,
89 data,
90 known_fields: Vec::new(),
91 accepted_tokens: false,
92 accepted_blocks: false,
93 accepted_block_fields: false,
94 accepted_value_fields: false,
95 case_sensitive: true,
96 allow_questionmark_equals: false,
97 max_severity: Severity::Fatal,
98 }
99 }
100
101 pub fn set_case_sensitive(&mut self, cs: bool) {
104 self.case_sensitive = cs;
105 }
106
107 pub fn set_allow_questionmark_equals(&mut self, allow_questionmark_equals: bool) {
110 self.allow_questionmark_equals = allow_questionmark_equals;
111 }
112
113 pub fn set_max_severity(&mut self, max_severity: Severity) {
114 self.max_severity = max_severity;
115 }
116 pub fn max_severity(&self) -> Severity {
117 self.max_severity
118 }
119
120 pub fn req_field(&mut self, name: &str) -> bool {
123 let found = self.check_key(name);
124 if !found {
125 let msg = format!("required field `{name}` missing");
126 let sev = Severity::Error.at_most(self.max_severity);
127 report(ErrorKey::FieldMissing, sev).msg(msg).loc(self.block).push();
128 }
129 found
130 }
131
132 pub fn req_field_one_of(&mut self, names: &[&str]) -> bool {
136 let mut count = 0;
137 for name in names {
138 if self.check_key(name) {
139 count += 1;
140 }
141 }
142 if count != 1 {
143 let msg = format!("expected exactly 1 of {}", names.join(", "));
144 let key = if count == 0 { ErrorKey::FieldMissing } else { ErrorKey::Validation };
145 let sev = Severity::Error.at_most(self.max_severity);
146 report(key, sev).msg(msg).loc(self.block).push();
147 }
148 count == 1
149 }
150
151 #[allow(dead_code)]
154 pub fn exclusive_fields(&mut self, names: &[&str]) -> bool {
155 let mut count = 0;
156 for name in names {
157 if self.check_key(name) {
158 count += 1;
159 }
160 }
161 if count > 1 {
162 let msg = format!("cannot combine fields {}", names.join(", "));
163 let sev = Severity::Error.at_most(self.max_severity);
164 report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
165 }
166 count == 1
167 }
168
169 pub fn req_field_warn(&mut self, name: &str) -> bool {
172 let found = self.check_key(name);
173 if !found {
174 let msg = format!("required field `{name}` missing");
175 let sev = Severity::Warning.at_most(self.max_severity);
176 report(ErrorKey::FieldMissing, sev).msg(msg).loc(self.block).push();
177 }
178 found
179 }
180
181 #[cfg(feature = "ck3")] pub fn req_field_fatal(&mut self, name: &str) -> bool {
185 let found = self.check_key(name);
186 if !found {
187 let msg = format!("required field `{name}` missing");
188 fatal(ErrorKey::FieldMissing).msg(msg).loc(self.block).push();
189 }
190 found
191 }
192
193 pub fn ban_field<F, S>(&mut self, name: &str, only_for: F)
198 where
199 F: Fn() -> S,
200 S: Borrow<str> + Display,
201 {
202 let sev = Severity::Error.at_most(self.max_severity);
203 self.multi_field_check(name, |key, _| {
204 let msg = format!("`{name} = ` is only for {}", only_for());
205 report(ErrorKey::Validation, sev).msg(msg).loc(key).push();
206 });
207 }
208
209 #[cfg(any(feature = "ck3", feature = "vic3"))]
212 pub fn replaced_field(&mut self, name: &str, replaced_by: &str) {
213 let sev = Severity::Error.at_most(self.max_severity);
214 self.multi_field_check(name, |key, _| {
215 let msg = format!("`{name}` has been replaced by {replaced_by}");
216 report(ErrorKey::Validation, sev).msg(msg).loc(key).push();
217 });
218 }
219
220 fn check_key(&mut self, name: &str) -> bool {
221 for Field(key, _, _) in self.block.iter_fields() {
222 if (self.case_sensitive && key.is(name))
223 || (!self.case_sensitive && key.lowercase_is(name))
224 {
225 self.known_fields.push(key.as_str());
226 return true;
227 }
228 }
229 false
230 }
231
232 fn field_check<F>(&mut self, name: &str, allow_inject: AllowInject, mut f: F) -> bool
233 where
234 F: FnMut(&Token, &BV),
235 {
236 let mut found = None;
237 for Field(key, cmp, bv) in self.block.iter_fields() {
238 if (self.case_sensitive && key.is(name))
239 || (!self.case_sensitive && key.lowercase_is(name))
240 {
241 self.known_fields.push(key.as_str());
242 if let Some(other) = found {
243 dup_assign_error(key, other, allow_inject);
244 }
245 self.expect_eq_qeq(key, *cmp);
246 f(key, bv);
247 found = Some(key);
248 }
249 }
250 found.is_some()
251 }
252
253 fn multi_field_check<F>(&mut self, name: &str, mut f: F) -> bool
254 where
255 F: FnMut(&Token, &BV),
256 {
257 let mut found = false;
258 for Field(key, cmp, bv) in self.block.iter_fields() {
259 if (self.case_sensitive && key.is(name))
260 || (!self.case_sensitive && key.lowercase_is(name))
261 {
262 self.known_fields.push(key.as_str());
263 self.expect_eq_qeq(key, *cmp);
264 f(key, bv);
265 found = true;
266 }
267 }
268 found
269 }
270
271 pub fn field(&mut self, name: &str) -> bool {
275 self.field_check(name, AllowInject::No, |_, _| ())
276 }
277
278 pub fn multi_field(&mut self, name: &str) -> bool {
280 self.multi_field_check(name, |_, _| ())
281 }
282
283 pub fn field_any_cmp(&mut self, name: &str) -> Option<&BV> {
288 let mut found = None;
289 for Field(key, _, bv) in self.block.iter_fields() {
290 if (self.case_sensitive && key.is(name))
291 || (!self.case_sensitive && key.lowercase_is(name))
292 {
293 self.known_fields.push(key.as_str());
294 if let Some((other, _)) = found {
295 dup_assign_error(key, other, AllowInject::Yes);
296 }
297 found = Some((key, bv));
298 }
299 }
300 if let Some((_, bv)) = found { Some(bv) } else { None }
301 }
302
303 pub fn field_value(&mut self, name: &str) -> Option<&Token> {
307 let mut found = None;
308 let mut result = None;
309 for Field(key, cmp, bv) in self.block.iter_fields() {
310 if (self.case_sensitive && key.is(name))
311 || (!self.case_sensitive && key.lowercase_is(name))
312 {
313 self.known_fields.push(key.as_str());
314 if let Some(other) = found {
315 dup_assign_error(key, other, AllowInject::Yes);
316 }
317 self.expect_eq_qeq(key, *cmp);
318 if let Some(token) = bv.expect_value() {
319 result = Some(token);
320 }
321 found = Some(key);
322 }
323 }
324 result
325 }
326
327 pub fn field_identifier(&mut self, name: &str, kind: &str) -> Option<&Token> {
332 let mut found = None;
333 let mut result = None;
334 for Field(key, cmp, bv) in self.block.iter_fields() {
335 if (self.case_sensitive && key.is(name))
336 || (!self.case_sensitive && key.lowercase_is(name))
337 {
338 self.known_fields.push(key.as_str());
339 if let Some(other) = found {
340 dup_assign_error(key, other, AllowInject::Yes);
341 }
342 self.expect_eq_qeq(key, *cmp);
343 if let Some(token) = bv.expect_value() {
344 validate_identifier(token, kind, Severity::Error.at_most(self.max_severity));
345 result = Some(token);
346 }
347 found = Some(key);
348 }
349 }
350 result
351 }
352
353 #[cfg(feature = "jomini")]
358 pub fn field_identifier_or_flag(
359 &mut self,
360 name: &str,
361 sc: &mut ScopeContext,
362 ) -> Option<&Token> {
363 let mut found = None;
364 let mut result = None;
365 for Field(key, cmp, bv) in self.block.iter_fields() {
366 if (self.case_sensitive && key.is(name))
367 || (!self.case_sensitive && key.lowercase_is(name))
368 {
369 self.known_fields.push(key.as_str());
370 if let Some(other) = found {
371 dup_assign_error(key, other, AllowInject::Yes);
372 }
373 self.expect_eq_qeq(key, *cmp);
374 if let Some(token) = bv.expect_value() {
375 if token.as_str().contains('.') || token.as_str().contains(':') {
377 validate_target(token, self.data, sc, Scopes::Flag);
378 }
379 result = Some(token);
380 }
381 found = Some(key);
382 }
383 }
384 result
385 }
386
387 pub fn field_validated_value<F>(&mut self, name: &str, mut f: F) -> bool
392 where
393 F: FnMut(&Token, ValueValidator),
394 {
395 let max_sev = self.max_severity;
396 self.field_check(name, AllowInject::Yes, |k, bv| {
397 if let Some(value) = bv.expect_value() {
398 let mut vd = ValueValidator::new(value, self.data);
399 vd.set_max_severity(max_sev);
400 f(k, vd);
401 }
402 })
403 }
404
405 #[allow(dead_code)]
407 pub fn multi_field_validated_value<F>(&mut self, name: &str, mut f: F) -> bool
408 where
409 F: FnMut(&Token, ValueValidator),
410 {
411 let max_sev = self.max_severity;
412 self.multi_field_check(name, |k, bv| {
413 if let Some(value) = bv.expect_value() {
414 let mut vd = ValueValidator::new(value, self.data);
415 vd.set_max_severity(max_sev);
416 f(k, vd);
417 }
418 })
419 }
420
421 pub fn field_item(&mut self, name: &str, itype: Item) -> bool {
426 let sev = self.max_severity;
427 self.field_check(name, AllowInject::Yes, |_, bv| {
428 if let Some(token) = bv.expect_value() {
429 self.data.verify_exists_max_sev(itype, token, sev);
430 }
431 })
432 }
433
434 #[cfg(feature = "hoi4")]
438 pub fn field_variable(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
439 let sev = Severity::Error.at_most(self.max_severity);
440 self.field_check(name, AllowInject::Yes, |_, bv| {
441 if let Some(token) = bv.expect_value() {
442 validate_variable(token, self.data, sc, sev);
443 }
444 })
445 }
446
447 #[cfg(feature = "hoi4")]
451 pub fn field_variable_or_integer(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
452 let sev = Severity::Error.at_most(self.max_severity);
453 self.field_check(name, AllowInject::Yes, |_, bv| {
454 if let Some(token) = bv.expect_value() {
455 if token.is_number() {
456 token.expect_integer();
457 } else {
458 validate_variable(token, self.data, sc, sev);
459 }
460 }
461 })
462 }
463 pub fn field_action(&mut self, name: &str, sc: &ScopeContext) -> bool {
469 let sev = self.max_severity;
470 let data = &self.data;
471 self.field_check(name, AllowInject::Yes, |_, bv| {
472 if let Some(token) = bv.expect_value() {
473 self.data.verify_exists_max_sev(Item::OnAction, token, sev);
474 if let Some(mut action_sc) = sc.root_for_action(token, self.data) {
475 self.data.on_actions.validate_call(token, data, &mut action_sc);
476 }
477 }
478 })
479 }
480
481 #[allow(dead_code)]
487 pub fn field_event(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
488 let sev = self.max_severity;
489 self.field_check(name, AllowInject::Yes, |_, bv| {
490 if let Some(token) = bv.expect_value() {
491 self.data.verify_exists_max_sev(Item::Event, token, sev);
492 self.data.event_check_scope(token, sc);
493 if let Some(mut event_sc) = sc.root_for_event(token, self.data) {
494 self.data.event_validate_call(token, &mut event_sc);
495 }
496 }
497 })
498 }
499
500 pub fn field_item_or_empty(&mut self, name: &str, itype: Item) -> bool {
506 let sev = self.max_severity;
507 self.field_check(name, AllowInject::Yes, |_, bv| {
508 if let Some(token) = bv.expect_value()
509 && !token.is("")
510 {
511 self.data.verify_exists_max_sev(itype, token, sev);
512 }
513 })
514 }
515
516 #[allow(dead_code)]
523 pub fn field_localization(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
524 let sev = self.max_severity;
525 self.field_check(name, AllowInject::Yes, |_, bv| {
526 if let Some(token) = bv.expect_value() {
527 self.data.verify_exists_max_sev(Item::Localization, token, sev);
528 self.data.localization.validate_use(token.as_str(), self.data, sc);
529 }
530 })
531 }
532
533 pub fn field_target(&mut self, name: &str, sc: &mut ScopeContext, outscopes: Scopes) -> bool {
542 self.field_check(name, AllowInject::Yes, |_, bv| {
543 if let Some(token) = bv.expect_value() {
544 validate_target(token, self.data, sc, outscopes);
546 }
547 })
548 }
549
550 #[allow(dead_code)]
553 pub fn multi_field_target(
554 &mut self,
555 name: &str,
556 sc: &mut ScopeContext,
557 outscopes: Scopes,
558 ) -> bool {
559 self.multi_field_check(name, |_, bv| {
560 if let Some(token) = bv.expect_value() {
561 validate_target(token, self.data, sc, outscopes);
563 }
564 })
565 }
566
567 #[allow(dead_code)]
570 pub fn field_target_ok_this(
571 &mut self,
572 name: &str,
573 sc: &mut ScopeContext,
574 outscopes: Scopes,
575 ) -> bool {
576 self.field_check(name, AllowInject::Yes, |_, bv| {
577 if let Some(token) = bv.expect_value() {
578 validate_target_ok_this(token, self.data, sc, outscopes);
580 }
581 })
582 }
583
584 #[allow(dead_code)]
588 pub fn field_item_or_target(
589 &mut self,
590 name: &str,
591 sc: &mut ScopeContext,
592 itype: Item,
593 outscopes: Scopes,
594 ) -> bool {
595 self.field_check(name, AllowInject::Yes, |_, bv| {
596 if let Some(token) = bv.expect_value()
597 && !self.data.item_exists(itype, token.as_str())
598 {
599 validate_target(token, self.data, sc, outscopes);
601 }
602 })
603 }
604
605 #[allow(dead_code)]
609 pub fn field_item_or_target_ok_this(
610 &mut self,
611 name: &str,
612 sc: &mut ScopeContext,
613 itype: Item,
614 outscopes: Scopes,
615 ) -> bool {
616 self.field_check(name, AllowInject::Yes, |_, bv| {
617 if let Some(token) = bv.expect_value()
618 && !self.data.item_exists(itype, token.as_str())
619 {
620 validate_target_ok_this(token, self.data, sc, outscopes);
622 }
623 })
624 }
625
626 pub fn field_block(&mut self, name: &str) -> bool {
631 self.field_check(name, AllowInject::No, |_, bv| _ = bv.expect_block())
632 }
633
634 pub fn field_bool(&mut self, name: &str) -> bool {
638 let sev = Severity::Error.at_most(self.max_severity);
639 self.field_check(name, AllowInject::Yes, |_, bv| {
640 if let Some(token) = bv.expect_value()
641 && !token.is("yes")
642 && !token.is("no")
643 && !token.is("YES")
644 && !token.is("NO")
645 {
646 report(ErrorKey::Validation, sev).msg("expected yes or no").loc(token).push();
647 }
648 })
649 }
650
651 pub fn field_integer(&mut self, name: &str) -> bool {
655 self.field_check(name, AllowInject::Yes, |_, bv| {
656 if let Some(token) = bv.expect_value() {
657 token.expect_integer();
659 }
660 })
661 }
662
663 pub fn field_integer_range<R: RangeBounds<i64>>(&mut self, name: &str, range: R) {
667 let sev = Severity::Error.at_most(self.max_severity);
668 self.field_check(name, AllowInject::Yes, |_, bv| {
669 if let Some(token) = bv.expect_value() {
670 if let Some(i) = token.expect_integer()
672 && !range.contains(&i)
673 {
674 let low = match range.start_bound() {
675 Bound::Unbounded => None,
676 Bound::Included(&n) => Some(n),
677 Bound::Excluded(&n) => Some(n + 1),
678 };
679 let high = match range.end_bound() {
680 Bound::Unbounded => None,
681 Bound::Included(&n) => Some(n),
682 Bound::Excluded(&n) => Some(n - 1),
683 };
684 let msg;
685 if let (Some(low), Some(high)) = (low, high) {
686 msg = format!("should be between {low} and {high} (inclusive)");
687 } else if let Some(low) = low {
688 msg = format!("should be at least {low}");
689 } else if let Some(high) = high {
690 msg = format!("should be at most {high}");
691 } else {
692 unreachable!(); }
694 report(ErrorKey::Range, sev).msg(msg).loc(token).push();
695 }
696 }
697 });
698 }
699
700 pub fn field_numeric(&mut self, name: &str) -> bool {
705 self.field_check(name, AllowInject::Yes, |_, bv| {
706 if let Some(token) = bv.expect_value() {
707 token.expect_number();
708 }
709 })
710 }
711
712 #[cfg(feature = "hoi4")]
717 pub fn multi_field_numeric(&mut self, name: &str) -> bool {
718 self.multi_field_check(name, |_, bv| {
719 if let Some(token) = bv.expect_value() {
720 token.expect_number();
721 }
722 })
723 }
724
725 pub fn field_precise_numeric(&mut self, name: &str) -> bool {
729 self.field_check(name, AllowInject::Yes, |_, bv| {
730 if let Some(token) = bv.expect_value() {
731 token.expect_precise_number();
732 }
733 })
734 }
735
736 #[cfg(any(feature = "ck3", feature = "vic3"))]
737 pub fn field_numeric_range_internal<R: RangeBounds<f64>>(
738 &mut self,
739 name: &str,
740 range: R,
741 precise: bool,
742 ) {
743 let sev = Severity::Error.at_most(self.max_severity);
744 self.field_check(name, AllowInject::Yes, |_, bv| {
745 if let Some(token) = bv.expect_value() {
746 let numeric =
747 if precise { token.expect_precise_number() } else { token.expect_number() };
748 if let Some(f) = numeric
749 && !range.contains(&f)
750 {
751 let low = match range.start_bound() {
752 Bound::Unbounded => None,
753 Bound::Included(f) => Some(format!("{f} (inclusive)")),
754 Bound::Excluded(f) => Some(format!("{f}")),
755 };
756 let high = match range.end_bound() {
757 Bound::Unbounded => None,
758 Bound::Included(f) => Some(format!("{f} (inclusive)")),
759 Bound::Excluded(f) => Some(format!("{f}")),
760 };
761 let msg;
762 if let (Some(low), Some(high)) = (low.as_ref(), high.as_ref()) {
763 msg = format!("should be between {low} and {high}");
764 } else if let Some(low) = low {
765 msg = format!("should be at least {low}");
766 } else if let Some(high) = high {
767 msg = format!("should be at most {high}");
768 } else {
769 unreachable!(); }
771 report(ErrorKey::Range, sev).msg(msg).loc(token).push();
772 }
773 }
774 });
775 }
776
777 #[cfg(any(feature = "ck3", feature = "vic3"))]
781 pub fn field_numeric_range<R: RangeBounds<f64>>(&mut self, name: &str, range: R) {
782 self.field_numeric_range_internal(name, range, false);
783 }
784
785 #[cfg(feature = "ck3")]
788 pub fn field_precise_numeric_range<R: RangeBounds<f64>>(&mut self, name: &str, range: R) {
789 self.field_numeric_range_internal(name, range, true);
790 }
791
792 pub fn field_date(&mut self, name: &str) -> bool {
798 let sev = Severity::Error.at_most(self.max_severity);
799 self.field_check(name, AllowInject::Yes, |_, bv| {
800 if let Some(token) = bv.expect_value()
801 && Date::from_str(token.as_str()).is_err()
802 {
803 let msg = "expected date value";
804 report(ErrorKey::Validation, sev).msg(msg).loc(token).push();
805 }
806 })
807 }
808
809 pub fn field_trigger(
814 &mut self,
815 name: &str,
816 tooltipped: Tooltipped,
817 sc: &mut ScopeContext,
818 ) -> bool {
819 let max_sev = self.max_severity;
820 self.field_validated_block(name, |block, data| {
821 let mut vd = Validator::new(block, data);
822 vd.set_max_severity(max_sev);
823 validate_trigger_internal(
824 Lowercase::empty(),
825 ListType::None,
826 block,
827 data,
828 sc,
829 vd,
830 tooltipped,
831 false,
832 );
833 })
834 }
835
836 #[allow(dead_code)]
842 pub fn field_trigger_rooted(
843 &mut self,
844 name: &str,
845 tooltipped: Tooltipped,
846 scope: Scopes,
847 ) -> bool {
848 let max_sev = self.max_severity;
849 self.field_validated_key_block(name, |key, block, data| {
850 let mut vd = Validator::new(block, data);
851 let mut sc = ScopeContext::new(scope, key);
852 vd.set_max_severity(max_sev);
853 validate_trigger_internal(
854 Lowercase::empty(),
855 ListType::None,
856 block,
857 data,
858 &mut sc,
859 vd,
860 tooltipped,
861 false,
862 );
863 })
864 }
865
866 #[allow(dead_code)]
872 pub fn field_trigger_builder<F>(
873 &mut self,
874 name: &str,
875 tooltipped: Tooltipped,
876 mut sc_builder: F,
877 ) -> bool
878 where
879 F: FnMut(&Token) -> ScopeContext,
880 {
881 let max_sev = self.max_severity;
882 self.field_validated_key_block(name, |key, block, data| {
883 let mut vd = Validator::new(block, data);
884 vd.set_max_severity(max_sev);
885 let mut sc = sc_builder(key);
886 validate_trigger_internal(
887 Lowercase::empty(),
888 ListType::None,
889 block,
890 data,
891 &mut sc,
892 vd,
893 tooltipped,
894 false,
895 );
896 })
897 }
898
899 #[allow(dead_code)]
904 pub fn field_effect(
905 &mut self,
906 name: &str,
907 tooltipped: Tooltipped,
908 sc: &mut ScopeContext,
909 ) -> bool {
910 let max_sev = self.max_severity;
911 self.field_validated_block(name, |block, data| {
912 let mut vd = Validator::new(block, data);
913 vd.set_max_severity(max_sev);
914 validate_effect_internal(
915 Lowercase::empty(),
916 ListType::None,
917 block,
918 data,
919 sc,
920 &mut vd,
921 tooltipped,
922 &mut SpecialTokens::none(),
923 );
924 })
925 }
926
927 #[allow(dead_code)]
933 pub fn field_effect_rooted(
934 &mut self,
935 name: &str,
936 tooltipped: Tooltipped,
937 scope: Scopes,
938 ) -> bool {
939 let max_sev = self.max_severity;
940 self.field_validated_key_block(name, |key, block, data| {
941 let mut vd = Validator::new(block, data);
942 vd.set_max_severity(max_sev);
943 let mut sc = ScopeContext::new(scope, key);
944 validate_effect_internal(
945 Lowercase::empty(),
946 ListType::None,
947 block,
948 data,
949 &mut sc,
950 &mut vd,
951 tooltipped,
952 &mut SpecialTokens::none(),
953 );
954 })
955 }
956
957 #[allow(dead_code)]
963 pub fn field_effect_builder<F>(
964 &mut self,
965 name: &str,
966 tooltipped: Tooltipped,
967 mut sc_builder: F,
968 ) -> bool
969 where
970 F: FnMut(&Token) -> ScopeContext,
971 {
972 let max_sev = self.max_severity;
973 self.field_validated_key_block(name, |key, block, data| {
974 let mut vd = Validator::new(block, data);
975 vd.set_max_severity(max_sev);
976 let mut sc = sc_builder(key);
977 validate_effect_internal(
978 Lowercase::empty(),
979 ListType::None,
980 block,
981 data,
982 &mut sc,
983 &mut vd,
984 tooltipped,
985 &mut SpecialTokens::none(),
986 );
987 })
988 }
989
990 #[cfg(feature = "jomini")]
1000 pub fn field_script_value(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1001 self.field_check(name, AllowInject::Yes, |_, bv| {
1002 validate_script_value(bv, self.data, sc);
1004 })
1005 }
1006
1007 #[cfg(any(feature = "ck3", feature = "vic3", feature = "eu5"))]
1011 pub fn field_script_value_no_breakdown(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1012 self.field_check(name, AllowInject::Yes, |_, bv| {
1013 validate_script_value_no_breakdown(bv, self.data, sc);
1015 })
1016 }
1017
1018 #[cfg(feature = "jomini")]
1025 pub fn field_script_value_rooted(&mut self, name: &str, scopes: Scopes) -> bool {
1026 self.field_check(name, AllowInject::Yes, |key, bv| {
1027 let mut sc = ScopeContext::new(scopes, key);
1028 validate_script_value(bv, self.data, &mut sc);
1030 })
1031 }
1032
1033 #[cfg(feature = "jomini")]
1038 #[allow(dead_code)]
1039 pub fn field_script_value_no_breakdown_rooted(&mut self, name: &str, scopes: Scopes) -> bool {
1040 self.field_check(name, AllowInject::Yes, |key, bv| {
1041 let mut sc = ScopeContext::new(scopes, key);
1042 validate_script_value(bv, self.data, &mut sc);
1044 })
1045 }
1046
1047 #[cfg(feature = "jomini")]
1051 #[allow(dead_code)]
1052 pub fn field_script_value_builder<F>(&mut self, name: &str, mut f: F) -> bool
1053 where
1054 F: FnMut(&Token) -> ScopeContext,
1055 {
1056 self.field_check(name, AllowInject::Yes, |key, bv| {
1057 let mut sc = f(key);
1058 validate_script_value(bv, self.data, &mut sc);
1060 })
1061 }
1062
1063 #[cfg(feature = "jomini")]
1069 #[allow(dead_code)]
1070 pub fn field_script_value_no_breakdown_builder<F>(&mut self, name: &str, mut f: F) -> bool
1071 where
1072 F: FnMut(&Token) -> ScopeContext,
1073 {
1074 self.field_check(name, AllowInject::Yes, |key, bv| {
1075 let mut sc = f(key);
1076 validate_script_value_no_breakdown(bv, self.data, &mut sc);
1078 })
1079 }
1080
1081 #[cfg(feature = "jomini")]
1083 pub fn field_script_value_or_flag(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1084 self.field_check(name, AllowInject::Yes, |_, bv| {
1085 if let Some(token) = bv.get_value() {
1087 validate_target(token, self.data, sc, Scopes::Value | Scopes::Bool | Scopes::Flag);
1088 } else {
1089 validate_script_value(bv, self.data, sc);
1090 }
1091 })
1092 }
1093
1094 #[cfg(feature = "jomini")]
1096 pub fn multi_field_script_value(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1097 self.multi_field_check(name, |_, bv| {
1098 validate_script_value(bv, self.data, sc);
1100 })
1101 }
1102
1103 pub fn field_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1107 let sev = Severity::Error.at_most(self.max_severity);
1108 self.field_check(name, AllowInject::Yes, |_, bv| {
1109 if let Some(token) = bv.expect_value()
1110 && !choices.contains(&token.as_str())
1111 {
1112 let msg = format!("expected one of {}", choices.join(", "));
1113 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1114 }
1115 })
1116 }
1117
1118 #[allow(dead_code)] pub fn multi_field_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1121 let sev = Severity::Error.at_most(self.max_severity);
1122 self.multi_field_check(name, |_, bv| {
1123 if let Some(token) = bv.expect_value()
1124 && !choices.contains(&token.as_str())
1125 {
1126 let msg = format!("expected one of {}", choices.join(", "));
1127 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1128 }
1129 })
1130 }
1131
1132 #[allow(dead_code)]
1134 pub fn multi_field_choice_any_cmp(&mut self, name: &str, choices: &[&str]) -> bool {
1135 let mut found = false;
1136 let sev = Severity::Error.at_most(self.max_severity);
1137 for Field(key, _, bv) in self.block.iter_fields() {
1138 if key.is(name) {
1139 self.known_fields.push(key.as_str());
1140 found = true;
1141 if let Some(token) = bv.expect_value()
1142 && !choices.contains(&token.as_str())
1143 {
1144 let msg = format!("expected one of {}", choices.join(", "));
1145 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1146 }
1147 }
1148 }
1149 found
1150 }
1151
1152 pub fn field_list(&mut self, name: &str) -> bool {
1156 self.field_validated_list(name, |_, _| ())
1157 }
1158
1159 pub fn field_validated_list<F>(&mut self, name: &str, mut f: F) -> bool
1164 where
1165 F: FnMut(&Token, &Everything),
1166 {
1167 self.field_check(name, AllowInject::No, |_, bv| {
1168 if let Some(block) = bv.expect_block() {
1169 for token in block.iter_values_warn() {
1170 f(token, self.data);
1171 }
1172 }
1173 })
1174 }
1175
1176 pub fn field_list_items(&mut self, name: &str, item: Item) -> bool {
1181 let sev = Severity::Error.at_most(self.max_severity);
1182 self.field_validated_list(name, |token, data| {
1183 data.verify_exists_max_sev(item, token, sev);
1184 })
1185 }
1186
1187 #[allow(dead_code)]
1192 pub fn field_list_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1193 let sev = Severity::Error.at_most(self.max_severity);
1194 self.field_validated_list(name, |token, _| {
1195 if !choices.contains(&token.as_str()) {
1196 let msg = format!("expected one of {}", choices.join(", "));
1197 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1198 }
1199 })
1200 }
1201
1202 #[cfg(feature = "ck3")]
1203 pub fn field_icon(&mut self, name: &str, define: &str, suffix: &str) -> bool {
1204 self.field_check(name, AllowInject::Yes, |_, bv| {
1205 if let Some(token) = bv.expect_value() {
1206 self.data.verify_icon(define, token, suffix);
1207 }
1208 })
1209 }
1210
1211 #[allow(dead_code)]
1213 pub fn multi_field_validated_list<F>(&mut self, name: &str, mut f: F) -> bool
1214 where
1215 F: FnMut(&Token, &Everything),
1216 {
1217 self.multi_field_check(name, |_, bv| {
1218 if let Some(block) = bv.expect_block() {
1219 for token in block.iter_values_warn() {
1220 f(token, self.data);
1221 }
1222 }
1223 })
1224 }
1225
1226 #[cfg(any(feature = "ck3", feature = "hoi4", feature = "vic3"))]
1228 pub fn multi_field_list_items(&mut self, name: &str, item: Item) -> bool {
1229 let sev = self.max_severity;
1230 self.multi_field_validated_list(name, |token, data| {
1231 data.verify_exists_max_sev(item, token, sev);
1232 })
1233 }
1234
1235 #[allow(dead_code)]
1237 pub fn multi_field_list_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1238 let sev = Severity::Error.at_most(self.max_severity);
1239 self.multi_field_validated_list(name, |token, _| {
1240 if !choices.contains(&token.as_str()) {
1241 let msg = format!("expected one of {}", choices.join(", "));
1242 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1243 }
1244 })
1245 }
1246
1247 pub fn multi_field_value(&mut self, name: &str) -> Vec<&Token> {
1249 let mut vec = Vec::new();
1250 for Field(key, cmp, bv) in self.block.iter_fields() {
1251 if key.is(name) {
1252 self.known_fields.push(key.as_str());
1253 self.expect_eq_qeq(key, *cmp);
1254 if let Some(token) = bv.expect_value() {
1255 vec.push(token);
1256 }
1257 }
1258 }
1259 vec
1260 }
1261
1262 pub fn multi_field_item(&mut self, name: &str, itype: Item) {
1264 for Field(key, cmp, bv) in self.block.iter_fields() {
1265 if key.is(name) {
1266 self.known_fields.push(key.as_str());
1267 self.expect_eq_qeq(key, *cmp);
1268 if let Some(token) = bv.expect_value() {
1269 self.data.verify_exists_max_sev(itype, token, self.max_severity);
1270 }
1271 }
1272 }
1273 }
1274
1275 pub fn multi_field_any_cmp(&mut self, name: &str) -> bool {
1277 let mut found = false;
1278 for Field(key, _, _) in self.block.iter_fields() {
1279 if key.is(name) {
1280 self.known_fields.push(key.as_str());
1281 found = true;
1282 }
1283 }
1284 found
1285 }
1286
1287 #[allow(dead_code)]
1289 pub fn multi_field_validated_any_cmp<F>(&mut self, name: &str, mut f: F) -> bool
1290 where
1291 F: FnMut(&BV, &Everything),
1292 {
1293 let mut found = false;
1294 for Field(key, _, bv) in self.block.iter_fields() {
1295 if key.is(name) {
1296 self.known_fields.push(key.as_str());
1297 f(bv, self.data);
1298 found = true;
1299 }
1300 }
1301 found
1302 }
1303
1304 pub fn field_validated<F>(&mut self, name: &str, mut f: F) -> bool
1309 where
1310 F: FnMut(&BV, &Everything),
1311 {
1312 let mut found = None;
1313 for Field(key, cmp, bv) in self.block.iter_fields() {
1314 if key.is(name) {
1315 self.known_fields.push(key.as_str());
1316 self.expect_eq_qeq(key, *cmp);
1317 if let Some(other) = found {
1318 dup_assign_error(key, other, AllowInject::No);
1319 }
1320 f(bv, self.data);
1321 found = Some(key);
1322 }
1323 }
1324 found.is_some()
1325 }
1326
1327 pub fn field_validated_key<F>(&mut self, name: &str, mut f: F) -> bool
1329 where
1330 F: FnMut(&Token, &BV, &Everything),
1331 {
1332 let mut found = None;
1333 for Field(key, cmp, bv) in self.block.iter_fields() {
1334 if key.is(name) {
1335 self.known_fields.push(key.as_str());
1336 self.expect_eq_qeq(key, *cmp);
1337 if let Some(other) = found {
1338 dup_assign_error(key, other, AllowInject::No);
1339 }
1340 f(key, bv, self.data);
1341 found = Some(key);
1342 }
1343 }
1344 found.is_some()
1345 }
1346
1347 pub fn field_validated_sc<F>(&mut self, name: &str, sc: &mut ScopeContext, mut f: F) -> bool
1352 where
1353 F: FnMut(&BV, &Everything, &mut ScopeContext),
1354 {
1355 self.field_validated(name, |bv, data| f(bv, data, sc))
1356 }
1357
1358 #[cfg(feature = "ck3")] pub fn field_validated_rooted<F>(&mut self, name: &str, scopes: Scopes, f: F) -> bool
1364 where
1365 F: FnMut(&BV, &Everything, &mut ScopeContext),
1366 {
1367 self.field_validated_build_sc(name, |key| ScopeContext::new(scopes, key), f)
1368 }
1369
1370 #[cfg(feature = "ck3")]
1371 pub fn field_validated_build_sc<B, F>(&mut self, name: &str, mut b: B, mut f: F) -> bool
1372 where
1373 B: FnMut(&Token) -> ScopeContext,
1374 F: FnMut(&BV, &Everything, &mut ScopeContext),
1375 {
1376 self.field_validated_key(name, |key, bv, data| {
1377 let mut sc = b(key);
1378 f(bv, data, &mut sc);
1379 })
1380 }
1381
1382 pub fn multi_field_validated<F>(&mut self, name: &str, mut f: F) -> bool
1384 where
1385 F: FnMut(&BV, &Everything),
1386 {
1387 let mut found = false;
1388 for Field(key, cmp, bv) in self.block.iter_fields() {
1389 if key.is(name) {
1390 self.known_fields.push(key.as_str());
1391 self.expect_eq_qeq(key, *cmp);
1392 f(bv, self.data);
1393 found = true;
1394 }
1395 }
1396 found
1397 }
1398
1399 #[cfg(any(feature = "ck3", feature = "eu5"))] pub fn multi_field_validated_key<F>(&mut self, name: &str, mut f: F) -> bool
1402 where
1403 F: FnMut(&Token, &BV, &Everything),
1404 {
1405 let mut found = false;
1406 for Field(key, cmp, bv) in self.block.iter_fields() {
1407 if key.is(name) {
1408 self.known_fields.push(key.as_str());
1409 self.expect_eq_qeq(key, *cmp);
1410 f(key, bv, self.data);
1411 found = true;
1412 }
1413 }
1414 found
1415 }
1416
1417 #[allow(dead_code)]
1419 pub fn multi_field_validated_sc<F>(
1420 &mut self,
1421 name: &str,
1422 sc: &mut ScopeContext,
1423 mut f: F,
1424 ) -> bool
1425 where
1426 F: FnMut(&BV, &Everything, &mut ScopeContext),
1427 {
1428 self.multi_field_validated(name, |b, data| f(b, data, sc))
1429 }
1430
1431 pub fn multi_field_validated_block<F>(&mut self, name: &str, mut f: F) -> bool
1433 where
1434 F: FnMut(&Block, &Everything),
1435 {
1436 let mut found = false;
1437 for Field(key, cmp, bv) in self.block.iter_fields() {
1438 if (self.case_sensitive && key.is(name))
1439 || (!self.case_sensitive && key.lowercase_is(name))
1440 {
1441 self.known_fields.push(key.as_str());
1442 self.expect_eq_qeq(key, *cmp);
1443 if let Some(block) = bv.expect_block() {
1444 f(block, self.data);
1445 }
1446 found = true;
1447 }
1448 }
1449 found
1450 }
1451
1452 #[allow(dead_code)]
1454 pub fn multi_field_validated_block_sc<F>(
1455 &mut self,
1456 name: &str,
1457 sc: &mut ScopeContext,
1458 mut f: F,
1459 ) -> bool
1460 where
1461 F: FnMut(&Block, &Everything, &mut ScopeContext),
1462 {
1463 self.multi_field_validated_block(name, |b, data| f(b, data, sc))
1464 }
1465
1466 pub fn field_validated_block<F>(&mut self, name: &str, mut f: F) -> bool
1471 where
1472 F: FnMut(&Block, &Everything),
1473 {
1474 let mut found = None;
1475 for Field(key, cmp, bv) in self.block.iter_fields() {
1476 if (self.case_sensitive && key.is(name))
1477 || (!self.case_sensitive && key.lowercase_is(name))
1478 {
1479 self.known_fields.push(key.as_str());
1480 if let Some(other) = found {
1481 dup_assign_error(key, other, AllowInject::No);
1482 }
1483 self.expect_eq_qeq(key, *cmp);
1484 if let Some(block) = bv.expect_block() {
1485 f(block, self.data);
1486 }
1487 found = Some(key);
1488 }
1489 }
1490 found.is_some()
1491 }
1492
1493 #[cfg(feature = "vic3")]
1496 pub fn multi_warn_field_validated_block<F>(&mut self, name: &str, mut f: F) -> bool
1497 where
1498 F: FnMut(&Block, &Everything),
1499 {
1500 let mut found: Option<&Token> = None;
1501 for Field(key, cmp, bv) in self.block.iter_fields() {
1502 if (self.case_sensitive && key.is(name))
1503 || (!self.case_sensitive && key.lowercase_is(name))
1504 {
1505 self.known_fields.push(key.as_str());
1506 if let Some(other) = found {
1507 dup_assign_error(key, other, AllowInject::Yes);
1508 }
1509 self.expect_eq_qeq(key, *cmp);
1510 if let Some(block) = bv.expect_block() {
1511 f(block, self.data);
1512 }
1513 found = Some(key);
1514 }
1515 }
1516 found.is_some()
1517 }
1518
1519 pub fn field_validated_key_block<F>(&mut self, name: &str, mut f: F) -> bool
1521 where
1522 F: FnMut(&Token, &Block, &Everything),
1523 {
1524 let mut found = None;
1525 for Field(key, cmp, bv) in self.block.iter_fields() {
1526 if (self.case_sensitive && key.is(name))
1527 || (!self.case_sensitive && key.lowercase_is(name))
1528 {
1529 self.known_fields.push(key.as_str());
1530 if let Some(other) = found {
1531 dup_assign_error(key, other, AllowInject::No);
1532 }
1533 self.expect_eq_qeq(key, *cmp);
1534 if let Some(block) = bv.expect_block() {
1535 f(key, block, self.data);
1536 }
1537 found = Some(key);
1538 }
1539 }
1540 found.is_some()
1541 }
1542
1543 #[allow(dead_code)]
1544 pub fn field_validated_block_build_sc<B, F>(&mut self, name: &str, mut b: B, mut f: F) -> bool
1545 where
1546 B: FnMut(&Token) -> ScopeContext,
1547 F: FnMut(&Block, &Everything, &mut ScopeContext),
1548 {
1549 let mut found = None;
1550 for Field(key, cmp, bv) in self.block.iter_fields() {
1551 if (self.case_sensitive && key.is(name))
1552 || (!self.case_sensitive && key.lowercase_is(name))
1553 {
1554 self.known_fields.push(key.as_str());
1555 if let Some(other) = found {
1556 dup_assign_error(key, other, AllowInject::No);
1557 }
1558 self.expect_eq_qeq(key, *cmp);
1559 if let Some(block) = bv.expect_block() {
1560 let mut sc = b(key);
1561 f(block, self.data, &mut sc);
1562 }
1563 found = Some(key);
1564 }
1565 }
1566 found.is_some()
1567 }
1568
1569 pub fn multi_field_validated_key_block<F>(&mut self, name: &str, mut f: F) -> bool
1571 where
1572 F: FnMut(&Token, &Block, &Everything),
1573 {
1574 let mut found = false;
1575 for Field(key, cmp, bv) in self.block.iter_fields() {
1576 if (self.case_sensitive && key.is(name))
1577 || (!self.case_sensitive && key.lowercase_is(name))
1578 {
1579 self.known_fields.push(key.as_str());
1580 self.expect_eq_qeq(key, *cmp);
1581 if let Some(block) = bv.expect_block() {
1582 f(key, block, self.data);
1583 }
1584 found = true;
1585 }
1586 }
1587 found
1588 }
1589
1590 pub fn field_validated_block_sc<F>(
1592 &mut self,
1593 name: &str,
1594 sc: &mut ScopeContext,
1595 mut f: F,
1596 ) -> bool
1597 where
1598 F: FnMut(&Block, &Everything, &mut ScopeContext),
1599 {
1600 self.field_validated_block(name, |b, data| f(b, data, sc))
1601 }
1602
1603 #[allow(dead_code)]
1608 pub fn field_validated_block_rooted<F>(&mut self, name: &str, scopes: Scopes, f: F) -> bool
1609 where
1610 F: FnMut(&Block, &Everything, &mut ScopeContext),
1611 {
1612 self.field_validated_block_build_sc(name, |key| ScopeContext::new(scopes, key), f)
1613 }
1614
1615 #[cfg(feature = "ck3")] pub fn multi_field_validated_block_rooted<F>(&mut self, name: &str, scopes: Scopes, mut f: F)
1618 where
1619 F: FnMut(&Block, &Everything, &mut ScopeContext),
1620 {
1621 for Field(key, cmp, bv) in self.block.iter_fields() {
1622 if (self.case_sensitive && key.is(name))
1623 || (!self.case_sensitive && key.lowercase_is(name))
1624 {
1625 self.known_fields.push(key.as_str());
1626 self.expect_eq_qeq(key, *cmp);
1627 if let Some(block) = bv.expect_block() {
1628 let mut sc = ScopeContext::new(scopes, key);
1629 f(block, self.data, &mut sc);
1630 }
1631 }
1632 }
1633 }
1634
1635 #[cfg(feature = "ck3")] pub fn field_validated_block_rerooted<F>(
1641 &mut self,
1642 name: &str,
1643 sc: &ScopeContext,
1644 scopes: Scopes,
1645 mut f: F,
1646 ) -> bool
1647 where
1648 F: FnMut(&Block, &Everything, &mut ScopeContext),
1649 {
1650 let mut found = None;
1651 for Field(key, cmp, bv) in self.block.iter_fields() {
1652 if (self.case_sensitive && key.is(name))
1653 || (!self.case_sensitive && key.lowercase_is(name))
1654 {
1655 self.known_fields.push(key.as_str());
1656 if let Some(other) = found {
1657 dup_assign_error(key, other, AllowInject::No);
1658 }
1659 self.expect_eq_qeq(key, *cmp);
1660 if let Some(block) = bv.expect_block() {
1661 let mut sc = sc.clone();
1662 sc.change_root(scopes, key);
1663 f(block, self.data, &mut sc);
1664 }
1665 found = Some(key);
1666 }
1667 }
1668 found.is_some()
1669 }
1670
1671 #[cfg(feature = "ck3")] pub fn multi_field_block(&mut self, name: &str) -> bool {
1674 let mut found = false;
1675 for Field(key, cmp, bv) in self.block.iter_fields() {
1676 if (self.case_sensitive && key.is(name))
1677 || (!self.case_sensitive && key.lowercase_is(name))
1678 {
1679 self.known_fields.push(key.as_str());
1680 self.expect_eq_qeq(key, *cmp);
1681 bv.expect_block();
1682 found = true;
1683 }
1684 }
1685 found
1686 }
1687
1688 pub fn req_tokens_integers_exactly(&mut self, expect: usize) {
1691 self.accepted_tokens = true;
1692 let mut found = 0;
1693 for token in self.block.iter_values() {
1694 if token.expect_integer().is_some() {
1695 found += 1;
1696 }
1697 }
1698 if found != expect {
1699 let msg = format!("expected {expect} integers");
1700 let sev = Severity::Error.at_most(self.max_severity);
1701 report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
1702 }
1703 }
1704
1705 pub fn req_tokens_numbers_exactly(&mut self, expect: usize) {
1708 self.accepted_tokens = true;
1709 let mut found = 0;
1710 for token in self.block.iter_values() {
1711 if token.expect_number().is_some() {
1712 found += 1;
1713 }
1714 }
1715 if found != expect {
1716 let msg = format!("expected {expect} numbers");
1717 let sev = Severity::Error.at_most(self.max_severity);
1718 report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
1719 }
1720 }
1721
1722 pub fn field_list_numeric_exactly(&mut self, name: &str, expect: usize) {
1726 self.field_validated_block(name, |block, data| {
1727 let mut vd = Validator::new(block, data);
1728 vd.req_tokens_numbers_exactly(expect);
1729 });
1730 }
1731
1732 #[allow(dead_code)]
1734 pub fn req_tokens_precise_numbers_exactly(&mut self, expect: usize) {
1735 self.accepted_tokens = true;
1736 let mut found = 0;
1737 for token in self.block.iter_values() {
1738 if token.expect_precise_number().is_some() {
1739 found += 1;
1740 }
1741 }
1742 if found != expect {
1743 let msg = format!("expected {expect} numbers");
1744 let sev = Severity::Error.at_most(self.max_severity);
1745 report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
1746 }
1747 }
1748
1749 #[allow(dead_code)]
1751 pub fn field_list_precise_numeric_exactly(&mut self, name: &str, expect: usize) {
1752 self.field_validated_block(name, |block, data| {
1753 let mut vd = Validator::new(block, data);
1754 vd.req_tokens_precise_numbers_exactly(expect);
1755 });
1756 }
1757
1758 pub fn field_list_integers_exactly(&mut self, name: &str, expect: usize) {
1760 self.field_validated_block(name, |block, data| {
1761 let mut vd = Validator::new(block, data);
1762 vd.req_tokens_integers_exactly(expect);
1763 });
1764 }
1765
1766 #[allow(dead_code)]
1769 pub fn advice_field(&mut self, name: &str, msg: &str) {
1770 if let Some(key) = self.block.get_key(name) {
1771 self.known_fields.push(key.as_str());
1772 let sev = Severity::Untidy.at_most(self.max_severity);
1773 report(ErrorKey::Unneeded, sev).msg(msg).loc(key).push();
1774 }
1775 }
1776
1777 pub fn values(&mut self) -> Vec<&Token> {
1781 self.accepted_tokens = true;
1782 self.block.iter_values().collect()
1783 }
1784
1785 #[allow(dead_code)]
1789 pub fn blocks(&mut self) -> Vec<&Block> {
1790 self.accepted_blocks = true;
1791 self.block.iter_blocks().collect()
1792 }
1793
1794 #[cfg(any(feature = "vic3", feature = "imperator"))] pub fn validated_blocks<F>(&mut self, mut f: F)
1798 where
1799 F: FnMut(&Block, &Everything),
1800 {
1801 self.accepted_blocks = true;
1802 for block in self.block.iter_blocks() {
1803 f(block, self.data);
1804 }
1805 }
1806
1807 pub fn integer_blocks(&mut self) -> Vec<(&Token, &Block)> {
1811 let mut vec = Vec::new();
1812 for Field(key, cmp, bv) in self.block.iter_fields() {
1813 if key.is_integer() {
1814 self.known_fields.push(key.as_str());
1815 self.expect_eq_qeq(key, *cmp);
1816 if let Some(block) = bv.expect_block() {
1817 vec.push((key, block));
1818 }
1819 }
1820 }
1821 vec
1822 }
1823
1824 pub fn integer_values(&mut self) -> Vec<(&Token, &Token)> {
1828 let mut vec = Vec::new();
1829 for Field(key, cmp, bv) in self.block.iter_fields() {
1830 if key.is_integer() {
1831 self.known_fields.push(key.as_str());
1832 self.expect_eq_qeq(key, *cmp);
1833 if let Some(token) = bv.expect_value() {
1834 vec.push((key, token));
1835 }
1836 }
1837 }
1838 vec
1839 }
1840
1841 #[allow(dead_code)]
1843 pub fn integer_keys<F: FnMut(&Token, &BV)>(&mut self, mut f: F) {
1844 for Field(key, cmp, bv) in self.block.iter_fields() {
1845 if key.is_integer() {
1846 self.known_fields.push(key.as_str());
1847 self.expect_eq_qeq(key, *cmp);
1848 f(key, bv);
1849 }
1850 }
1851 }
1852
1853 #[cfg(feature = "vic3")] pub fn numeric_keys<F: FnMut(&Token, &BV)>(&mut self, mut f: F) {
1858 for Field(key, cmp, bv) in self.block.iter_fields() {
1859 if key.is_number() {
1860 self.known_fields.push(key.as_str());
1861 self.expect_eq_qeq(key, *cmp);
1862 f(key, bv);
1863 }
1864 }
1865 }
1866
1867 #[cfg(any(feature = "ck3", feature = "hoi4"))]
1870 pub fn validate_history_blocks<F>(&mut self, mut f: F)
1871 where
1872 F: FnMut(Date, &Token, &Block, &Everything),
1873 {
1874 for Field(key, cmp, bv) in self.block.iter_fields() {
1875 if let Ok(date) = Date::try_from(key) {
1876 key.expect_date(); self.known_fields.push(key.as_str());
1878 self.expect_eq_qeq(key, *cmp);
1879 if let Some(block) = bv.expect_block() {
1880 f(date, key, block, self.data);
1881 }
1882 }
1883 }
1884 }
1885
1886 #[allow(dead_code)]
1890 pub fn validate_item_key_fields<F>(&mut self, itype: Item, mut f: F)
1891 where
1892 F: FnMut(&Token, &BV, &Everything),
1893 {
1894 let mut visited_fields = TigerHashSet::default();
1895 for Field(key, _, bv) in self.block.iter_fields() {
1896 if !self.known_fields.contains(&key.as_str()) {
1897 self.data.verify_exists(itype, key);
1898
1899 match visited_fields.get(key.as_str()) {
1900 Some(&duplicate) => dup_assign_error(key, duplicate, AllowInject::No),
1901 None => {
1902 visited_fields.insert(key);
1903 }
1904 }
1905
1906 self.known_fields.push(key.as_str());
1907
1908 f(key, bv, self.data);
1909 }
1910 }
1911 }
1912
1913 #[allow(dead_code)]
1917 pub fn validate_item_key_values<F>(&mut self, itype: Item, mut f: F)
1918 where
1919 F: FnMut(&Token, ValueValidator),
1920 {
1921 let sev = self.max_severity;
1922 self.validate_item_key_fields(itype, |key, bv, data| {
1923 if let Some(value) = bv.expect_value() {
1924 let mut vd = ValueValidator::new(value, data);
1925 vd.set_max_severity(sev);
1926 f(key, vd);
1927 }
1928 });
1929 }
1930
1931 #[allow(dead_code)]
1935 pub fn validate_item_key_blocks<F>(&mut self, itype: Item, mut f: F)
1936 where
1937 F: FnMut(&Token, &Block, &Everything),
1938 {
1939 self.validate_item_key_fields(itype, |key, bv, data| {
1940 if let Some(block) = bv.expect_block() {
1941 f(key, block, data);
1942 }
1943 });
1944 }
1945
1946 pub fn unknown_fields<F: FnMut(&Token, &BV)>(&mut self, mut f: F) {
1950 self.accepted_block_fields = true;
1951 self.accepted_value_fields = true;
1952 for Field(key, cmp, bv) in self.block.iter_fields() {
1953 self.expect_eq_qeq(key, *cmp);
1954 if !self.known_fields.contains(&key.as_str()) {
1955 f(key, bv);
1956 }
1957 }
1958 }
1959
1960 pub fn unknown_block_fields<F: FnMut(&Token, &Block)>(&mut self, mut f: F) {
1963 self.accepted_block_fields = true;
1964 for Field(key, cmp, bv) in self.block.iter_fields() {
1965 if let Some(block) = bv.get_block() {
1966 self.expect_eq_qeq(key, *cmp);
1967 if !self.known_fields.contains(&key.as_str()) {
1968 f(key, block);
1969 }
1970 }
1971 }
1972 }
1973
1974 pub fn unknown_value_fields<F: FnMut(&Token, &Token)>(&mut self, mut f: F) {
1977 self.accepted_value_fields = true;
1978 for Field(key, cmp, bv) in self.block.iter_fields() {
1979 if let Some(value) = bv.get_value() {
1980 self.expect_eq_qeq(key, *cmp);
1981 if !self.known_fields.contains(&key.as_str()) {
1982 f(key, value);
1983 }
1984 }
1985 }
1986 }
1987
1988 pub fn unknown_fields_cmp<F: FnMut(&Token, Comparator, &BV)>(&mut self, mut f: F) {
1991 self.accepted_block_fields = true;
1992 self.accepted_value_fields = true;
1993 for Field(key, cmp, bv) in self.block.iter_fields() {
1994 if !self.known_fields.contains(&key.as_str()) {
1995 self.expect_eq_qeq(key, *cmp);
1996 f(key, *cmp, bv);
1997 }
1998 }
1999 }
2000
2001 pub fn unknown_fields_any_cmp<F: FnMut(&Token, Comparator, &BV)>(&mut self, mut f: F) {
2003 self.accepted_block_fields = true;
2004 self.accepted_value_fields = true;
2005 for Field(key, cmp, bv) in self.block.iter_fields() {
2006 if !self.known_fields.contains(&key.as_str()) {
2007 f(key, *cmp, bv);
2008 }
2009 }
2010 }
2011
2012 pub fn no_warn_remaining(&mut self) {
2015 self.accepted_block_fields = true;
2016 self.accepted_value_fields = true;
2017 self.accepted_tokens = true;
2018 self.accepted_blocks = true;
2019 }
2020
2021 pub fn warn_remaining(&mut self) -> bool {
2025 let mut warned = false;
2026 for item in self.block.iter_items() {
2027 match item {
2028 BlockItem::Field(Field(key, _, bv)) => match bv {
2029 BV::Value(_) => {
2030 if !self.accepted_value_fields && !self.known_fields.contains(&key.as_str())
2031 {
2032 let msg = format!("unknown field `{key}`");
2033 let sev = Severity::Error.at_most(self.max_severity);
2034 report(ErrorKey::UnknownField, sev).weak().msg(msg).loc(key).push();
2035 warned = true;
2036 }
2037 }
2038 BV::Block(_) => {
2039 if !self.accepted_block_fields && !self.known_fields.contains(&key.as_str())
2040 {
2041 let msg = format!("unknown field `{key}`");
2042 let sev = Severity::Error.at_most(self.max_severity);
2043 report(ErrorKey::UnknownField, sev).weak().msg(msg).loc(key).push();
2044 warned = true;
2045 }
2046 }
2047 },
2048 BlockItem::Value(t) => {
2049 if !self.accepted_tokens {
2050 let msg = format!("found loose value {t}, expected only `key =`");
2051 let sev = Severity::Error.at_most(self.max_severity);
2052 report(ErrorKey::Structure, sev).msg(msg).loc(t).push();
2053 warned = true;
2054 }
2055 }
2056 BlockItem::Block(b) => {
2057 if !self.accepted_blocks {
2058 let msg = "found sub-block, expected only `key =`";
2059 let sev = Severity::Error.at_most(self.max_severity);
2060 report(ErrorKey::Structure, sev).msg(msg).loc(b).push();
2061 warned = true;
2062 }
2063 }
2064 }
2065 }
2066 self.no_warn_remaining();
2067 warned
2068 }
2069
2070 fn expect_eq_qeq(&self, key: &Token, cmp: Comparator) {
2071 #[allow(clippy::collapsible_else_if)]
2072 if self.allow_questionmark_equals {
2073 if !matches!(cmp, Comparator::Equals(Single | Question)) {
2074 let msg = format!("expected `{key} =` or `?=`, found `{cmp}`");
2075 let sev = Severity::Error.at_most(self.max_severity);
2076 report(ErrorKey::Validation, sev).msg(msg).loc(key).push();
2077 }
2078 } else {
2079 if !matches!(cmp, Comparator::Equals(Single)) {
2080 let msg = format!("expected `{key} =`, found `{cmp}`");
2081 let sev = Severity::Error.at_most(self.max_severity);
2082 report(ErrorKey::Validation, sev).msg(msg).loc(key).push();
2083 }
2084 }
2085 }
2086}
2087
2088impl Drop for Validator<'_> {
2089 fn drop(&mut self) {
2090 self.warn_remaining();
2091 }
2092}