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 if !token.is("") {
510 self.data.verify_exists_max_sev(itype, token, sev);
511 }
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 if !self.data.item_exists(itype, token.as_str()) {
598 validate_target(token, self.data, sc, outscopes);
600 }
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 if !self.data.item_exists(itype, token.as_str()) {
619 validate_target_ok_this(token, self.data, sc, outscopes);
621 }
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 if !token.is("yes") && !token.is("no") && !token.is("YES") && !token.is("NO") {
642 report(ErrorKey::Validation, sev).msg("expected yes or no").loc(token).push();
643 }
644 }
645 })
646 }
647
648 pub fn field_integer(&mut self, name: &str) -> bool {
652 self.field_check(name, AllowInject::Yes, |_, bv| {
653 if let Some(token) = bv.expect_value() {
654 token.expect_integer();
656 }
657 })
658 }
659
660 pub fn field_integer_range<R: RangeBounds<i64>>(&mut self, name: &str, range: R) {
664 let sev = Severity::Error.at_most(self.max_severity);
665 self.field_check(name, AllowInject::Yes, |_, bv| {
666 if let Some(token) = bv.expect_value() {
667 if let Some(i) = token.expect_integer() {
669 if !range.contains(&i) {
670 let low = match range.start_bound() {
671 Bound::Unbounded => None,
672 Bound::Included(&n) => Some(n),
673 Bound::Excluded(&n) => Some(n + 1),
674 };
675 let high = match range.end_bound() {
676 Bound::Unbounded => None,
677 Bound::Included(&n) => Some(n),
678 Bound::Excluded(&n) => Some(n - 1),
679 };
680 let msg;
681 if let (Some(low), Some(high)) = (low, high) {
682 msg = format!("should be between {low} and {high} (inclusive)");
683 } else if let Some(low) = low {
684 msg = format!("should be at least {low}");
685 } else if let Some(high) = high {
686 msg = format!("should be at most {high}");
687 } else {
688 unreachable!(); }
690 report(ErrorKey::Range, sev).msg(msg).loc(token).push();
691 }
692 }
693 }
694 });
695 }
696
697 pub fn field_numeric(&mut self, name: &str) -> bool {
702 self.field_check(name, AllowInject::Yes, |_, bv| {
703 if let Some(token) = bv.expect_value() {
704 token.expect_number();
705 }
706 })
707 }
708
709 #[cfg(feature = "hoi4")]
714 pub fn multi_field_numeric(&mut self, name: &str) -> bool {
715 self.multi_field_check(name, |_, bv| {
716 if let Some(token) = bv.expect_value() {
717 token.expect_number();
718 }
719 })
720 }
721
722 pub fn field_precise_numeric(&mut self, name: &str) -> bool {
726 self.field_check(name, AllowInject::Yes, |_, bv| {
727 if let Some(token) = bv.expect_value() {
728 token.expect_precise_number();
729 }
730 })
731 }
732
733 #[cfg(any(feature = "ck3", feature = "vic3"))]
734 pub fn field_numeric_range_internal<R: RangeBounds<f64>>(
735 &mut self,
736 name: &str,
737 range: R,
738 precise: bool,
739 ) {
740 let sev = Severity::Error.at_most(self.max_severity);
741 self.field_check(name, AllowInject::Yes, |_, bv| {
742 if let Some(token) = bv.expect_value() {
743 let numeric =
744 if precise { token.expect_precise_number() } else { token.expect_number() };
745 if let Some(f) = numeric {
746 if !range.contains(&f) {
747 let low = match range.start_bound() {
748 Bound::Unbounded => None,
749 Bound::Included(f) => Some(format!("{f} (inclusive)")),
750 Bound::Excluded(f) => Some(format!("{f}")),
751 };
752 let high = match range.end_bound() {
753 Bound::Unbounded => None,
754 Bound::Included(f) => Some(format!("{f} (inclusive)")),
755 Bound::Excluded(f) => Some(format!("{f}")),
756 };
757 let msg;
758 if let (Some(low), Some(high)) = (low.as_ref(), high.as_ref()) {
759 msg = format!("should be between {low} and {high}");
760 } else if let Some(low) = low {
761 msg = format!("should be at least {low}");
762 } else if let Some(high) = high {
763 msg = format!("should be at most {high}");
764 } else {
765 unreachable!(); }
767 report(ErrorKey::Range, sev).msg(msg).loc(token).push();
768 }
769 }
770 }
771 });
772 }
773
774 #[cfg(any(feature = "ck3", feature = "vic3"))]
778 pub fn field_numeric_range<R: RangeBounds<f64>>(&mut self, name: &str, range: R) {
779 self.field_numeric_range_internal(name, range, false);
780 }
781
782 #[cfg(feature = "ck3")]
785 pub fn field_precise_numeric_range<R: RangeBounds<f64>>(&mut self, name: &str, range: R) {
786 self.field_numeric_range_internal(name, range, true);
787 }
788
789 pub fn field_date(&mut self, name: &str) -> bool {
795 let sev = Severity::Error.at_most(self.max_severity);
796 self.field_check(name, AllowInject::Yes, |_, bv| {
797 if let Some(token) = bv.expect_value() {
798 if Date::from_str(token.as_str()).is_err() {
799 let msg = "expected date value";
800 report(ErrorKey::Validation, sev).msg(msg).loc(token).push();
801 }
802 }
803 })
804 }
805
806 pub fn field_trigger(
811 &mut self,
812 name: &str,
813 tooltipped: Tooltipped,
814 sc: &mut ScopeContext,
815 ) -> bool {
816 let max_sev = self.max_severity;
817 self.field_validated_block(name, |block, data| {
818 let mut vd = Validator::new(block, data);
819 vd.set_max_severity(max_sev);
820 validate_trigger_internal(
821 Lowercase::empty(),
822 ListType::None,
823 block,
824 data,
825 sc,
826 vd,
827 tooltipped,
828 false,
829 );
830 })
831 }
832
833 #[allow(dead_code)]
839 pub fn field_trigger_rooted(
840 &mut self,
841 name: &str,
842 tooltipped: Tooltipped,
843 scope: Scopes,
844 ) -> bool {
845 let max_sev = self.max_severity;
846 self.field_validated_key_block(name, |key, block, data| {
847 let mut vd = Validator::new(block, data);
848 let mut sc = ScopeContext::new(scope, key);
849 vd.set_max_severity(max_sev);
850 validate_trigger_internal(
851 Lowercase::empty(),
852 ListType::None,
853 block,
854 data,
855 &mut sc,
856 vd,
857 tooltipped,
858 false,
859 );
860 })
861 }
862
863 #[allow(dead_code)]
869 pub fn field_trigger_builder<F>(
870 &mut self,
871 name: &str,
872 tooltipped: Tooltipped,
873 mut sc_builder: F,
874 ) -> bool
875 where
876 F: FnMut(&Token) -> ScopeContext,
877 {
878 let max_sev = self.max_severity;
879 self.field_validated_key_block(name, |key, block, data| {
880 let mut vd = Validator::new(block, data);
881 vd.set_max_severity(max_sev);
882 let mut sc = sc_builder(key);
883 validate_trigger_internal(
884 Lowercase::empty(),
885 ListType::None,
886 block,
887 data,
888 &mut sc,
889 vd,
890 tooltipped,
891 false,
892 );
893 })
894 }
895
896 #[allow(dead_code)]
901 pub fn field_effect(
902 &mut self,
903 name: &str,
904 tooltipped: Tooltipped,
905 sc: &mut ScopeContext,
906 ) -> bool {
907 let max_sev = self.max_severity;
908 self.field_validated_block(name, |block, data| {
909 let mut vd = Validator::new(block, data);
910 vd.set_max_severity(max_sev);
911 validate_effect_internal(
912 Lowercase::empty(),
913 ListType::None,
914 block,
915 data,
916 sc,
917 &mut vd,
918 tooltipped,
919 &mut SpecialTokens::none(),
920 );
921 })
922 }
923
924 #[allow(dead_code)]
930 pub fn field_effect_rooted(
931 &mut self,
932 name: &str,
933 tooltipped: Tooltipped,
934 scope: Scopes,
935 ) -> bool {
936 let max_sev = self.max_severity;
937 self.field_validated_key_block(name, |key, block, data| {
938 let mut vd = Validator::new(block, data);
939 vd.set_max_severity(max_sev);
940 let mut sc = ScopeContext::new(scope, key);
941 validate_effect_internal(
942 Lowercase::empty(),
943 ListType::None,
944 block,
945 data,
946 &mut sc,
947 &mut vd,
948 tooltipped,
949 &mut SpecialTokens::none(),
950 );
951 })
952 }
953
954 #[allow(dead_code)]
960 pub fn field_effect_builder<F>(
961 &mut self,
962 name: &str,
963 tooltipped: Tooltipped,
964 mut sc_builder: F,
965 ) -> bool
966 where
967 F: FnMut(&Token) -> ScopeContext,
968 {
969 let max_sev = self.max_severity;
970 self.field_validated_key_block(name, |key, block, data| {
971 let mut vd = Validator::new(block, data);
972 vd.set_max_severity(max_sev);
973 let mut sc = sc_builder(key);
974 validate_effect_internal(
975 Lowercase::empty(),
976 ListType::None,
977 block,
978 data,
979 &mut sc,
980 &mut vd,
981 tooltipped,
982 &mut SpecialTokens::none(),
983 );
984 })
985 }
986
987 #[cfg(feature = "jomini")]
997 pub fn field_script_value(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
998 self.field_check(name, AllowInject::Yes, |_, bv| {
999 validate_script_value(bv, self.data, sc);
1001 })
1002 }
1003
1004 #[cfg(any(feature = "ck3", feature = "vic3", feature = "eu5"))]
1008 pub fn field_script_value_no_breakdown(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1009 self.field_check(name, AllowInject::Yes, |_, bv| {
1010 validate_script_value_no_breakdown(bv, self.data, sc);
1012 })
1013 }
1014
1015 #[cfg(feature = "jomini")]
1022 pub fn field_script_value_rooted(&mut self, name: &str, scopes: Scopes) -> bool {
1023 self.field_check(name, AllowInject::Yes, |key, bv| {
1024 let mut sc = ScopeContext::new(scopes, key);
1025 validate_script_value(bv, self.data, &mut sc);
1027 })
1028 }
1029
1030 #[cfg(feature = "jomini")]
1035 #[allow(dead_code)]
1036 pub fn field_script_value_no_breakdown_rooted(&mut self, name: &str, scopes: Scopes) -> bool {
1037 self.field_check(name, AllowInject::Yes, |key, bv| {
1038 let mut sc = ScopeContext::new(scopes, key);
1039 validate_script_value(bv, self.data, &mut sc);
1041 })
1042 }
1043
1044 #[cfg(feature = "jomini")]
1048 #[allow(dead_code)]
1049 pub fn field_script_value_builder<F>(&mut self, name: &str, mut f: F) -> bool
1050 where
1051 F: FnMut(&Token) -> ScopeContext,
1052 {
1053 self.field_check(name, AllowInject::Yes, |key, bv| {
1054 let mut sc = f(key);
1055 validate_script_value(bv, self.data, &mut sc);
1057 })
1058 }
1059
1060 #[cfg(feature = "jomini")]
1066 #[allow(dead_code)]
1067 pub fn field_script_value_no_breakdown_builder<F>(&mut self, name: &str, mut f: F) -> bool
1068 where
1069 F: FnMut(&Token) -> ScopeContext,
1070 {
1071 self.field_check(name, AllowInject::Yes, |key, bv| {
1072 let mut sc = f(key);
1073 validate_script_value_no_breakdown(bv, self.data, &mut sc);
1075 })
1076 }
1077
1078 #[cfg(feature = "jomini")]
1080 pub fn field_script_value_or_flag(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1081 self.field_check(name, AllowInject::Yes, |_, bv| {
1082 if let Some(token) = bv.get_value() {
1084 validate_target(token, self.data, sc, Scopes::Value | Scopes::Bool | Scopes::Flag);
1085 } else {
1086 validate_script_value(bv, self.data, sc);
1087 }
1088 })
1089 }
1090
1091 #[cfg(feature = "jomini")]
1093 pub fn multi_field_script_value(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1094 self.multi_field_check(name, |_, bv| {
1095 validate_script_value(bv, self.data, sc);
1097 })
1098 }
1099
1100 pub fn field_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1104 let sev = Severity::Error.at_most(self.max_severity);
1105 self.field_check(name, AllowInject::Yes, |_, bv| {
1106 if let Some(token) = bv.expect_value() {
1107 if !choices.contains(&token.as_str()) {
1108 let msg = format!("expected one of {}", choices.join(", "));
1109 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1110 }
1111 }
1112 })
1113 }
1114
1115 #[allow(dead_code)] pub fn multi_field_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1118 let sev = Severity::Error.at_most(self.max_severity);
1119 self.multi_field_check(name, |_, bv| {
1120 if let Some(token) = bv.expect_value() {
1121 if !choices.contains(&token.as_str()) {
1122 let msg = format!("expected one of {}", choices.join(", "));
1123 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1124 }
1125 }
1126 })
1127 }
1128
1129 #[allow(dead_code)]
1131 pub fn multi_field_choice_any_cmp(&mut self, name: &str, choices: &[&str]) -> bool {
1132 let mut found = false;
1133 let sev = Severity::Error.at_most(self.max_severity);
1134 for Field(key, _, bv) in self.block.iter_fields() {
1135 if key.is(name) {
1136 self.known_fields.push(key.as_str());
1137 found = true;
1138 if let Some(token) = bv.expect_value() {
1139 if !choices.contains(&token.as_str()) {
1140 let msg = format!("expected one of {}", choices.join(", "));
1141 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1142 }
1143 }
1144 }
1145 }
1146 found
1147 }
1148
1149 pub fn field_list(&mut self, name: &str) -> bool {
1153 self.field_validated_list(name, |_, _| ())
1154 }
1155
1156 pub fn field_validated_list<F>(&mut self, name: &str, mut f: F) -> bool
1161 where
1162 F: FnMut(&Token, &Everything),
1163 {
1164 self.field_check(name, AllowInject::No, |_, bv| {
1165 if let Some(block) = bv.expect_block() {
1166 for token in block.iter_values_warn() {
1167 f(token, self.data);
1168 }
1169 }
1170 })
1171 }
1172
1173 pub fn field_list_items(&mut self, name: &str, item: Item) -> bool {
1178 let sev = Severity::Error.at_most(self.max_severity);
1179 self.field_validated_list(name, |token, data| {
1180 data.verify_exists_max_sev(item, token, sev);
1181 })
1182 }
1183
1184 #[allow(dead_code)]
1189 pub fn field_list_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1190 let sev = Severity::Error.at_most(self.max_severity);
1191 self.field_validated_list(name, |token, _| {
1192 if !choices.contains(&token.as_str()) {
1193 let msg = format!("expected one of {}", choices.join(", "));
1194 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1195 }
1196 })
1197 }
1198
1199 #[cfg(feature = "ck3")]
1200 pub fn field_icon(&mut self, name: &str, define: &str, suffix: &str) -> bool {
1201 self.field_check(name, AllowInject::Yes, |_, bv| {
1202 if let Some(token) = bv.expect_value() {
1203 self.data.verify_icon(define, token, suffix);
1204 }
1205 })
1206 }
1207
1208 #[allow(dead_code)]
1210 pub fn multi_field_validated_list<F>(&mut self, name: &str, mut f: F) -> bool
1211 where
1212 F: FnMut(&Token, &Everything),
1213 {
1214 self.multi_field_check(name, |_, bv| {
1215 if let Some(block) = bv.expect_block() {
1216 for token in block.iter_values_warn() {
1217 f(token, self.data);
1218 }
1219 }
1220 })
1221 }
1222
1223 #[cfg(any(feature = "ck3", feature = "hoi4", feature = "vic3"))]
1225 pub fn multi_field_list_items(&mut self, name: &str, item: Item) -> bool {
1226 let sev = self.max_severity;
1227 self.multi_field_validated_list(name, |token, data| {
1228 data.verify_exists_max_sev(item, token, sev);
1229 })
1230 }
1231
1232 #[allow(dead_code)]
1234 pub fn multi_field_list_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1235 let sev = Severity::Error.at_most(self.max_severity);
1236 self.multi_field_validated_list(name, |token, _| {
1237 if !choices.contains(&token.as_str()) {
1238 let msg = format!("expected one of {}", choices.join(", "));
1239 report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1240 }
1241 })
1242 }
1243
1244 pub fn multi_field_value(&mut self, name: &str) -> Vec<&Token> {
1246 let mut vec = Vec::new();
1247 for Field(key, cmp, bv) in self.block.iter_fields() {
1248 if key.is(name) {
1249 self.known_fields.push(key.as_str());
1250 self.expect_eq_qeq(key, *cmp);
1251 if let Some(token) = bv.expect_value() {
1252 vec.push(token);
1253 }
1254 }
1255 }
1256 vec
1257 }
1258
1259 pub fn multi_field_item(&mut self, name: &str, itype: Item) {
1261 for Field(key, cmp, bv) in self.block.iter_fields() {
1262 if key.is(name) {
1263 self.known_fields.push(key.as_str());
1264 self.expect_eq_qeq(key, *cmp);
1265 if let Some(token) = bv.expect_value() {
1266 self.data.verify_exists_max_sev(itype, token, self.max_severity);
1267 }
1268 }
1269 }
1270 }
1271
1272 pub fn multi_field_any_cmp(&mut self, name: &str) -> bool {
1274 let mut found = false;
1275 for Field(key, _, _) in self.block.iter_fields() {
1276 if key.is(name) {
1277 self.known_fields.push(key.as_str());
1278 found = true;
1279 }
1280 }
1281 found
1282 }
1283
1284 #[allow(dead_code)]
1286 pub fn multi_field_validated_any_cmp<F>(&mut self, name: &str, mut f: F) -> bool
1287 where
1288 F: FnMut(&BV, &Everything),
1289 {
1290 let mut found = false;
1291 for Field(key, _, bv) in self.block.iter_fields() {
1292 if key.is(name) {
1293 self.known_fields.push(key.as_str());
1294 f(bv, self.data);
1295 found = true;
1296 }
1297 }
1298 found
1299 }
1300
1301 pub fn field_validated<F>(&mut self, name: &str, mut f: F) -> bool
1306 where
1307 F: FnMut(&BV, &Everything),
1308 {
1309 let mut found = None;
1310 for Field(key, cmp, bv) in self.block.iter_fields() {
1311 if key.is(name) {
1312 self.known_fields.push(key.as_str());
1313 self.expect_eq_qeq(key, *cmp);
1314 if let Some(other) = found {
1315 dup_assign_error(key, other, AllowInject::No);
1316 }
1317 f(bv, self.data);
1318 found = Some(key);
1319 }
1320 }
1321 found.is_some()
1322 }
1323
1324 pub fn field_validated_key<F>(&mut self, name: &str, mut f: F) -> bool
1326 where
1327 F: FnMut(&Token, &BV, &Everything),
1328 {
1329 let mut found = None;
1330 for Field(key, cmp, bv) in self.block.iter_fields() {
1331 if key.is(name) {
1332 self.known_fields.push(key.as_str());
1333 self.expect_eq_qeq(key, *cmp);
1334 if let Some(other) = found {
1335 dup_assign_error(key, other, AllowInject::No);
1336 }
1337 f(key, bv, self.data);
1338 found = Some(key);
1339 }
1340 }
1341 found.is_some()
1342 }
1343
1344 pub fn field_validated_sc<F>(&mut self, name: &str, sc: &mut ScopeContext, mut f: F) -> bool
1349 where
1350 F: FnMut(&BV, &Everything, &mut ScopeContext),
1351 {
1352 self.field_validated(name, |bv, data| f(bv, data, sc))
1353 }
1354
1355 #[cfg(feature = "ck3")] pub fn field_validated_rooted<F>(&mut self, name: &str, scopes: Scopes, f: F) -> bool
1361 where
1362 F: FnMut(&BV, &Everything, &mut ScopeContext),
1363 {
1364 self.field_validated_build_sc(name, |key| ScopeContext::new(scopes, key), f)
1365 }
1366
1367 #[cfg(feature = "ck3")]
1368 pub fn field_validated_build_sc<B, F>(&mut self, name: &str, mut b: B, mut f: F) -> bool
1369 where
1370 B: FnMut(&Token) -> ScopeContext,
1371 F: FnMut(&BV, &Everything, &mut ScopeContext),
1372 {
1373 self.field_validated_key(name, |key, bv, data| {
1374 let mut sc = b(key);
1375 f(bv, data, &mut sc);
1376 })
1377 }
1378
1379 pub fn multi_field_validated<F>(&mut self, name: &str, mut f: F) -> bool
1381 where
1382 F: FnMut(&BV, &Everything),
1383 {
1384 let mut found = false;
1385 for Field(key, cmp, bv) in self.block.iter_fields() {
1386 if key.is(name) {
1387 self.known_fields.push(key.as_str());
1388 self.expect_eq_qeq(key, *cmp);
1389 f(bv, self.data);
1390 found = true;
1391 }
1392 }
1393 found
1394 }
1395
1396 #[cfg(any(feature = "ck3", feature = "eu5"))] pub fn multi_field_validated_key<F>(&mut self, name: &str, mut f: F) -> bool
1399 where
1400 F: FnMut(&Token, &BV, &Everything),
1401 {
1402 let mut found = false;
1403 for Field(key, cmp, bv) in self.block.iter_fields() {
1404 if key.is(name) {
1405 self.known_fields.push(key.as_str());
1406 self.expect_eq_qeq(key, *cmp);
1407 f(key, bv, self.data);
1408 found = true;
1409 }
1410 }
1411 found
1412 }
1413
1414 #[allow(dead_code)]
1416 pub fn multi_field_validated_sc<F>(
1417 &mut self,
1418 name: &str,
1419 sc: &mut ScopeContext,
1420 mut f: F,
1421 ) -> bool
1422 where
1423 F: FnMut(&BV, &Everything, &mut ScopeContext),
1424 {
1425 self.multi_field_validated(name, |b, data| f(b, data, sc))
1426 }
1427
1428 pub fn multi_field_validated_block<F>(&mut self, name: &str, mut f: F) -> bool
1430 where
1431 F: FnMut(&Block, &Everything),
1432 {
1433 let mut found = false;
1434 for Field(key, cmp, bv) in self.block.iter_fields() {
1435 if (self.case_sensitive && key.is(name))
1436 || (!self.case_sensitive && key.lowercase_is(name))
1437 {
1438 self.known_fields.push(key.as_str());
1439 self.expect_eq_qeq(key, *cmp);
1440 if let Some(block) = bv.expect_block() {
1441 f(block, self.data);
1442 }
1443 found = true;
1444 }
1445 }
1446 found
1447 }
1448
1449 #[allow(dead_code)]
1451 pub fn multi_field_validated_block_sc<F>(
1452 &mut self,
1453 name: &str,
1454 sc: &mut ScopeContext,
1455 mut f: F,
1456 ) -> bool
1457 where
1458 F: FnMut(&Block, &Everything, &mut ScopeContext),
1459 {
1460 self.multi_field_validated_block(name, |b, data| f(b, data, sc))
1461 }
1462
1463 pub fn field_validated_block<F>(&mut self, name: &str, mut f: F) -> bool
1468 where
1469 F: FnMut(&Block, &Everything),
1470 {
1471 let mut found = None;
1472 for Field(key, cmp, bv) in self.block.iter_fields() {
1473 if (self.case_sensitive && key.is(name))
1474 || (!self.case_sensitive && key.lowercase_is(name))
1475 {
1476 self.known_fields.push(key.as_str());
1477 if let Some(other) = found {
1478 dup_assign_error(key, other, AllowInject::No);
1479 }
1480 self.expect_eq_qeq(key, *cmp);
1481 if let Some(block) = bv.expect_block() {
1482 f(block, self.data);
1483 }
1484 found = Some(key);
1485 }
1486 }
1487 found.is_some()
1488 }
1489
1490 #[cfg(feature = "vic3")]
1493 pub fn multi_warn_field_validated_block<F>(&mut self, name: &str, mut f: F) -> bool
1494 where
1495 F: FnMut(&Block, &Everything),
1496 {
1497 let mut found: Option<&Token> = None;
1498 for Field(key, cmp, bv) in self.block.iter_fields() {
1499 if (self.case_sensitive && key.is(name))
1500 || (!self.case_sensitive && key.lowercase_is(name))
1501 {
1502 self.known_fields.push(key.as_str());
1503 if let Some(other) = found {
1504 dup_assign_error(key, other, AllowInject::Yes);
1505 }
1506 self.expect_eq_qeq(key, *cmp);
1507 if let Some(block) = bv.expect_block() {
1508 f(block, self.data);
1509 }
1510 found = Some(key);
1511 }
1512 }
1513 found.is_some()
1514 }
1515
1516 pub fn field_validated_key_block<F>(&mut self, name: &str, mut f: F) -> bool
1518 where
1519 F: FnMut(&Token, &Block, &Everything),
1520 {
1521 let mut found = None;
1522 for Field(key, cmp, bv) in self.block.iter_fields() {
1523 if (self.case_sensitive && key.is(name))
1524 || (!self.case_sensitive && key.lowercase_is(name))
1525 {
1526 self.known_fields.push(key.as_str());
1527 if let Some(other) = found {
1528 dup_assign_error(key, other, AllowInject::No);
1529 }
1530 self.expect_eq_qeq(key, *cmp);
1531 if let Some(block) = bv.expect_block() {
1532 f(key, block, self.data);
1533 }
1534 found = Some(key);
1535 }
1536 }
1537 found.is_some()
1538 }
1539
1540 #[allow(dead_code)]
1541 pub fn field_validated_block_build_sc<B, F>(&mut self, name: &str, mut b: B, mut f: F) -> bool
1542 where
1543 B: FnMut(&Token) -> ScopeContext,
1544 F: FnMut(&Block, &Everything, &mut ScopeContext),
1545 {
1546 let mut found = None;
1547 for Field(key, cmp, bv) in self.block.iter_fields() {
1548 if (self.case_sensitive && key.is(name))
1549 || (!self.case_sensitive && key.lowercase_is(name))
1550 {
1551 self.known_fields.push(key.as_str());
1552 if let Some(other) = found {
1553 dup_assign_error(key, other, AllowInject::No);
1554 }
1555 self.expect_eq_qeq(key, *cmp);
1556 if let Some(block) = bv.expect_block() {
1557 let mut sc = b(key);
1558 f(block, self.data, &mut sc);
1559 }
1560 found = Some(key);
1561 }
1562 }
1563 found.is_some()
1564 }
1565
1566 pub fn multi_field_validated_key_block<F>(&mut self, name: &str, mut f: F) -> bool
1568 where
1569 F: FnMut(&Token, &Block, &Everything),
1570 {
1571 let mut found = false;
1572 for Field(key, cmp, bv) in self.block.iter_fields() {
1573 if (self.case_sensitive && key.is(name))
1574 || (!self.case_sensitive && key.lowercase_is(name))
1575 {
1576 self.known_fields.push(key.as_str());
1577 self.expect_eq_qeq(key, *cmp);
1578 if let Some(block) = bv.expect_block() {
1579 f(key, block, self.data);
1580 }
1581 found = true;
1582 }
1583 }
1584 found
1585 }
1586
1587 pub fn field_validated_block_sc<F>(
1589 &mut self,
1590 name: &str,
1591 sc: &mut ScopeContext,
1592 mut f: F,
1593 ) -> bool
1594 where
1595 F: FnMut(&Block, &Everything, &mut ScopeContext),
1596 {
1597 self.field_validated_block(name, |b, data| f(b, data, sc))
1598 }
1599
1600 #[allow(dead_code)]
1605 pub fn field_validated_block_rooted<F>(&mut self, name: &str, scopes: Scopes, f: F) -> bool
1606 where
1607 F: FnMut(&Block, &Everything, &mut ScopeContext),
1608 {
1609 self.field_validated_block_build_sc(name, |key| ScopeContext::new(scopes, key), f)
1610 }
1611
1612 #[cfg(feature = "ck3")] pub fn multi_field_validated_block_rooted<F>(&mut self, name: &str, scopes: Scopes, mut f: F)
1615 where
1616 F: FnMut(&Block, &Everything, &mut ScopeContext),
1617 {
1618 for Field(key, cmp, bv) in self.block.iter_fields() {
1619 if (self.case_sensitive && key.is(name))
1620 || (!self.case_sensitive && key.lowercase_is(name))
1621 {
1622 self.known_fields.push(key.as_str());
1623 self.expect_eq_qeq(key, *cmp);
1624 if let Some(block) = bv.expect_block() {
1625 let mut sc = ScopeContext::new(scopes, key);
1626 f(block, self.data, &mut sc);
1627 }
1628 }
1629 }
1630 }
1631
1632 #[cfg(feature = "ck3")] pub fn field_validated_block_rerooted<F>(
1638 &mut self,
1639 name: &str,
1640 sc: &ScopeContext,
1641 scopes: Scopes,
1642 mut f: F,
1643 ) -> bool
1644 where
1645 F: FnMut(&Block, &Everything, &mut ScopeContext),
1646 {
1647 let mut found = None;
1648 for Field(key, cmp, bv) in self.block.iter_fields() {
1649 if (self.case_sensitive && key.is(name))
1650 || (!self.case_sensitive && key.lowercase_is(name))
1651 {
1652 self.known_fields.push(key.as_str());
1653 if let Some(other) = found {
1654 dup_assign_error(key, other, AllowInject::No);
1655 }
1656 self.expect_eq_qeq(key, *cmp);
1657 if let Some(block) = bv.expect_block() {
1658 let mut sc = sc.clone();
1659 sc.change_root(scopes, key);
1660 f(block, self.data, &mut sc);
1661 }
1662 found = Some(key);
1663 }
1664 }
1665 found.is_some()
1666 }
1667
1668 #[cfg(feature = "ck3")] pub fn multi_field_block(&mut self, name: &str) -> bool {
1671 let mut found = false;
1672 for Field(key, cmp, bv) in self.block.iter_fields() {
1673 if (self.case_sensitive && key.is(name))
1674 || (!self.case_sensitive && key.lowercase_is(name))
1675 {
1676 self.known_fields.push(key.as_str());
1677 self.expect_eq_qeq(key, *cmp);
1678 bv.expect_block();
1679 found = true;
1680 }
1681 }
1682 found
1683 }
1684
1685 pub fn req_tokens_integers_exactly(&mut self, expect: usize) {
1688 self.accepted_tokens = true;
1689 let mut found = 0;
1690 for token in self.block.iter_values() {
1691 if token.expect_integer().is_some() {
1692 found += 1;
1693 }
1694 }
1695 if found != expect {
1696 let msg = format!("expected {expect} integers");
1697 let sev = Severity::Error.at_most(self.max_severity);
1698 report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
1699 }
1700 }
1701
1702 pub fn req_tokens_numbers_exactly(&mut self, expect: usize) {
1705 self.accepted_tokens = true;
1706 let mut found = 0;
1707 for token in self.block.iter_values() {
1708 if token.expect_number().is_some() {
1709 found += 1;
1710 }
1711 }
1712 if found != expect {
1713 let msg = format!("expected {expect} numbers");
1714 let sev = Severity::Error.at_most(self.max_severity);
1715 report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
1716 }
1717 }
1718
1719 pub fn field_list_numeric_exactly(&mut self, name: &str, expect: usize) {
1723 self.field_validated_block(name, |block, data| {
1724 let mut vd = Validator::new(block, data);
1725 vd.req_tokens_numbers_exactly(expect);
1726 });
1727 }
1728
1729 #[allow(dead_code)]
1731 pub fn req_tokens_precise_numbers_exactly(&mut self, expect: usize) {
1732 self.accepted_tokens = true;
1733 let mut found = 0;
1734 for token in self.block.iter_values() {
1735 if token.expect_precise_number().is_some() {
1736 found += 1;
1737 }
1738 }
1739 if found != expect {
1740 let msg = format!("expected {expect} numbers");
1741 let sev = Severity::Error.at_most(self.max_severity);
1742 report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
1743 }
1744 }
1745
1746 #[allow(dead_code)]
1748 pub fn field_list_precise_numeric_exactly(&mut self, name: &str, expect: usize) {
1749 self.field_validated_block(name, |block, data| {
1750 let mut vd = Validator::new(block, data);
1751 vd.req_tokens_precise_numbers_exactly(expect);
1752 });
1753 }
1754
1755 pub fn field_list_integers_exactly(&mut self, name: &str, expect: usize) {
1757 self.field_validated_block(name, |block, data| {
1758 let mut vd = Validator::new(block, data);
1759 vd.req_tokens_integers_exactly(expect);
1760 });
1761 }
1762
1763 #[allow(dead_code)]
1766 pub fn advice_field(&mut self, name: &str, msg: &str) {
1767 if let Some(key) = self.block.get_key(name) {
1768 self.known_fields.push(key.as_str());
1769 let sev = Severity::Untidy.at_most(self.max_severity);
1770 report(ErrorKey::Unneeded, sev).msg(msg).loc(key).push();
1771 }
1772 }
1773
1774 pub fn values(&mut self) -> Vec<&Token> {
1778 self.accepted_tokens = true;
1779 self.block.iter_values().collect()
1780 }
1781
1782 #[allow(dead_code)]
1786 pub fn blocks(&mut self) -> Vec<&Block> {
1787 self.accepted_blocks = true;
1788 self.block.iter_blocks().collect()
1789 }
1790
1791 #[cfg(any(feature = "vic3", feature = "imperator"))] pub fn validated_blocks<F>(&mut self, mut f: F)
1795 where
1796 F: FnMut(&Block, &Everything),
1797 {
1798 self.accepted_blocks = true;
1799 for block in self.block.iter_blocks() {
1800 f(block, self.data);
1801 }
1802 }
1803
1804 pub fn integer_blocks(&mut self) -> Vec<(&Token, &Block)> {
1808 let mut vec = Vec::new();
1809 for Field(key, cmp, bv) in self.block.iter_fields() {
1810 if key.is_integer() {
1811 self.known_fields.push(key.as_str());
1812 self.expect_eq_qeq(key, *cmp);
1813 if let Some(block) = bv.expect_block() {
1814 vec.push((key, block));
1815 }
1816 }
1817 }
1818 vec
1819 }
1820
1821 pub fn integer_values(&mut self) -> Vec<(&Token, &Token)> {
1825 let mut vec = Vec::new();
1826 for Field(key, cmp, bv) in self.block.iter_fields() {
1827 if key.is_integer() {
1828 self.known_fields.push(key.as_str());
1829 self.expect_eq_qeq(key, *cmp);
1830 if let Some(token) = bv.expect_value() {
1831 vec.push((key, token));
1832 }
1833 }
1834 }
1835 vec
1836 }
1837
1838 #[allow(dead_code)]
1840 pub fn integer_keys<F: FnMut(&Token, &BV)>(&mut self, mut f: F) {
1841 for Field(key, cmp, bv) in self.block.iter_fields() {
1842 if key.is_integer() {
1843 self.known_fields.push(key.as_str());
1844 self.expect_eq_qeq(key, *cmp);
1845 f(key, bv);
1846 }
1847 }
1848 }
1849
1850 #[cfg(feature = "vic3")] pub fn numeric_keys<F: FnMut(&Token, &BV)>(&mut self, mut f: F) {
1855 for Field(key, cmp, bv) in self.block.iter_fields() {
1856 if key.is_number() {
1857 self.known_fields.push(key.as_str());
1858 self.expect_eq_qeq(key, *cmp);
1859 f(key, bv);
1860 }
1861 }
1862 }
1863
1864 #[cfg(any(feature = "ck3", feature = "hoi4"))]
1867 pub fn validate_history_blocks<F>(&mut self, mut f: F)
1868 where
1869 F: FnMut(Date, &Token, &Block, &Everything),
1870 {
1871 for Field(key, cmp, bv) in self.block.iter_fields() {
1872 if let Ok(date) = Date::try_from(key) {
1873 key.expect_date(); self.known_fields.push(key.as_str());
1875 self.expect_eq_qeq(key, *cmp);
1876 if let Some(block) = bv.expect_block() {
1877 f(date, key, block, self.data);
1878 }
1879 }
1880 }
1881 }
1882
1883 #[allow(dead_code)]
1887 pub fn validate_item_key_fields<F>(&mut self, itype: Item, mut f: F)
1888 where
1889 F: FnMut(&Token, &BV, &Everything),
1890 {
1891 let mut visited_fields = TigerHashSet::default();
1892 for Field(key, _, bv) in self.block.iter_fields() {
1893 if !self.known_fields.contains(&key.as_str()) {
1894 self.data.verify_exists(itype, key);
1895
1896 match visited_fields.get(key.as_str()) {
1897 Some(&duplicate) => dup_assign_error(key, duplicate, AllowInject::No),
1898 None => {
1899 visited_fields.insert(key);
1900 }
1901 }
1902
1903 self.known_fields.push(key.as_str());
1904
1905 f(key, bv, self.data);
1906 }
1907 }
1908 }
1909
1910 #[allow(dead_code)]
1914 pub fn validate_item_key_values<F>(&mut self, itype: Item, mut f: F)
1915 where
1916 F: FnMut(&Token, ValueValidator),
1917 {
1918 let sev = self.max_severity;
1919 self.validate_item_key_fields(itype, |key, bv, data| {
1920 if let Some(value) = bv.expect_value() {
1921 let mut vd = ValueValidator::new(value, data);
1922 vd.set_max_severity(sev);
1923 f(key, vd);
1924 }
1925 });
1926 }
1927
1928 #[allow(dead_code)]
1932 pub fn validate_item_key_blocks<F>(&mut self, itype: Item, mut f: F)
1933 where
1934 F: FnMut(&Token, &Block, &Everything),
1935 {
1936 self.validate_item_key_fields(itype, |key, bv, data| {
1937 if let Some(block) = bv.expect_block() {
1938 f(key, block, data);
1939 }
1940 });
1941 }
1942
1943 pub fn unknown_fields<F: FnMut(&Token, &BV)>(&mut self, mut f: F) {
1947 self.accepted_block_fields = true;
1948 self.accepted_value_fields = true;
1949 for Field(key, cmp, bv) in self.block.iter_fields() {
1950 self.expect_eq_qeq(key, *cmp);
1951 if !self.known_fields.contains(&key.as_str()) {
1952 f(key, bv);
1953 }
1954 }
1955 }
1956
1957 pub fn unknown_block_fields<F: FnMut(&Token, &Block)>(&mut self, mut f: F) {
1960 self.accepted_block_fields = true;
1961 for Field(key, cmp, bv) in self.block.iter_fields() {
1962 if let Some(block) = bv.get_block() {
1963 self.expect_eq_qeq(key, *cmp);
1964 if !self.known_fields.contains(&key.as_str()) {
1965 f(key, block);
1966 }
1967 }
1968 }
1969 }
1970
1971 pub fn unknown_value_fields<F: FnMut(&Token, &Token)>(&mut self, mut f: F) {
1974 self.accepted_value_fields = true;
1975 for Field(key, cmp, bv) in self.block.iter_fields() {
1976 if let Some(value) = bv.get_value() {
1977 self.expect_eq_qeq(key, *cmp);
1978 if !self.known_fields.contains(&key.as_str()) {
1979 f(key, value);
1980 }
1981 }
1982 }
1983 }
1984
1985 pub fn unknown_fields_cmp<F: FnMut(&Token, Comparator, &BV)>(&mut self, mut f: F) {
1988 self.accepted_block_fields = true;
1989 self.accepted_value_fields = true;
1990 for Field(key, cmp, bv) in self.block.iter_fields() {
1991 if !self.known_fields.contains(&key.as_str()) {
1992 self.expect_eq_qeq(key, *cmp);
1993 f(key, *cmp, bv);
1994 }
1995 }
1996 }
1997
1998 pub fn unknown_fields_any_cmp<F: FnMut(&Token, Comparator, &BV)>(&mut self, mut f: F) {
2000 self.accepted_block_fields = true;
2001 self.accepted_value_fields = true;
2002 for Field(key, cmp, bv) in self.block.iter_fields() {
2003 if !self.known_fields.contains(&key.as_str()) {
2004 f(key, *cmp, bv);
2005 }
2006 }
2007 }
2008
2009 pub fn no_warn_remaining(&mut self) {
2012 self.accepted_block_fields = true;
2013 self.accepted_value_fields = true;
2014 self.accepted_tokens = true;
2015 self.accepted_blocks = true;
2016 }
2017
2018 pub fn warn_remaining(&mut self) -> bool {
2022 let mut warned = false;
2023 for item in self.block.iter_items() {
2024 match item {
2025 BlockItem::Field(Field(key, _, bv)) => match bv {
2026 BV::Value(_) => {
2027 if !self.accepted_value_fields && !self.known_fields.contains(&key.as_str())
2028 {
2029 let msg = format!("unknown field `{key}`");
2030 let sev = Severity::Error.at_most(self.max_severity);
2031 report(ErrorKey::UnknownField, sev).weak().msg(msg).loc(key).push();
2032 warned = true;
2033 }
2034 }
2035 BV::Block(_) => {
2036 if !self.accepted_block_fields && !self.known_fields.contains(&key.as_str())
2037 {
2038 let msg = format!("unknown field `{key}`");
2039 let sev = Severity::Error.at_most(self.max_severity);
2040 report(ErrorKey::UnknownField, sev).weak().msg(msg).loc(key).push();
2041 warned = true;
2042 }
2043 }
2044 },
2045 BlockItem::Value(t) => {
2046 if !self.accepted_tokens {
2047 let msg = format!("found loose value {t}, expected only `key =`");
2048 let sev = Severity::Error.at_most(self.max_severity);
2049 report(ErrorKey::Structure, sev).msg(msg).loc(t).push();
2050 warned = true;
2051 }
2052 }
2053 BlockItem::Block(b) => {
2054 if !self.accepted_blocks {
2055 let msg = "found sub-block, expected only `key =`";
2056 let sev = Severity::Error.at_most(self.max_severity);
2057 report(ErrorKey::Structure, sev).msg(msg).loc(b).push();
2058 warned = true;
2059 }
2060 }
2061 }
2062 }
2063 self.no_warn_remaining();
2064 warned
2065 }
2066
2067 fn expect_eq_qeq(&self, key: &Token, cmp: Comparator) {
2068 #[allow(clippy::collapsible_else_if)]
2069 if self.allow_questionmark_equals {
2070 if !matches!(cmp, Comparator::Equals(Single | Question)) {
2071 let msg = format!("expected `{key} =` or `?=`, found `{cmp}`");
2072 let sev = Severity::Error.at_most(self.max_severity);
2073 report(ErrorKey::Validation, sev).msg(msg).loc(key).push();
2074 }
2075 } else {
2076 if !matches!(cmp, Comparator::Equals(Single)) {
2077 let msg = format!("expected `{key} =`, found `{cmp}`");
2078 let sev = Severity::Error.at_most(self.max_severity);
2079 report(ErrorKey::Validation, sev).msg(msg).loc(key).push();
2080 }
2081 }
2082 }
2083}
2084
2085impl Drop for Validator<'_> {
2086 fn drop(&mut self) {
2087 self.warn_remaining();
2088 }
2089}