Skip to main content

tiger_lib/
validator.rs

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
32/// A validator for one `Block`.
33/// The intended usage is that you wrap the `Block` in a validator, then call validation functions on it
34/// until you've validated all the possible legitimate contents of the `Block`, and then the `Validator`
35/// will warn the user about anything left over when it goes out of scope. This way you don't have to worry
36/// about checking for unknown fields yourself.
37///
38/// The validator is mostly for checking "fields" (`key = value` and `key = { block }` items in the block),
39/// but it can validate loose blocks and loose values and comparisons as well.
40pub struct Validator<'a> {
41    /// The block being validated
42    block: &'a Block,
43    /// A link to all the loaded and processed CK3 and mod files
44    data: &'a Everything,
45    /// Fields that have been requested so far
46    known_fields: Vec<&'a str>,
47    /// Whether loose tokens are expected
48    accepted_tokens: bool,
49    /// Whether subblocks are expected
50    accepted_blocks: bool,
51    /// Whether unknown block fields are expected
52    accepted_block_fields: bool,
53    /// Whether unknown value fields are expected
54    accepted_value_fields: bool,
55    /// Whether key comparisons should be done case-sensitively
56    case_sensitive: bool,
57    /// Whether this block can have ?= operators
58    allow_questionmark_equals: bool,
59    /// Maximum severity of problems reported by this `Validator`. Defaults to `Error`.
60    /// This is intended to be set lower by validators for less-important items.
61    /// As an exception, `Fatal` severity reports will still always be logged as `Fatal`.
62    /// TODO: pass this down to all the helper functions
63    max_severity: Severity,
64}
65
66impl Debug for Validator<'_> {
67    /// Roll our own `Debug` implementation in order to leave out the `data` field.
68    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    /// Construct a new `Validator` for a [`Block`]. The `data` reference is there to help out some of the convenience
85    /// functions, and also to pass along to closures so that you can easily pass independent functions as the closures.
86    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    /// Control whether the fields in this `Block` will be matched case-sensitively or not.
102    /// Whether this should be on or off depends on what the game engine allows, which is not always known.
103    pub fn set_case_sensitive(&mut self, cs: bool) {
104        self.case_sensitive = cs;
105    }
106
107    /// Whether this block can contain `?=` as well as `=` for assignments and definitions.
108    /// Blocks that allow `?=` are mostly specialized ones such as triggers and effects.
109    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    /// Require field `name` to be present in the block, and warn if it isn't there.
121    /// Returns true iff the field is present.
122    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    /// Require exactly one of the fields in `names` to be present in the block,
133    /// and warn if they are missing or there is more than one.
134    /// Returns true iff it found exactly one.
135    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    /// Require no more than one of the fields in `names` to be present in the block.
152    /// Returns true iff it found exactly one.
153    #[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    /// Require field `name` to be present in the block, and warn if it isn't there.
170    /// Returns true iff the field is present. Warns at a lower severity than `req_field`.
171    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    /// Require field `name` to be present in the block, and warn if it isn't there.
182    /// Returns true iff the field is present. Warns at [`Severity::Fatal`] level.
183    #[cfg(feature = "ck3")] // vic3 happens not to use; silence dead code warning
184    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    /// Require field `name` to not be in the block, and warn if it is found.
194    /// The warning will include the output from the `only_for` closure,
195    /// which describes where the field *is* expected.
196    /// TODO: make lower-severity versions of this function.
197    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    /// Require field `name` to not be in the block. If it is found, warn that it has been replaced by `replaced_by`.
210    /// This is used to adapt to and warn about changes in the game engine.
211    #[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    /// Expect field `name`, if present, to be either an assignment (`= value`) or a definition (`= { block }`).
272    /// Expect no more than one `name` field in the block.
273    /// Returns true iff the field is present.
274    pub fn field(&mut self, name: &str) -> bool {
275        self.field_check(name, AllowInject::No, |_, _| ())
276    }
277
278    /// Just like [`Validator::field`], but expects any number of `name` fields in the block.
279    pub fn multi_field(&mut self, name: &str) -> bool {
280        self.multi_field_check(name, |_, _| ())
281    }
282
283    /// Expect field `name`, if present, to be... present.
284    /// Expect no more than one `name` field in the block.
285    /// Returns the field's `BV` (block or value) if the field is present.
286    /// TODO: replace this with a `field_validated` variant.
287    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    /// Expect field `name`, if present, to be an assignment (`name = value`).
304    /// Expect no more than one `name` field in the block.
305    /// Returns the field's value if the field is present.
306    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    /// Expect field `name`, if present, to be set to a single word.
328    /// Expect no more than one `name` field in the block.
329    /// `kind` is the kind of identifier expected here (for display to the user).
330    /// Returns the field's value if the field is present.
331    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    /// Expect field `name`, if present, to be set to a single word or a flag target.
354    /// Expect no more than one `name` field in the block.
355    /// `kind` is the kind of identifier expected here (for display to the user).
356    /// Returns the field's value if the field is present.
357    #[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                    // NOTE: this check should mirror the one in validate_identifier
376                    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    /// Expect field `name`, if present, to be an assignment (`name = value`).
388    /// Expect no more than one `name` field in the block.
389    /// Runs the validation closure `f(key, vd)` for every matching field.
390    /// Returns true iff the field is present.
391    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    /// Just like [`Validator::field_validated_value`], but expect any number of `name` fields in the block.
406    #[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    /// Expect field `name`, if present, to be set to the key of an `itype` item the game database.
422    /// The item is looked up and must exist.
423    /// Expect no more than one `name` field in the block.
424    /// Returns true iff the field is present.
425    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    /// Expect field `name`, if present, to be a variable reference.
435    /// Expect no more than one `name` field in the block.
436    /// Returns true iff the field is present.
437    #[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    /// Expect field `name`, if present, to be a variable reference or an integer.
448    /// Expect no more than one `name` field in the block.
449    /// Returns true iff the field is present.
450    #[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    /// Expect field `name`, if present, to be set to the key of an `on_action`.
464    /// The action is looked up and must exist.
465    /// If it would be useful, validate the action with the given `ScopeContext`.
466    /// Expect no more than one `name` field in the block.
467    /// Returns true iff the field is present.
468    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    /// Expect field `name`, if present, to be set to an event id.
482    /// The event is looked up and must exist.
483    /// If it would be useful, validate the event with the given `ScopeContext`.
484    /// Expect no more than one `name` field in the block.
485    /// Returns true iff the field is present.
486    #[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    /// Expect field `name`, if present, to be set to the key of an `itype` item the game database,
501    /// or be the empty string.
502    /// The item is looked up and must exist.
503    /// Expect no more than one `name` field in the block.
504    /// Returns true iff the field is present.
505    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    /// Expect field `name`, if present, to be a localization key.
517    /// The key is looked up and must exist.
518    /// The key's localization entry is validated using the given `ScopeContext`.
519    ///
520    /// Expect no more than one `name` field in the block.
521    /// Returns true iff the field is present.
522    #[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    /// Expect field `name`, if present, to be an assignment where the value evaluates to a scope type in `outscopes`.
534    ///
535    /// The value is evaluated in the scope context `sc`, so for example if the value does `scope:actor` but there is
536    /// no named scope "actor" in the scope context, then a warning is emitted.
537    /// Also emits a warning if the value is simply "`this`", because that is almost never correct.
538    ///
539    /// Expect no more than one `name` field in the block.
540    /// Returns true iff the field is present.
541    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                // TODO: pass max_severity here
545                validate_target(token, self.data, sc, outscopes);
546            }
547        })
548    }
549
550    /// Returns true iff the field is present.
551    /// Just like [`Validator::field_target`], but allows multiple fields.
552    #[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                // TODO: pass max_severity here
562                validate_target(token, self.data, sc, outscopes);
563            }
564        })
565    }
566
567    /// Just like [`Validator::field_target`], but allows the value to be simply "`this`".
568    /// It is expected to be used judiciously in cases where "`this`" can be correct.
569    #[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                // TODO: pass max_severity here
579                validate_target_ok_this(token, self.data, sc, outscopes);
580            }
581        })
582    }
583
584    /// This is a combination of [`Validator::field_item`] and [`Validator::field_target`]. If the field is present
585    /// and is not a known `itype` item, then it is evaluated as a target.
586    /// Returns true iff the field is present.
587    #[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                // TODO: pass max_severity here
600                validate_target(token, self.data, sc, outscopes);
601            }
602        })
603    }
604
605    /// This is a combination of [`Validator::field_item`] and [`Validator::field_target_ok_this`].
606    /// If the field is present and is not a known `itype` item, then it is evaluated as a target.
607    /// Returns true iff the field is present.
608    #[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                // TODO: pass max_severity here
621                validate_target_ok_this(token, self.data, sc, outscopes);
622            }
623        })
624    }
625
626    /// Expect field `name`, if present, to be a definition `name = { block }`.
627    /// Expect no more than one `name` field.
628    /// No other validation is done.
629    /// Returns true iff the field is present.
630    pub fn field_block(&mut self, name: &str) -> bool {
631        self.field_check(name, AllowInject::No, |_, bv| _ = bv.expect_block())
632    }
633
634    /// Expect field `name`, if present, to be `name = yes` or `name = no`.
635    /// Expect no more than one `name` field.
636    /// Returns true iff the field is present.
637    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    /// Expect field `name`, if present, to be set to an integer.
652    /// Expect no more than one `name` field.
653    /// Returns true iff the field is present.
654    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                // TODO: pass max_severity here
658                token.expect_integer();
659            }
660        })
661    }
662
663    /// Expect field `name`, if present, to be set to an integer within the `range` provided.
664    /// Expect no more than one `name` field.
665    /// Returns true iff the field is present.
666    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                // TODO: pass max_severity here
671                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!(); // could not have failed the contains check
693                    }
694                    report(ErrorKey::Range, sev).msg(msg).loc(token).push();
695                }
696            }
697        });
698    }
699
700    /// Expect field `name`, if present, to be set to a number with up to 5 decimals.
701    /// (5 decimals is the limit accepted by the game engine in most contexts).
702    /// Expect no more than one `name` field.
703    /// Returns true iff the field is present.
704    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    /// Expect field `name`, if present, to be set to a number with up to 5 decimals.
713    /// (5 decimals is the limit accepted by the game engine in most contexts).
714    /// Expect any number of `name` fields.
715    /// Returns true iff the field is present.
716    #[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    /// Expect field `name`, if present, to be set to a number with any number of decimals.
726    /// Expect no more than one `name` field.
727    /// Returns true iff the field is present.
728    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!(); // could not have failed the contains check
770                    }
771                    report(ErrorKey::Range, sev).msg(msg).loc(token).push();
772                }
773            }
774        });
775    }
776
777    /// Expect field `name`, if present, to be set to a number within the `range` provided.
778    /// Accept at most 5 decimals. (5 decimals is the limit accepted by the game engine in most contexts).
779    /// Expect no more than one `name` field.
780    #[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    /// Expect field `name`, if present, to be set to a number within the `range` provided.
786    /// Expect no more than one `name` field.
787    #[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    /// Expect field `name`, if present, to be set to a date.
793    /// The format of dates is very flexible, from a single number (the year), to a year.month or year.month.day.
794    /// No checking is done on the validity of the date as a date (so January 42nd is okay).
795    /// Expect no more than one `name` field.
796    /// Returns true iff the field is present.
797    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    /// Expect field `name`, if present, to introduce a trigger block.
810    ///
811    /// Expect no more than one `name` field in the block.
812    /// Returns true iff the field is present.
813    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    /// Expect field `name`, if present, to introduce a trigger block.
837    /// Its `ScopeContext` will be constructed from the field key, with the given `Scopes` as root.
838    ///
839    /// Expect no more than one `name` field in the block.
840    /// Returns true iff the field is present.
841    #[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    /// Expect field `name`, if present, to introduce a trigger block.
867    /// Its `ScopeContext` will be created by calling the provided closure with the field's key.
868    ///
869    /// Expect no more than one `name` field in the block.
870    /// Returns true iff the field is present.
871    #[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    /// Expect field `name`, if present, to introduce an effect block.
900    ///
901    /// Expect no more than one `name` field in the block.
902    /// Returns true iff the field is present.
903    #[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    /// Expect field `name`, if present, to introduce an effect block.
928    /// Its `ScopeContext` will be constructed from the field key, with the given `Scopes` as root.
929    ///
930    /// Expect no more than one `name` field in the block.
931    /// Returns true iff the field is present.
932    #[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    /// Expect field `name`, if present, to introduce an effect block.
958    /// Its `ScopeContext` will be created by calling the provided closure with the field's key.
959    ///
960    /// Expect no more than one `name` field in the block.
961    /// Returns true iff the field is present.
962    #[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    /// Expect field `name`, if present, to be set to a script value, either a named one (simply `name = scriptvaluename`)
991    /// or an inline one (can be a simple number, or a range `{ min max }`, or a full script value definition with limits
992    /// and math).
993    ///
994    /// The script value is evaluated in the scope context `sc`, so for example if the script value does `scope:actor` but
995    /// there is no named scope "actor" in the scope context, then a warning is emitted.
996    ///
997    /// Expect no more than one `name` field in the block.
998    /// Returns true iff the field is present.
999    #[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            // TODO: pass max_severity value down
1003            validate_script_value(bv, self.data, sc);
1004        })
1005    }
1006
1007    /// Just like [`Validator::field_script_value`], but does not warn if it is an inline script value and the `desc` fields
1008    /// in it do not contain valid localizations. This is generally used for script values that will never be shown to
1009    /// the user except in debugging contexts, such as `ai_will_do`.
1010    #[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            // TODO: pass max_severity value down
1014            validate_script_value_no_breakdown(bv, self.data, sc);
1015        })
1016    }
1017
1018    /// Just like [`Validator::field_script_value`], but instead of a full [`ScopeContext`] it just gets the scope type
1019    /// to be used for the `root` of a `ScopeContext` that is made on the spot. This is a convenient way to associate the
1020    /// `root` type with the key of this field, for clearer warnings. A passed-in `ScopeContext` would have to be associated
1021    /// with a key that is further away.
1022    ///
1023    /// Does not warn if it is an inline script value and the `desc` fields in it do not contain valid localizations.
1024    #[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            // TODO: pass max_severity value down
1029            validate_script_value(bv, self.data, &mut sc);
1030        })
1031    }
1032
1033    /// Just like [`Validator::field_script_value`], but instead of a full [`ScopeContext`] it just gets the scope type
1034    /// to be used for the `root` of a `ScopeContext` that is made on the spot. This is a convenient way to associate the
1035    /// `root` type with the key of this field, for clearer warnings. A passed-in `ScopeContext` would have to be associated
1036    /// with a key that is further away.
1037    #[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            // TODO: pass max_severity value down
1043            validate_script_value(bv, self.data, &mut sc);
1044        })
1045    }
1046
1047    /// Just like [`Validator::field_script_value`], but it takes a closure that uses the field key token
1048    /// as the input to build and output a [`ScopeContext`]. This is a convenient way to associate the `root` type with the key
1049    /// of this field, for clearer warnings. A passed-in `ScopeContext` would have to be associated with a key that is further away.
1050    #[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            // TODO: pass max_severity value down
1059            validate_script_value(bv, self.data, &mut sc);
1060        })
1061    }
1062
1063    /// Just like [`Validator::field_script_value`], but it takes a closure that uses the field key token
1064    /// as the input to build and output a [`ScopeContext`]. This is a convenient way to associate the `root` type with the key
1065    /// of this field, for clearer warnings. A passed-in `ScopeContext` would have to be associated with a key that is further away.
1066    ///
1067    /// Does not warn if it is an inline script value and the `desc` fields in it do not contain valid localizations.
1068    #[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            // TODO: pass max_severity value down
1077            validate_script_value_no_breakdown(bv, self.data, &mut sc);
1078        })
1079    }
1080
1081    /// Just like [`Validator::field_script_value`], but it can accept a literal `flag:something` value as well as a script value.
1082    #[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            // TODO: pass max_severity value down
1086            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    /// Just like [`Validator::field_script_value`], but it it expects any number of `name` fields.
1095    #[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            // TODO: pass max_severity value down
1099            validate_script_value(bv, self.data, sc);
1100        })
1101    }
1102
1103    /// Expect field `name`, if present, to be set to one of the listed strings in `choices`.
1104    /// Expect no more than one `name` field in the block.
1105    /// Returns true iff the field is present.
1106    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    /// Just like [`Validator::field_choice`], but expect any number of `name` fields in the block.
1119    #[allow(dead_code)] // not currently used
1120    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    /// Just like [`Validator::multi_field_choice`], but allow other comparators than `=`
1133    #[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    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with any number of values.
1153    /// Expect no more than one `name` field in the block.
1154    /// Returns true iff the field is present.
1155    pub fn field_list(&mut self, name: &str) -> bool {
1156        self.field_validated_list(name, |_, _| ())
1157    }
1158
1159    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with any number of values.
1160    /// Expect no more than one `name` field in the block.
1161    /// Calls the closure `f(value, data)` for every value in the list.
1162    /// Returns true iff the field is present.
1163    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    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with any number of values.
1177    /// Expect every value to be an `itype` item in the game database.
1178    /// Expect no more than one `name` field in the block.
1179    /// Returns true iff the field is present.
1180    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    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with any number of values.
1188    /// Expect every value to be an entry from the choices array.
1189    /// Expect no more than one `name` field in the block.
1190    /// Returns true iff the field is present.
1191    #[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    /// Just like [`Validator::field_validated_list`], but expect any number of `name` fields in the block.
1212    #[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    /// Just like [`Validator::field_list_items`], but expect any number of `name` fields in the block.
1227    #[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    /// Just like [`Validator::field_list_choice`], but expect any number of `name` fields in the block.
1236    #[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    /// Just like [`Validator::field_value`], but expect any number of `name` fields in the block.
1248    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    /// Just like [`Validator::field_item`], but expect any number of `name` fields in the block.
1263    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    /// Just like [`Validator::field_any_cmp`], but expect any number of `name` fields in the block.
1276    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    /// Just like [`Validator::multi_field_any_cmp`], but takes a validation closure.
1288    #[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    /// Expect field `name`, if present, to be either an assignment (`= value`) or a definition (`= { block }`).
1305    /// Expect no more than one `name` field in the block.
1306    /// Calls the closure `f(bv, data)` for every matching field.
1307    /// Returns true iff the field is present.
1308    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    /// Just like [`Validator::field_validated`], but the closure is `f(key, bv, data)`.
1328    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    /// Just like [`Validator::field_validated`], but the closure is `f(bv, data, sc)` where `sc` is
1348    /// the passed-in [`ScopeContext`].
1349    ///
1350    /// This method is useful for delegating to [`validate_desc`](crate::desc::validate_desc) which takes a bv and a sc.
1351    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    /// Just like [`Validator::field_validated_sc`], but instead of a full [`ScopeContext`] it just gets the scope type
1359    /// to be used for the `root` of a [`ScopeContext`] that is made on the spot. This is a convenient way to associate the
1360    /// `root` type with the key of this field, for clearer warnings. A passed-in [`ScopeContext`] would have to be associated
1361    /// with a key that is further away.
1362    #[cfg(feature = "ck3")] // vic3 happens not to use; silence dead code warning
1363    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    /// Just like [`Validator::field_validated`], but expect any number of `name` fields in the block.
1383    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    /// Just like [`Validator::field_validated_key`], but expect any number of `name` fields in the block.
1400    #[cfg(any(feature = "ck3", feature = "eu5"))] // vic3 happens not to use; silence dead code warning
1401    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    /// Just like [`Validator::field_validated_sc`], but expect any number of `name` fields in the block.
1418    #[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    /// Just like [`Validator::field_validated_block`], but expect any number of `name` fields in the block.
1432    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    /// Just like [`Validator::field_validated_block_sc`], but expect any number of `name` fields in the block.
1453    #[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    /// Expect field `name`, if present, to be a definition `name = { block }`.
1467    /// Expect no more than one `name` field in the block.
1468    /// Calls the closure `f(block, data)` for every matching field.
1469    /// Returns true iff the field is present.
1470    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    /// Just like [`Validator::multi_field_validated_block`], but warn if the field is redefined in
1494    /// the same file.
1495    #[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    /// Just like [`Validator::field_validated_block`], but the closure is `f(key, block, data)`.
1520    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    /// Just like [`Validator::field_validated_key_block`], but expect any number of `name` fields in the block.
1570    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    /// Just like [`Validator::field_validated_block`], but the closure is `f(block, data, sc)` where sc is the passed-in `ScopeContext`.
1591    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    /// Just like [`Validator::field_validated_block_sc`], but instead of a full [`ScopeContext`] it just gets the scope type
1604    /// to be used for the `root` of a [`ScopeContext`] that is made on the spot. This is a convenient way to associate the
1605    /// `root` type with the key of this field, for clearer warnings. A passed-in [`ScopeContext`] would have to be associated
1606    /// with a key that is further away.
1607    #[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    /// Just like [`Validator::field_validated_block_rooted`], but expect any number of `name` fields in the block.
1616    #[cfg(feature = "ck3")] // vic3 happens not to use; silence dead code warning
1617    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    /// Just like [`Validator::field_validated_block_rooted`], but it takes the passed-in `ScopeContext` and associates its
1636    /// root with this field's key instead of whatever it was associated with before. This is purely to get better warnings.
1637    ///
1638    /// TODO: get rid of this in favor of making proper `ScopeContext` to begin with.
1639    #[cfg(feature = "ck3")] // vic3 happens not to use; silence dead code warning
1640    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    /// Just like [`Validator::field_block`], but expect any number of `name` fields in the block.
1672    #[cfg(feature = "ck3")] // vic3 happens not to use; silence dead code warning
1673    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    /// Expect this [`Block`] to be a block with exactly `expect` loose values that are integers.
1689    /// So it's of the form `{ 1 2 3 }`.
1690    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    /// Expect this [`Block`] to be a block with exactly `expect` loose values that are numeric with up to 5 decimals.
1706    /// So it's of the form `{ 0.0 0.5 1.0 }`
1707    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    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with exactly `expect` values.
1723    /// Expect every value to be a number with up to 5 decimals.
1724    /// Expect no more than one `name` field in the block.
1725    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    /// Like [`Validator::req_tokens_numbers_exactly`] but the numbers can have any number of decimals.
1733    #[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    /// Like [`Validator::field_list_numeric_exactly`] but the numbers can have any number of decimals.
1750    #[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    /// Like [`Validator::field_list_numeric_exactly`] but the numbers have to be integers.
1759    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    /// If `name` is present in the block, emit a low-severity warning together with the helpful message `msg`.
1767    /// This is for harmless but unneeded fields.
1768    #[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    /// Expect the block to contain any number of loose values (possibly in addition to other things).
1778    /// Return a vector of those values.
1779    /// TODO: make this take a closure or make it an iterator.
1780    pub fn values(&mut self) -> Vec<&Token> {
1781        self.accepted_tokens = true;
1782        self.block.iter_values().collect()
1783    }
1784
1785    /// Expect the block to contain any number of loose sub-blocks (possibly in addition to other things).
1786    /// Return a vector of those blocks.
1787    /// TODO: make callers use `validated_blocks` instead.
1788    #[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    /// Expect the block to contain any number of loose sub-blocks (possibly in addition to other things).
1795    /// Run the closure `f(block, data)` for every sub-block.
1796    #[cfg(any(feature = "vic3", feature = "imperator"))] // ck3 happens not to use; silence dead code warning
1797    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    /// Expect the block to contain any number of `key = { block }` fields where the key is an integer.
1808    /// Return them as a vector of (key, block) pairs.
1809    /// TODO: make this take a closure.
1810    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    /// Expect the block to contain any number of `key = value` fields where the key is an integer.
1825    /// Return them as a vector of (key, value) pairs.
1826    /// TODO: make this take a closure.
1827    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    /// Expect the block to contain any number of `key = value` or `key = { block }` fields where the key is an integer.
1842    #[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    /// Expect the block to contain any number of `key = value` or `key = { block }` fields where the key is a number with up to 5 decimals.
1854    /// Return them as a vector of (key, bv) pairs.
1855    /// TODO: make this take a closure.
1856    #[cfg(feature = "vic3")] // ck3 happens not to use; silence dead code warning
1857    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    /// Expect the block to contain any number of `key = { block }` fields where the key is a date.
1868    /// Run the closure `f(date, block, data)` for every matching field.
1869    #[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(); // warn about unusual date formats
1877                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    /// Expect the block to contain any number of `key = value` or `key = { block }`fields
1887    /// where each key is a unique Item of type itype.
1888    /// Run the closure `f(key, bv, data)` for every matching block.
1889    #[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    /// Expect the block to contain any number of `key = value` fields
1914    /// where each key is a unique Item of type itype.
1915    /// Run the closure `f(key, vd)` for every matching block.
1916    #[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    /// Expect the block to contain any number of `key = { block }` fields
1932    /// where each key is a unique Item of type itype.
1933    /// Run the closure `f(key, block, data)` for every matching block.
1934    #[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    /// Expect the block to contain any number of unknown fields (so don't warn about unknown fields anymore).
1947    /// Loose values and loose sub-blocks will still be warned about.
1948    /// Run the closure `f(key, bv)` on every matching *unknown* field. Previously-validated fields will be skipped.
1949    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    /// Expect the block to contain any number of unknown `key = { block }` fields.
1961    /// Run the closure `f(key, block)` on every matching *unknown* field. Previously-validated fields will be skipped.
1962    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    /// Expect the block to contain any number of unknown `key = value` fields.
1975    /// Run the closure `f(key, value)` on every matching *unknown* field. Previously-validated fields will be skipped.
1976    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    /// Like [`Validator::unknown_fields`] but passes the comparator, so that `f` can determine whether it is `=` or `?=`
1989    /// It still expects the comparator to be one of those two.
1990    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    /// Like [`Validator::unknown_fields_cmp`] but accepts and passes any comparator.
2002    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    /// Tells the Validator to not warn about any unknown block contents when it goes out of scope.
2013    /// (The default is to warn.)
2014    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    /// Tells the Validator to warn about any unknown block contents right now, before it goes out of scope.
2022    /// It will not warn again when it does go out of scope.
2023    /// Returns true iff any warnings were emitted.
2024    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}