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                if !token.is("") {
510                    self.data.verify_exists_max_sev(itype, token, sev);
511                }
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                if !self.data.item_exists(itype, token.as_str()) {
598                    // TODO: pass max_severity here
599                    validate_target(token, self.data, sc, outscopes);
600                }
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                if !self.data.item_exists(itype, token.as_str()) {
619                    // TODO: pass max_severity here
620                    validate_target_ok_this(token, self.data, sc, outscopes);
621                }
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                if !token.is("yes") && !token.is("no") && !token.is("YES") && !token.is("NO") {
642                    report(ErrorKey::Validation, sev).msg("expected yes or no").loc(token).push();
643                }
644            }
645        })
646    }
647
648    /// Expect field `name`, if present, to be set to an integer.
649    /// Expect no more than one `name` field.
650    /// Returns true iff the field is present.
651    pub fn field_integer(&mut self, name: &str) -> bool {
652        self.field_check(name, AllowInject::Yes, |_, bv| {
653            if let Some(token) = bv.expect_value() {
654                // TODO: pass max_severity here
655                token.expect_integer();
656            }
657        })
658    }
659
660    /// Expect field `name`, if present, to be set to an integer within the `range` provided.
661    /// Expect no more than one `name` field.
662    /// Returns true iff the field is present.
663    pub fn field_integer_range<R: RangeBounds<i64>>(&mut self, name: &str, range: R) {
664        let sev = Severity::Error.at_most(self.max_severity);
665        self.field_check(name, AllowInject::Yes, |_, bv| {
666            if let Some(token) = bv.expect_value() {
667                // TODO: pass max_severity here
668                if let Some(i) = token.expect_integer() {
669                    if !range.contains(&i) {
670                        let low = match range.start_bound() {
671                            Bound::Unbounded => None,
672                            Bound::Included(&n) => Some(n),
673                            Bound::Excluded(&n) => Some(n + 1),
674                        };
675                        let high = match range.end_bound() {
676                            Bound::Unbounded => None,
677                            Bound::Included(&n) => Some(n),
678                            Bound::Excluded(&n) => Some(n - 1),
679                        };
680                        let msg;
681                        if let (Some(low), Some(high)) = (low, high) {
682                            msg = format!("should be between {low} and {high} (inclusive)");
683                        } else if let Some(low) = low {
684                            msg = format!("should be at least {low}");
685                        } else if let Some(high) = high {
686                            msg = format!("should be at most {high}");
687                        } else {
688                            unreachable!(); // could not have failed the contains check
689                        }
690                        report(ErrorKey::Range, sev).msg(msg).loc(token).push();
691                    }
692                }
693            }
694        });
695    }
696
697    /// Expect field `name`, if present, to be set to a number with up to 5 decimals.
698    /// (5 decimals is the limit accepted by the game engine in most contexts).
699    /// Expect no more than one `name` field.
700    /// Returns true iff the field is present.
701    pub fn field_numeric(&mut self, name: &str) -> bool {
702        self.field_check(name, AllowInject::Yes, |_, bv| {
703            if let Some(token) = bv.expect_value() {
704                token.expect_number();
705            }
706        })
707    }
708
709    /// Expect field `name`, if present, to be set to a number with up to 5 decimals.
710    /// (5 decimals is the limit accepted by the game engine in most contexts).
711    /// Expect any number of `name` fields.
712    /// Returns true iff the field is present.
713    #[cfg(feature = "hoi4")]
714    pub fn multi_field_numeric(&mut self, name: &str) -> bool {
715        self.multi_field_check(name, |_, bv| {
716            if let Some(token) = bv.expect_value() {
717                token.expect_number();
718            }
719        })
720    }
721
722    /// Expect field `name`, if present, to be set to a number with any number of decimals.
723    /// Expect no more than one `name` field.
724    /// Returns true iff the field is present.
725    pub fn field_precise_numeric(&mut self, name: &str) -> bool {
726        self.field_check(name, AllowInject::Yes, |_, bv| {
727            if let Some(token) = bv.expect_value() {
728                token.expect_precise_number();
729            }
730        })
731    }
732
733    #[cfg(any(feature = "ck3", feature = "vic3"))]
734    pub fn field_numeric_range_internal<R: RangeBounds<f64>>(
735        &mut self,
736        name: &str,
737        range: R,
738        precise: bool,
739    ) {
740        let sev = Severity::Error.at_most(self.max_severity);
741        self.field_check(name, AllowInject::Yes, |_, bv| {
742            if let Some(token) = bv.expect_value() {
743                let numeric =
744                    if precise { token.expect_precise_number() } else { token.expect_number() };
745                if let Some(f) = numeric {
746                    if !range.contains(&f) {
747                        let low = match range.start_bound() {
748                            Bound::Unbounded => None,
749                            Bound::Included(f) => Some(format!("{f} (inclusive)")),
750                            Bound::Excluded(f) => Some(format!("{f}")),
751                        };
752                        let high = match range.end_bound() {
753                            Bound::Unbounded => None,
754                            Bound::Included(f) => Some(format!("{f} (inclusive)")),
755                            Bound::Excluded(f) => Some(format!("{f}")),
756                        };
757                        let msg;
758                        if let (Some(low), Some(high)) = (low.as_ref(), high.as_ref()) {
759                            msg = format!("should be between {low} and {high}");
760                        } else if let Some(low) = low {
761                            msg = format!("should be at least {low}");
762                        } else if let Some(high) = high {
763                            msg = format!("should be at most {high}");
764                        } else {
765                            unreachable!(); // could not have failed the contains check
766                        }
767                        report(ErrorKey::Range, sev).msg(msg).loc(token).push();
768                    }
769                }
770            }
771        });
772    }
773
774    /// Expect field `name`, if present, to be set to a number within the `range` provided.
775    /// Accept at most 5 decimals. (5 decimals is the limit accepted by the game engine in most contexts).
776    /// Expect no more than one `name` field.
777    #[cfg(any(feature = "ck3", feature = "vic3"))]
778    pub fn field_numeric_range<R: RangeBounds<f64>>(&mut self, name: &str, range: R) {
779        self.field_numeric_range_internal(name, range, false);
780    }
781
782    /// Expect field `name`, if present, to be set to a number within the `range` provided.
783    /// Expect no more than one `name` field.
784    #[cfg(feature = "ck3")]
785    pub fn field_precise_numeric_range<R: RangeBounds<f64>>(&mut self, name: &str, range: R) {
786        self.field_numeric_range_internal(name, range, true);
787    }
788
789    /// Expect field `name`, if present, to be set to a date.
790    /// The format of dates is very flexible, from a single number (the year), to a year.month or year.month.day.
791    /// No checking is done on the validity of the date as a date (so January 42nd is okay).
792    /// Expect no more than one `name` field.
793    /// Returns true iff the field is present.
794    pub fn field_date(&mut self, name: &str) -> bool {
795        let sev = Severity::Error.at_most(self.max_severity);
796        self.field_check(name, AllowInject::Yes, |_, bv| {
797            if let Some(token) = bv.expect_value() {
798                if Date::from_str(token.as_str()).is_err() {
799                    let msg = "expected date value";
800                    report(ErrorKey::Validation, sev).msg(msg).loc(token).push();
801                }
802            }
803        })
804    }
805
806    /// Expect field `name`, if present, to introduce a trigger block.
807    ///
808    /// Expect no more than one `name` field in the block.
809    /// Returns true iff the field is present.
810    pub fn field_trigger(
811        &mut self,
812        name: &str,
813        tooltipped: Tooltipped,
814        sc: &mut ScopeContext,
815    ) -> bool {
816        let max_sev = self.max_severity;
817        self.field_validated_block(name, |block, data| {
818            let mut vd = Validator::new(block, data);
819            vd.set_max_severity(max_sev);
820            validate_trigger_internal(
821                Lowercase::empty(),
822                ListType::None,
823                block,
824                data,
825                sc,
826                vd,
827                tooltipped,
828                false,
829            );
830        })
831    }
832
833    /// Expect field `name`, if present, to introduce a trigger block.
834    /// Its `ScopeContext` will be constructed from the field key, with the given `Scopes` as root.
835    ///
836    /// Expect no more than one `name` field in the block.
837    /// Returns true iff the field is present.
838    #[allow(dead_code)]
839    pub fn field_trigger_rooted(
840        &mut self,
841        name: &str,
842        tooltipped: Tooltipped,
843        scope: Scopes,
844    ) -> bool {
845        let max_sev = self.max_severity;
846        self.field_validated_key_block(name, |key, block, data| {
847            let mut vd = Validator::new(block, data);
848            let mut sc = ScopeContext::new(scope, key);
849            vd.set_max_severity(max_sev);
850            validate_trigger_internal(
851                Lowercase::empty(),
852                ListType::None,
853                block,
854                data,
855                &mut sc,
856                vd,
857                tooltipped,
858                false,
859            );
860        })
861    }
862
863    /// Expect field `name`, if present, to introduce a trigger block.
864    /// Its `ScopeContext` will be created by calling the provided closure with the field's key.
865    ///
866    /// Expect no more than one `name` field in the block.
867    /// Returns true iff the field is present.
868    #[allow(dead_code)]
869    pub fn field_trigger_builder<F>(
870        &mut self,
871        name: &str,
872        tooltipped: Tooltipped,
873        mut sc_builder: F,
874    ) -> bool
875    where
876        F: FnMut(&Token) -> ScopeContext,
877    {
878        let max_sev = self.max_severity;
879        self.field_validated_key_block(name, |key, block, data| {
880            let mut vd = Validator::new(block, data);
881            vd.set_max_severity(max_sev);
882            let mut sc = sc_builder(key);
883            validate_trigger_internal(
884                Lowercase::empty(),
885                ListType::None,
886                block,
887                data,
888                &mut sc,
889                vd,
890                tooltipped,
891                false,
892            );
893        })
894    }
895
896    /// Expect field `name`, if present, to introduce an effect block.
897    ///
898    /// Expect no more than one `name` field in the block.
899    /// Returns true iff the field is present.
900    #[allow(dead_code)]
901    pub fn field_effect(
902        &mut self,
903        name: &str,
904        tooltipped: Tooltipped,
905        sc: &mut ScopeContext,
906    ) -> bool {
907        let max_sev = self.max_severity;
908        self.field_validated_block(name, |block, data| {
909            let mut vd = Validator::new(block, data);
910            vd.set_max_severity(max_sev);
911            validate_effect_internal(
912                Lowercase::empty(),
913                ListType::None,
914                block,
915                data,
916                sc,
917                &mut vd,
918                tooltipped,
919                &mut SpecialTokens::none(),
920            );
921        })
922    }
923
924    /// Expect field `name`, if present, to introduce an effect block.
925    /// Its `ScopeContext` will be constructed from the field key, with the given `Scopes` as root.
926    ///
927    /// Expect no more than one `name` field in the block.
928    /// Returns true iff the field is present.
929    #[allow(dead_code)]
930    pub fn field_effect_rooted(
931        &mut self,
932        name: &str,
933        tooltipped: Tooltipped,
934        scope: Scopes,
935    ) -> bool {
936        let max_sev = self.max_severity;
937        self.field_validated_key_block(name, |key, block, data| {
938            let mut vd = Validator::new(block, data);
939            vd.set_max_severity(max_sev);
940            let mut sc = ScopeContext::new(scope, key);
941            validate_effect_internal(
942                Lowercase::empty(),
943                ListType::None,
944                block,
945                data,
946                &mut sc,
947                &mut vd,
948                tooltipped,
949                &mut SpecialTokens::none(),
950            );
951        })
952    }
953
954    /// Expect field `name`, if present, to introduce an effect block.
955    /// Its `ScopeContext` will be created by calling the provided closure with the field's key.
956    ///
957    /// Expect no more than one `name` field in the block.
958    /// Returns true iff the field is present.
959    #[allow(dead_code)]
960    pub fn field_effect_builder<F>(
961        &mut self,
962        name: &str,
963        tooltipped: Tooltipped,
964        mut sc_builder: F,
965    ) -> bool
966    where
967        F: FnMut(&Token) -> ScopeContext,
968    {
969        let max_sev = self.max_severity;
970        self.field_validated_key_block(name, |key, block, data| {
971            let mut vd = Validator::new(block, data);
972            vd.set_max_severity(max_sev);
973            let mut sc = sc_builder(key);
974            validate_effect_internal(
975                Lowercase::empty(),
976                ListType::None,
977                block,
978                data,
979                &mut sc,
980                &mut vd,
981                tooltipped,
982                &mut SpecialTokens::none(),
983            );
984        })
985    }
986
987    /// Expect field `name`, if present, to be set to a script value, either a named one (simply `name = scriptvaluename`)
988    /// or an inline one (can be a simple number, or a range `{ min max }`, or a full script value definition with limits
989    /// and math).
990    ///
991    /// The script value is evaluated in the scope context `sc`, so for example if the script value does `scope:actor` but
992    /// there is no named scope "actor" in the scope context, then a warning is emitted.
993    ///
994    /// Expect no more than one `name` field in the block.
995    /// Returns true iff the field is present.
996    #[cfg(feature = "jomini")]
997    pub fn field_script_value(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
998        self.field_check(name, AllowInject::Yes, |_, bv| {
999            // TODO: pass max_severity value down
1000            validate_script_value(bv, self.data, sc);
1001        })
1002    }
1003
1004    /// Just like [`Validator::field_script_value`], but does not warn if it is an inline script value and the `desc` fields
1005    /// in it do not contain valid localizations. This is generally used for script values that will never be shown to
1006    /// the user except in debugging contexts, such as `ai_will_do`.
1007    #[cfg(any(feature = "ck3", feature = "vic3", feature = "eu5"))]
1008    pub fn field_script_value_no_breakdown(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1009        self.field_check(name, AllowInject::Yes, |_, bv| {
1010            // TODO: pass max_severity value down
1011            validate_script_value_no_breakdown(bv, self.data, sc);
1012        })
1013    }
1014
1015    /// Just like [`Validator::field_script_value`], but instead of a full [`ScopeContext`] it just gets the scope type
1016    /// to be used for the `root` of a `ScopeContext` that is made on the spot. This is a convenient way to associate the
1017    /// `root` type with the key of this field, for clearer warnings. A passed-in `ScopeContext` would have to be associated
1018    /// with a key that is further away.
1019    ///
1020    /// Does not warn if it is an inline script value and the `desc` fields in it do not contain valid localizations.
1021    #[cfg(feature = "jomini")]
1022    pub fn field_script_value_rooted(&mut self, name: &str, scopes: Scopes) -> bool {
1023        self.field_check(name, AllowInject::Yes, |key, bv| {
1024            let mut sc = ScopeContext::new(scopes, key);
1025            // TODO: pass max_severity value down
1026            validate_script_value(bv, self.data, &mut sc);
1027        })
1028    }
1029
1030    /// Just like [`Validator::field_script_value`], but instead of a full [`ScopeContext`] it just gets the scope type
1031    /// to be used for the `root` of a `ScopeContext` that is made on the spot. This is a convenient way to associate the
1032    /// `root` type with the key of this field, for clearer warnings. A passed-in `ScopeContext` would have to be associated
1033    /// with a key that is further away.
1034    #[cfg(feature = "jomini")]
1035    #[allow(dead_code)]
1036    pub fn field_script_value_no_breakdown_rooted(&mut self, name: &str, scopes: Scopes) -> bool {
1037        self.field_check(name, AllowInject::Yes, |key, bv| {
1038            let mut sc = ScopeContext::new(scopes, key);
1039            // TODO: pass max_severity value down
1040            validate_script_value(bv, self.data, &mut sc);
1041        })
1042    }
1043
1044    /// Just like [`Validator::field_script_value`], but it takes a closure that uses the field key token
1045    /// as the input to build and output a [`ScopeContext`]. This is a convenient way to associate the `root` type with the key
1046    /// of this field, for clearer warnings. A passed-in `ScopeContext` would have to be associated with a key that is further away.
1047    #[cfg(feature = "jomini")]
1048    #[allow(dead_code)]
1049    pub fn field_script_value_builder<F>(&mut self, name: &str, mut f: F) -> bool
1050    where
1051        F: FnMut(&Token) -> ScopeContext,
1052    {
1053        self.field_check(name, AllowInject::Yes, |key, bv| {
1054            let mut sc = f(key);
1055            // TODO: pass max_severity value down
1056            validate_script_value(bv, self.data, &mut sc);
1057        })
1058    }
1059
1060    /// Just like [`Validator::field_script_value`], but it takes a closure that uses the field key token
1061    /// as the input to build and output a [`ScopeContext`]. This is a convenient way to associate the `root` type with the key
1062    /// of this field, for clearer warnings. A passed-in `ScopeContext` would have to be associated with a key that is further away.
1063    ///
1064    /// Does not warn if it is an inline script value and the `desc` fields in it do not contain valid localizations.
1065    #[cfg(feature = "jomini")]
1066    #[allow(dead_code)]
1067    pub fn field_script_value_no_breakdown_builder<F>(&mut self, name: &str, mut f: F) -> bool
1068    where
1069        F: FnMut(&Token) -> ScopeContext,
1070    {
1071        self.field_check(name, AllowInject::Yes, |key, bv| {
1072            let mut sc = f(key);
1073            // TODO: pass max_severity value down
1074            validate_script_value_no_breakdown(bv, self.data, &mut sc);
1075        })
1076    }
1077
1078    /// Just like [`Validator::field_script_value`], but it can accept a literal `flag:something` value as well as a script value.
1079    #[cfg(feature = "jomini")]
1080    pub fn field_script_value_or_flag(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1081        self.field_check(name, AllowInject::Yes, |_, bv| {
1082            // TODO: pass max_severity value down
1083            if let Some(token) = bv.get_value() {
1084                validate_target(token, self.data, sc, Scopes::Value | Scopes::Bool | Scopes::Flag);
1085            } else {
1086                validate_script_value(bv, self.data, sc);
1087            }
1088        })
1089    }
1090
1091    /// Just like [`Validator::field_script_value`], but it it expects any number of `name` fields.
1092    #[cfg(feature = "jomini")]
1093    pub fn multi_field_script_value(&mut self, name: &str, sc: &mut ScopeContext) -> bool {
1094        self.multi_field_check(name, |_, bv| {
1095            // TODO: pass max_severity value down
1096            validate_script_value(bv, self.data, sc);
1097        })
1098    }
1099
1100    /// Expect field `name`, if present, to be set to one of the listed strings in `choices`.
1101    /// Expect no more than one `name` field in the block.
1102    /// Returns true iff the field is present.
1103    pub fn field_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1104        let sev = Severity::Error.at_most(self.max_severity);
1105        self.field_check(name, AllowInject::Yes, |_, bv| {
1106            if let Some(token) = bv.expect_value() {
1107                if !choices.contains(&token.as_str()) {
1108                    let msg = format!("expected one of {}", choices.join(", "));
1109                    report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1110                }
1111            }
1112        })
1113    }
1114
1115    /// Just like [`Validator::field_choice`], but expect any number of `name` fields in the block.
1116    #[allow(dead_code)] // not currently used
1117    pub fn multi_field_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1118        let sev = Severity::Error.at_most(self.max_severity);
1119        self.multi_field_check(name, |_, bv| {
1120            if let Some(token) = bv.expect_value() {
1121                if !choices.contains(&token.as_str()) {
1122                    let msg = format!("expected one of {}", choices.join(", "));
1123                    report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1124                }
1125            }
1126        })
1127    }
1128
1129    /// Just like [`Validator::multi_field_choice`], but allow other comparators than `=`
1130    #[allow(dead_code)]
1131    pub fn multi_field_choice_any_cmp(&mut self, name: &str, choices: &[&str]) -> bool {
1132        let mut found = false;
1133        let sev = Severity::Error.at_most(self.max_severity);
1134        for Field(key, _, bv) in self.block.iter_fields() {
1135            if key.is(name) {
1136                self.known_fields.push(key.as_str());
1137                found = true;
1138                if let Some(token) = bv.expect_value() {
1139                    if !choices.contains(&token.as_str()) {
1140                        let msg = format!("expected one of {}", choices.join(", "));
1141                        report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1142                    }
1143                }
1144            }
1145        }
1146        found
1147    }
1148
1149    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with any number of values.
1150    /// Expect no more than one `name` field in the block.
1151    /// Returns true iff the field is present.
1152    pub fn field_list(&mut self, name: &str) -> bool {
1153        self.field_validated_list(name, |_, _| ())
1154    }
1155
1156    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with any number of values.
1157    /// Expect no more than one `name` field in the block.
1158    /// Calls the closure `f(value, data)` for every value in the list.
1159    /// Returns true iff the field is present.
1160    pub fn field_validated_list<F>(&mut self, name: &str, mut f: F) -> bool
1161    where
1162        F: FnMut(&Token, &Everything),
1163    {
1164        self.field_check(name, AllowInject::No, |_, bv| {
1165            if let Some(block) = bv.expect_block() {
1166                for token in block.iter_values_warn() {
1167                    f(token, self.data);
1168                }
1169            }
1170        })
1171    }
1172
1173    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with any number of values.
1174    /// Expect every value to be an `itype` item in the game database.
1175    /// Expect no more than one `name` field in the block.
1176    /// Returns true iff the field is present.
1177    pub fn field_list_items(&mut self, name: &str, item: Item) -> bool {
1178        let sev = Severity::Error.at_most(self.max_severity);
1179        self.field_validated_list(name, |token, data| {
1180            data.verify_exists_max_sev(item, token, sev);
1181        })
1182    }
1183
1184    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with any number of values.
1185    /// Expect every value to be an entry from the choices array.
1186    /// Expect no more than one `name` field in the block.
1187    /// Returns true iff the field is present.
1188    #[allow(dead_code)]
1189    pub fn field_list_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1190        let sev = Severity::Error.at_most(self.max_severity);
1191        self.field_validated_list(name, |token, _| {
1192            if !choices.contains(&token.as_str()) {
1193                let msg = format!("expected one of {}", choices.join(", "));
1194                report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1195            }
1196        })
1197    }
1198
1199    #[cfg(feature = "ck3")]
1200    pub fn field_icon(&mut self, name: &str, define: &str, suffix: &str) -> bool {
1201        self.field_check(name, AllowInject::Yes, |_, bv| {
1202            if let Some(token) = bv.expect_value() {
1203                self.data.verify_icon(define, token, suffix);
1204            }
1205        })
1206    }
1207
1208    /// Just like [`Validator::field_validated_list`], but expect any number of `name` fields in the block.
1209    #[allow(dead_code)]
1210    pub fn multi_field_validated_list<F>(&mut self, name: &str, mut f: F) -> bool
1211    where
1212        F: FnMut(&Token, &Everything),
1213    {
1214        self.multi_field_check(name, |_, bv| {
1215            if let Some(block) = bv.expect_block() {
1216                for token in block.iter_values_warn() {
1217                    f(token, self.data);
1218                }
1219            }
1220        })
1221    }
1222
1223    /// Just like [`Validator::field_list_items`], but expect any number of `name` fields in the block.
1224    #[cfg(any(feature = "ck3", feature = "hoi4", feature = "vic3"))]
1225    pub fn multi_field_list_items(&mut self, name: &str, item: Item) -> bool {
1226        let sev = self.max_severity;
1227        self.multi_field_validated_list(name, |token, data| {
1228            data.verify_exists_max_sev(item, token, sev);
1229        })
1230    }
1231
1232    /// Just like [`Validator::field_list_choice`], but expect any number of `name` fields in the block.
1233    #[allow(dead_code)]
1234    pub fn multi_field_list_choice(&mut self, name: &str, choices: &[&str]) -> bool {
1235        let sev = Severity::Error.at_most(self.max_severity);
1236        self.multi_field_validated_list(name, |token, _| {
1237            if !choices.contains(&token.as_str()) {
1238                let msg = format!("expected one of {}", choices.join(", "));
1239                report(ErrorKey::Choice, sev).msg(msg).loc(token).push();
1240            }
1241        })
1242    }
1243
1244    /// Just like [`Validator::field_value`], but expect any number of `name` fields in the block.
1245    pub fn multi_field_value(&mut self, name: &str) -> Vec<&Token> {
1246        let mut vec = Vec::new();
1247        for Field(key, cmp, bv) in self.block.iter_fields() {
1248            if key.is(name) {
1249                self.known_fields.push(key.as_str());
1250                self.expect_eq_qeq(key, *cmp);
1251                if let Some(token) = bv.expect_value() {
1252                    vec.push(token);
1253                }
1254            }
1255        }
1256        vec
1257    }
1258
1259    /// Just like [`Validator::field_item`], but expect any number of `name` fields in the block.
1260    pub fn multi_field_item(&mut self, name: &str, itype: Item) {
1261        for Field(key, cmp, bv) in self.block.iter_fields() {
1262            if key.is(name) {
1263                self.known_fields.push(key.as_str());
1264                self.expect_eq_qeq(key, *cmp);
1265                if let Some(token) = bv.expect_value() {
1266                    self.data.verify_exists_max_sev(itype, token, self.max_severity);
1267                }
1268            }
1269        }
1270    }
1271
1272    /// Just like [`Validator::field_any_cmp`], but expect any number of `name` fields in the block.
1273    pub fn multi_field_any_cmp(&mut self, name: &str) -> bool {
1274        let mut found = false;
1275        for Field(key, _, _) in self.block.iter_fields() {
1276            if key.is(name) {
1277                self.known_fields.push(key.as_str());
1278                found = true;
1279            }
1280        }
1281        found
1282    }
1283
1284    /// Just like [`Validator::multi_field_any_cmp`], but takes a validation closure.
1285    #[allow(dead_code)]
1286    pub fn multi_field_validated_any_cmp<F>(&mut self, name: &str, mut f: F) -> bool
1287    where
1288        F: FnMut(&BV, &Everything),
1289    {
1290        let mut found = false;
1291        for Field(key, _, bv) in self.block.iter_fields() {
1292            if key.is(name) {
1293                self.known_fields.push(key.as_str());
1294                f(bv, self.data);
1295                found = true;
1296            }
1297        }
1298        found
1299    }
1300
1301    /// Expect field `name`, if present, to be either an assignment (`= value`) or a definition (`= { block }`).
1302    /// Expect no more than one `name` field in the block.
1303    /// Calls the closure `f(bv, data)` for every matching field.
1304    /// Returns true iff the field is present.
1305    pub fn field_validated<F>(&mut self, name: &str, mut f: F) -> bool
1306    where
1307        F: FnMut(&BV, &Everything),
1308    {
1309        let mut found = None;
1310        for Field(key, cmp, bv) in self.block.iter_fields() {
1311            if key.is(name) {
1312                self.known_fields.push(key.as_str());
1313                self.expect_eq_qeq(key, *cmp);
1314                if let Some(other) = found {
1315                    dup_assign_error(key, other, AllowInject::No);
1316                }
1317                f(bv, self.data);
1318                found = Some(key);
1319            }
1320        }
1321        found.is_some()
1322    }
1323
1324    /// Just like [`Validator::field_validated`], but the closure is `f(key, bv, data)`.
1325    pub fn field_validated_key<F>(&mut self, name: &str, mut f: F) -> bool
1326    where
1327        F: FnMut(&Token, &BV, &Everything),
1328    {
1329        let mut found = None;
1330        for Field(key, cmp, bv) in self.block.iter_fields() {
1331            if key.is(name) {
1332                self.known_fields.push(key.as_str());
1333                self.expect_eq_qeq(key, *cmp);
1334                if let Some(other) = found {
1335                    dup_assign_error(key, other, AllowInject::No);
1336                }
1337                f(key, bv, self.data);
1338                found = Some(key);
1339            }
1340        }
1341        found.is_some()
1342    }
1343
1344    /// Just like [`Validator::field_validated`], but the closure is `f(bv, data, sc)` where `sc` is
1345    /// the passed-in [`ScopeContext`].
1346    ///
1347    /// This method is useful for delegating to [`validate_desc`](crate::desc::validate_desc) which takes a bv and a sc.
1348    pub fn field_validated_sc<F>(&mut self, name: &str, sc: &mut ScopeContext, mut f: F) -> bool
1349    where
1350        F: FnMut(&BV, &Everything, &mut ScopeContext),
1351    {
1352        self.field_validated(name, |bv, data| f(bv, data, sc))
1353    }
1354
1355    /// Just like [`Validator::field_validated_sc`], but instead of a full [`ScopeContext`] it just gets the scope type
1356    /// to be used for the `root` of a [`ScopeContext`] that is made on the spot. This is a convenient way to associate the
1357    /// `root` type with the key of this field, for clearer warnings. A passed-in [`ScopeContext`] would have to be associated
1358    /// with a key that is further away.
1359    #[cfg(feature = "ck3")] // vic3 happens not to use; silence dead code warning
1360    pub fn field_validated_rooted<F>(&mut self, name: &str, scopes: Scopes, f: F) -> bool
1361    where
1362        F: FnMut(&BV, &Everything, &mut ScopeContext),
1363    {
1364        self.field_validated_build_sc(name, |key| ScopeContext::new(scopes, key), f)
1365    }
1366
1367    #[cfg(feature = "ck3")]
1368    pub fn field_validated_build_sc<B, F>(&mut self, name: &str, mut b: B, mut f: F) -> bool
1369    where
1370        B: FnMut(&Token) -> ScopeContext,
1371        F: FnMut(&BV, &Everything, &mut ScopeContext),
1372    {
1373        self.field_validated_key(name, |key, bv, data| {
1374            let mut sc = b(key);
1375            f(bv, data, &mut sc);
1376        })
1377    }
1378
1379    /// Just like [`Validator::field_validated`], but expect any number of `name` fields in the block.
1380    pub fn multi_field_validated<F>(&mut self, name: &str, mut f: F) -> bool
1381    where
1382        F: FnMut(&BV, &Everything),
1383    {
1384        let mut found = false;
1385        for Field(key, cmp, bv) in self.block.iter_fields() {
1386            if key.is(name) {
1387                self.known_fields.push(key.as_str());
1388                self.expect_eq_qeq(key, *cmp);
1389                f(bv, self.data);
1390                found = true;
1391            }
1392        }
1393        found
1394    }
1395
1396    /// Just like [`Validator::field_validated_key`], but expect any number of `name` fields in the block.
1397    #[cfg(any(feature = "ck3", feature = "eu5"))] // vic3 happens not to use; silence dead code warning
1398    pub fn multi_field_validated_key<F>(&mut self, name: &str, mut f: F) -> bool
1399    where
1400        F: FnMut(&Token, &BV, &Everything),
1401    {
1402        let mut found = false;
1403        for Field(key, cmp, bv) in self.block.iter_fields() {
1404            if key.is(name) {
1405                self.known_fields.push(key.as_str());
1406                self.expect_eq_qeq(key, *cmp);
1407                f(key, bv, self.data);
1408                found = true;
1409            }
1410        }
1411        found
1412    }
1413
1414    /// Just like [`Validator::field_validated_sc`], but expect any number of `name` fields in the block.
1415    #[allow(dead_code)]
1416    pub fn multi_field_validated_sc<F>(
1417        &mut self,
1418        name: &str,
1419        sc: &mut ScopeContext,
1420        mut f: F,
1421    ) -> bool
1422    where
1423        F: FnMut(&BV, &Everything, &mut ScopeContext),
1424    {
1425        self.multi_field_validated(name, |b, data| f(b, data, sc))
1426    }
1427
1428    /// Just like [`Validator::field_validated_block`], but expect any number of `name` fields in the block.
1429    pub fn multi_field_validated_block<F>(&mut self, name: &str, mut f: F) -> bool
1430    where
1431        F: FnMut(&Block, &Everything),
1432    {
1433        let mut found = false;
1434        for Field(key, cmp, bv) in self.block.iter_fields() {
1435            if (self.case_sensitive && key.is(name))
1436                || (!self.case_sensitive && key.lowercase_is(name))
1437            {
1438                self.known_fields.push(key.as_str());
1439                self.expect_eq_qeq(key, *cmp);
1440                if let Some(block) = bv.expect_block() {
1441                    f(block, self.data);
1442                }
1443                found = true;
1444            }
1445        }
1446        found
1447    }
1448
1449    /// Just like [`Validator::field_validated_block_sc`], but expect any number of `name` fields in the block.
1450    #[allow(dead_code)]
1451    pub fn multi_field_validated_block_sc<F>(
1452        &mut self,
1453        name: &str,
1454        sc: &mut ScopeContext,
1455        mut f: F,
1456    ) -> bool
1457    where
1458        F: FnMut(&Block, &Everything, &mut ScopeContext),
1459    {
1460        self.multi_field_validated_block(name, |b, data| f(b, data, sc))
1461    }
1462
1463    /// Expect field `name`, if present, to be a definition `name = { block }`.
1464    /// Expect no more than one `name` field in the block.
1465    /// Calls the closure `f(block, data)` for every matching field.
1466    /// Returns true iff the field is present.
1467    pub fn field_validated_block<F>(&mut self, name: &str, mut f: F) -> bool
1468    where
1469        F: FnMut(&Block, &Everything),
1470    {
1471        let mut found = None;
1472        for Field(key, cmp, bv) in self.block.iter_fields() {
1473            if (self.case_sensitive && key.is(name))
1474                || (!self.case_sensitive && key.lowercase_is(name))
1475            {
1476                self.known_fields.push(key.as_str());
1477                if let Some(other) = found {
1478                    dup_assign_error(key, other, AllowInject::No);
1479                }
1480                self.expect_eq_qeq(key, *cmp);
1481                if let Some(block) = bv.expect_block() {
1482                    f(block, self.data);
1483                }
1484                found = Some(key);
1485            }
1486        }
1487        found.is_some()
1488    }
1489
1490    /// Just like [`Validator::multi_field_validated_block`], but warn if the field is redefined in
1491    /// the same file.
1492    #[cfg(feature = "vic3")]
1493    pub fn multi_warn_field_validated_block<F>(&mut self, name: &str, mut f: F) -> bool
1494    where
1495        F: FnMut(&Block, &Everything),
1496    {
1497        let mut found: Option<&Token> = None;
1498        for Field(key, cmp, bv) in self.block.iter_fields() {
1499            if (self.case_sensitive && key.is(name))
1500                || (!self.case_sensitive && key.lowercase_is(name))
1501            {
1502                self.known_fields.push(key.as_str());
1503                if let Some(other) = found {
1504                    dup_assign_error(key, other, AllowInject::Yes);
1505                }
1506                self.expect_eq_qeq(key, *cmp);
1507                if let Some(block) = bv.expect_block() {
1508                    f(block, self.data);
1509                }
1510                found = Some(key);
1511            }
1512        }
1513        found.is_some()
1514    }
1515
1516    /// Just like [`Validator::field_validated_block`], but the closure is `f(key, block, data)`.
1517    pub fn field_validated_key_block<F>(&mut self, name: &str, mut f: F) -> bool
1518    where
1519        F: FnMut(&Token, &Block, &Everything),
1520    {
1521        let mut found = None;
1522        for Field(key, cmp, bv) in self.block.iter_fields() {
1523            if (self.case_sensitive && key.is(name))
1524                || (!self.case_sensitive && key.lowercase_is(name))
1525            {
1526                self.known_fields.push(key.as_str());
1527                if let Some(other) = found {
1528                    dup_assign_error(key, other, AllowInject::No);
1529                }
1530                self.expect_eq_qeq(key, *cmp);
1531                if let Some(block) = bv.expect_block() {
1532                    f(key, block, self.data);
1533                }
1534                found = Some(key);
1535            }
1536        }
1537        found.is_some()
1538    }
1539
1540    #[allow(dead_code)]
1541    pub fn field_validated_block_build_sc<B, F>(&mut self, name: &str, mut b: B, mut f: F) -> bool
1542    where
1543        B: FnMut(&Token) -> ScopeContext,
1544        F: FnMut(&Block, &Everything, &mut ScopeContext),
1545    {
1546        let mut found = None;
1547        for Field(key, cmp, bv) in self.block.iter_fields() {
1548            if (self.case_sensitive && key.is(name))
1549                || (!self.case_sensitive && key.lowercase_is(name))
1550            {
1551                self.known_fields.push(key.as_str());
1552                if let Some(other) = found {
1553                    dup_assign_error(key, other, AllowInject::No);
1554                }
1555                self.expect_eq_qeq(key, *cmp);
1556                if let Some(block) = bv.expect_block() {
1557                    let mut sc = b(key);
1558                    f(block, self.data, &mut sc);
1559                }
1560                found = Some(key);
1561            }
1562        }
1563        found.is_some()
1564    }
1565
1566    /// Just like [`Validator::field_validated_key_block`], but expect any number of `name` fields in the block.
1567    pub fn multi_field_validated_key_block<F>(&mut self, name: &str, mut f: F) -> bool
1568    where
1569        F: FnMut(&Token, &Block, &Everything),
1570    {
1571        let mut found = false;
1572        for Field(key, cmp, bv) in self.block.iter_fields() {
1573            if (self.case_sensitive && key.is(name))
1574                || (!self.case_sensitive && key.lowercase_is(name))
1575            {
1576                self.known_fields.push(key.as_str());
1577                self.expect_eq_qeq(key, *cmp);
1578                if let Some(block) = bv.expect_block() {
1579                    f(key, block, self.data);
1580                }
1581                found = true;
1582            }
1583        }
1584        found
1585    }
1586
1587    /// Just like [`Validator::field_validated_block`], but the closure is `f(block, data, sc)` where sc is the passed-in `ScopeContext`.
1588    pub fn field_validated_block_sc<F>(
1589        &mut self,
1590        name: &str,
1591        sc: &mut ScopeContext,
1592        mut f: F,
1593    ) -> bool
1594    where
1595        F: FnMut(&Block, &Everything, &mut ScopeContext),
1596    {
1597        self.field_validated_block(name, |b, data| f(b, data, sc))
1598    }
1599
1600    /// Just like [`Validator::field_validated_block_sc`], but instead of a full [`ScopeContext`] it just gets the scope type
1601    /// to be used for the `root` of a [`ScopeContext`] that is made on the spot. This is a convenient way to associate the
1602    /// `root` type with the key of this field, for clearer warnings. A passed-in [`ScopeContext`] would have to be associated
1603    /// with a key that is further away.
1604    #[allow(dead_code)]
1605    pub fn field_validated_block_rooted<F>(&mut self, name: &str, scopes: Scopes, f: F) -> bool
1606    where
1607        F: FnMut(&Block, &Everything, &mut ScopeContext),
1608    {
1609        self.field_validated_block_build_sc(name, |key| ScopeContext::new(scopes, key), f)
1610    }
1611
1612    /// Just like [`Validator::field_validated_block_rooted`], but expect any number of `name` fields in the block.
1613    #[cfg(feature = "ck3")] // vic3 happens not to use; silence dead code warning
1614    pub fn multi_field_validated_block_rooted<F>(&mut self, name: &str, scopes: Scopes, mut f: F)
1615    where
1616        F: FnMut(&Block, &Everything, &mut ScopeContext),
1617    {
1618        for Field(key, cmp, bv) in self.block.iter_fields() {
1619            if (self.case_sensitive && key.is(name))
1620                || (!self.case_sensitive && key.lowercase_is(name))
1621            {
1622                self.known_fields.push(key.as_str());
1623                self.expect_eq_qeq(key, *cmp);
1624                if let Some(block) = bv.expect_block() {
1625                    let mut sc = ScopeContext::new(scopes, key);
1626                    f(block, self.data, &mut sc);
1627                }
1628            }
1629        }
1630    }
1631
1632    /// Just like [`Validator::field_validated_block_rooted`], but it takes the passed-in `ScopeContext` and associates its
1633    /// root with this field's key instead of whatever it was associated with before. This is purely to get better warnings.
1634    ///
1635    /// TODO: get rid of this in favor of making proper `ScopeContext` to begin with.
1636    #[cfg(feature = "ck3")] // vic3 happens not to use; silence dead code warning
1637    pub fn field_validated_block_rerooted<F>(
1638        &mut self,
1639        name: &str,
1640        sc: &ScopeContext,
1641        scopes: Scopes,
1642        mut f: F,
1643    ) -> bool
1644    where
1645        F: FnMut(&Block, &Everything, &mut ScopeContext),
1646    {
1647        let mut found = None;
1648        for Field(key, cmp, bv) in self.block.iter_fields() {
1649            if (self.case_sensitive && key.is(name))
1650                || (!self.case_sensitive && key.lowercase_is(name))
1651            {
1652                self.known_fields.push(key.as_str());
1653                if let Some(other) = found {
1654                    dup_assign_error(key, other, AllowInject::No);
1655                }
1656                self.expect_eq_qeq(key, *cmp);
1657                if let Some(block) = bv.expect_block() {
1658                    let mut sc = sc.clone();
1659                    sc.change_root(scopes, key);
1660                    f(block, self.data, &mut sc);
1661                }
1662                found = Some(key);
1663            }
1664        }
1665        found.is_some()
1666    }
1667
1668    /// Just like [`Validator::field_block`], but expect any number of `name` fields in the block.
1669    #[cfg(feature = "ck3")] // vic3 happens not to use; silence dead code warning
1670    pub fn multi_field_block(&mut self, name: &str) -> bool {
1671        let mut found = false;
1672        for Field(key, cmp, bv) in self.block.iter_fields() {
1673            if (self.case_sensitive && key.is(name))
1674                || (!self.case_sensitive && key.lowercase_is(name))
1675            {
1676                self.known_fields.push(key.as_str());
1677                self.expect_eq_qeq(key, *cmp);
1678                bv.expect_block();
1679                found = true;
1680            }
1681        }
1682        found
1683    }
1684
1685    /// Expect this [`Block`] to be a block with exactly `expect` loose values that are integers.
1686    /// So it's of the form `{ 1 2 3 }`.
1687    pub fn req_tokens_integers_exactly(&mut self, expect: usize) {
1688        self.accepted_tokens = true;
1689        let mut found = 0;
1690        for token in self.block.iter_values() {
1691            if token.expect_integer().is_some() {
1692                found += 1;
1693            }
1694        }
1695        if found != expect {
1696            let msg = format!("expected {expect} integers");
1697            let sev = Severity::Error.at_most(self.max_severity);
1698            report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
1699        }
1700    }
1701
1702    /// Expect this [`Block`] to be a block with exactly `expect` loose values that are numeric with up to 5 decimals.
1703    /// So it's of the form `{ 0.0 0.5 1.0 }`
1704    pub fn req_tokens_numbers_exactly(&mut self, expect: usize) {
1705        self.accepted_tokens = true;
1706        let mut found = 0;
1707        for token in self.block.iter_values() {
1708            if token.expect_number().is_some() {
1709                found += 1;
1710            }
1711        }
1712        if found != expect {
1713            let msg = format!("expected {expect} numbers");
1714            let sev = Severity::Error.at_most(self.max_severity);
1715            report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
1716        }
1717    }
1718
1719    /// Expect field `name`, if present, to be of the form `name = { value value value ... }` with exactly `expect` values.
1720    /// Expect every value to be a number with up to 5 decimals.
1721    /// Expect no more than one `name` field in the block.
1722    pub fn field_list_numeric_exactly(&mut self, name: &str, expect: usize) {
1723        self.field_validated_block(name, |block, data| {
1724            let mut vd = Validator::new(block, data);
1725            vd.req_tokens_numbers_exactly(expect);
1726        });
1727    }
1728
1729    /// Like [`Validator::req_tokens_numbers_exactly`] but the numbers can have any number of decimals.
1730    #[allow(dead_code)]
1731    pub fn req_tokens_precise_numbers_exactly(&mut self, expect: usize) {
1732        self.accepted_tokens = true;
1733        let mut found = 0;
1734        for token in self.block.iter_values() {
1735            if token.expect_precise_number().is_some() {
1736                found += 1;
1737            }
1738        }
1739        if found != expect {
1740            let msg = format!("expected {expect} numbers");
1741            let sev = Severity::Error.at_most(self.max_severity);
1742            report(ErrorKey::Validation, sev).msg(msg).loc(self.block).push();
1743        }
1744    }
1745
1746    /// Like [`Validator::field_list_numeric_exactly`] but the numbers can have any number of decimals.
1747    #[allow(dead_code)]
1748    pub fn field_list_precise_numeric_exactly(&mut self, name: &str, expect: usize) {
1749        self.field_validated_block(name, |block, data| {
1750            let mut vd = Validator::new(block, data);
1751            vd.req_tokens_precise_numbers_exactly(expect);
1752        });
1753    }
1754
1755    /// Like [`Validator::field_list_numeric_exactly`] but the numbers have to be integers.
1756    pub fn field_list_integers_exactly(&mut self, name: &str, expect: usize) {
1757        self.field_validated_block(name, |block, data| {
1758            let mut vd = Validator::new(block, data);
1759            vd.req_tokens_integers_exactly(expect);
1760        });
1761    }
1762
1763    /// If `name` is present in the block, emit a low-severity warning together with the helpful message `msg`.
1764    /// This is for harmless but unneeded fields.
1765    #[allow(dead_code)]
1766    pub fn advice_field(&mut self, name: &str, msg: &str) {
1767        if let Some(key) = self.block.get_key(name) {
1768            self.known_fields.push(key.as_str());
1769            let sev = Severity::Untidy.at_most(self.max_severity);
1770            report(ErrorKey::Unneeded, sev).msg(msg).loc(key).push();
1771        }
1772    }
1773
1774    /// Expect the block to contain any number of loose values (possibly in addition to other things).
1775    /// Return a vector of those values.
1776    /// TODO: make this take a closure or make it an iterator.
1777    pub fn values(&mut self) -> Vec<&Token> {
1778        self.accepted_tokens = true;
1779        self.block.iter_values().collect()
1780    }
1781
1782    /// Expect the block to contain any number of loose sub-blocks (possibly in addition to other things).
1783    /// Return a vector of those blocks.
1784    /// TODO: make callers use `validated_blocks` instead.
1785    #[allow(dead_code)]
1786    pub fn blocks(&mut self) -> Vec<&Block> {
1787        self.accepted_blocks = true;
1788        self.block.iter_blocks().collect()
1789    }
1790
1791    /// Expect the block to contain any number of loose sub-blocks (possibly in addition to other things).
1792    /// Run the closure `f(block, data)` for every sub-block.
1793    #[cfg(any(feature = "vic3", feature = "imperator"))] // ck3 happens not to use; silence dead code warning
1794    pub fn validated_blocks<F>(&mut self, mut f: F)
1795    where
1796        F: FnMut(&Block, &Everything),
1797    {
1798        self.accepted_blocks = true;
1799        for block in self.block.iter_blocks() {
1800            f(block, self.data);
1801        }
1802    }
1803
1804    /// Expect the block to contain any number of `key = { block }` fields where the key is an integer.
1805    /// Return them as a vector of (key, block) pairs.
1806    /// TODO: make this take a closure.
1807    pub fn integer_blocks(&mut self) -> Vec<(&Token, &Block)> {
1808        let mut vec = Vec::new();
1809        for Field(key, cmp, bv) in self.block.iter_fields() {
1810            if key.is_integer() {
1811                self.known_fields.push(key.as_str());
1812                self.expect_eq_qeq(key, *cmp);
1813                if let Some(block) = bv.expect_block() {
1814                    vec.push((key, block));
1815                }
1816            }
1817        }
1818        vec
1819    }
1820
1821    /// Expect the block to contain any number of `key = value` fields where the key is an integer.
1822    /// Return them as a vector of (key, value) pairs.
1823    /// TODO: make this take a closure.
1824    pub fn integer_values(&mut self) -> Vec<(&Token, &Token)> {
1825        let mut vec = Vec::new();
1826        for Field(key, cmp, bv) in self.block.iter_fields() {
1827            if key.is_integer() {
1828                self.known_fields.push(key.as_str());
1829                self.expect_eq_qeq(key, *cmp);
1830                if let Some(token) = bv.expect_value() {
1831                    vec.push((key, token));
1832                }
1833            }
1834        }
1835        vec
1836    }
1837
1838    /// Expect the block to contain any number of `key = value` or `key = { block }` fields where the key is an integer.
1839    #[allow(dead_code)]
1840    pub fn integer_keys<F: FnMut(&Token, &BV)>(&mut self, mut f: F) {
1841        for Field(key, cmp, bv) in self.block.iter_fields() {
1842            if key.is_integer() {
1843                self.known_fields.push(key.as_str());
1844                self.expect_eq_qeq(key, *cmp);
1845                f(key, bv);
1846            }
1847        }
1848    }
1849
1850    /// 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.
1851    /// Return them as a vector of (key, bv) pairs.
1852    /// TODO: make this take a closure.
1853    #[cfg(feature = "vic3")] // ck3 happens not to use; silence dead code warning
1854    pub fn numeric_keys<F: FnMut(&Token, &BV)>(&mut self, mut f: F) {
1855        for Field(key, cmp, bv) in self.block.iter_fields() {
1856            if key.is_number() {
1857                self.known_fields.push(key.as_str());
1858                self.expect_eq_qeq(key, *cmp);
1859                f(key, bv);
1860            }
1861        }
1862    }
1863
1864    /// Expect the block to contain any number of `key = { block }` fields where the key is a date.
1865    /// Run the closure `f(date, block, data)` for every matching field.
1866    #[cfg(any(feature = "ck3", feature = "hoi4"))]
1867    pub fn validate_history_blocks<F>(&mut self, mut f: F)
1868    where
1869        F: FnMut(Date, &Token, &Block, &Everything),
1870    {
1871        for Field(key, cmp, bv) in self.block.iter_fields() {
1872            if let Ok(date) = Date::try_from(key) {
1873                key.expect_date(); // warn about unusual date formats
1874                self.known_fields.push(key.as_str());
1875                self.expect_eq_qeq(key, *cmp);
1876                if let Some(block) = bv.expect_block() {
1877                    f(date, key, block, self.data);
1878                }
1879            }
1880        }
1881    }
1882
1883    /// Expect the block to contain any number of `key = value` or `key = { block }`fields
1884    /// where each key is a unique Item of type itype.
1885    /// Run the closure `f(key, bv, data)` for every matching block.
1886    #[allow(dead_code)]
1887    pub fn validate_item_key_fields<F>(&mut self, itype: Item, mut f: F)
1888    where
1889        F: FnMut(&Token, &BV, &Everything),
1890    {
1891        let mut visited_fields = TigerHashSet::default();
1892        for Field(key, _, bv) in self.block.iter_fields() {
1893            if !self.known_fields.contains(&key.as_str()) {
1894                self.data.verify_exists(itype, key);
1895
1896                match visited_fields.get(key.as_str()) {
1897                    Some(&duplicate) => dup_assign_error(key, duplicate, AllowInject::No),
1898                    None => {
1899                        visited_fields.insert(key);
1900                    }
1901                }
1902
1903                self.known_fields.push(key.as_str());
1904
1905                f(key, bv, self.data);
1906            }
1907        }
1908    }
1909
1910    /// Expect the block to contain any number of `key = value` fields
1911    /// where each key is a unique Item of type itype.
1912    /// Run the closure `f(key, vd)` for every matching block.
1913    #[allow(dead_code)]
1914    pub fn validate_item_key_values<F>(&mut self, itype: Item, mut f: F)
1915    where
1916        F: FnMut(&Token, ValueValidator),
1917    {
1918        let sev = self.max_severity;
1919        self.validate_item_key_fields(itype, |key, bv, data| {
1920            if let Some(value) = bv.expect_value() {
1921                let mut vd = ValueValidator::new(value, data);
1922                vd.set_max_severity(sev);
1923                f(key, vd);
1924            }
1925        });
1926    }
1927
1928    /// Expect the block to contain any number of `key = { block }` fields
1929    /// where each key is a unique Item of type itype.
1930    /// Run the closure `f(key, block, data)` for every matching block.
1931    #[allow(dead_code)]
1932    pub fn validate_item_key_blocks<F>(&mut self, itype: Item, mut f: F)
1933    where
1934        F: FnMut(&Token, &Block, &Everything),
1935    {
1936        self.validate_item_key_fields(itype, |key, bv, data| {
1937            if let Some(block) = bv.expect_block() {
1938                f(key, block, data);
1939            }
1940        });
1941    }
1942
1943    /// Expect the block to contain any number of unknown fields (so don't warn about unknown fields anymore).
1944    /// Loose values and loose sub-blocks will still be warned about.
1945    /// Run the closure `f(key, bv)` on every matching *unknown* field. Previously-validated fields will be skipped.
1946    pub fn unknown_fields<F: FnMut(&Token, &BV)>(&mut self, mut f: F) {
1947        self.accepted_block_fields = true;
1948        self.accepted_value_fields = true;
1949        for Field(key, cmp, bv) in self.block.iter_fields() {
1950            self.expect_eq_qeq(key, *cmp);
1951            if !self.known_fields.contains(&key.as_str()) {
1952                f(key, bv);
1953            }
1954        }
1955    }
1956
1957    /// Expect the block to contain any number of unknown `key = { block }` fields.
1958    /// Run the closure `f(key, block)` on every matching *unknown* field. Previously-validated fields will be skipped.
1959    pub fn unknown_block_fields<F: FnMut(&Token, &Block)>(&mut self, mut f: F) {
1960        self.accepted_block_fields = true;
1961        for Field(key, cmp, bv) in self.block.iter_fields() {
1962            if let Some(block) = bv.get_block() {
1963                self.expect_eq_qeq(key, *cmp);
1964                if !self.known_fields.contains(&key.as_str()) {
1965                    f(key, block);
1966                }
1967            }
1968        }
1969    }
1970
1971    /// Expect the block to contain any number of unknown `key = value` fields.
1972    /// Run the closure `f(key, value)` on every matching *unknown* field. Previously-validated fields will be skipped.
1973    pub fn unknown_value_fields<F: FnMut(&Token, &Token)>(&mut self, mut f: F) {
1974        self.accepted_value_fields = true;
1975        for Field(key, cmp, bv) in self.block.iter_fields() {
1976            if let Some(value) = bv.get_value() {
1977                self.expect_eq_qeq(key, *cmp);
1978                if !self.known_fields.contains(&key.as_str()) {
1979                    f(key, value);
1980                }
1981            }
1982        }
1983    }
1984
1985    /// Like [`Validator::unknown_fields`] but passes the comparator, so that `f` can determine whether it is `=` or `?=`
1986    /// It still expects the comparator to be one of those two.
1987    pub fn unknown_fields_cmp<F: FnMut(&Token, Comparator, &BV)>(&mut self, mut f: F) {
1988        self.accepted_block_fields = true;
1989        self.accepted_value_fields = true;
1990        for Field(key, cmp, bv) in self.block.iter_fields() {
1991            if !self.known_fields.contains(&key.as_str()) {
1992                self.expect_eq_qeq(key, *cmp);
1993                f(key, *cmp, bv);
1994            }
1995        }
1996    }
1997
1998    /// Like [`Validator::unknown_fields_cmp`] but accepts and passes any comparator.
1999    pub fn unknown_fields_any_cmp<F: FnMut(&Token, Comparator, &BV)>(&mut self, mut f: F) {
2000        self.accepted_block_fields = true;
2001        self.accepted_value_fields = true;
2002        for Field(key, cmp, bv) in self.block.iter_fields() {
2003            if !self.known_fields.contains(&key.as_str()) {
2004                f(key, *cmp, bv);
2005            }
2006        }
2007    }
2008
2009    /// Tells the Validator to not warn about any unknown block contents when it goes out of scope.
2010    /// (The default is to warn.)
2011    pub fn no_warn_remaining(&mut self) {
2012        self.accepted_block_fields = true;
2013        self.accepted_value_fields = true;
2014        self.accepted_tokens = true;
2015        self.accepted_blocks = true;
2016    }
2017
2018    /// Tells the Validator to warn about any unknown block contents right now, before it goes out of scope.
2019    /// It will not warn again when it does go out of scope.
2020    /// Returns true iff any warnings were emitted.
2021    pub fn warn_remaining(&mut self) -> bool {
2022        let mut warned = false;
2023        for item in self.block.iter_items() {
2024            match item {
2025                BlockItem::Field(Field(key, _, bv)) => match bv {
2026                    BV::Value(_) => {
2027                        if !self.accepted_value_fields && !self.known_fields.contains(&key.as_str())
2028                        {
2029                            let msg = format!("unknown field `{key}`");
2030                            let sev = Severity::Error.at_most(self.max_severity);
2031                            report(ErrorKey::UnknownField, sev).weak().msg(msg).loc(key).push();
2032                            warned = true;
2033                        }
2034                    }
2035                    BV::Block(_) => {
2036                        if !self.accepted_block_fields && !self.known_fields.contains(&key.as_str())
2037                        {
2038                            let msg = format!("unknown field `{key}`");
2039                            let sev = Severity::Error.at_most(self.max_severity);
2040                            report(ErrorKey::UnknownField, sev).weak().msg(msg).loc(key).push();
2041                            warned = true;
2042                        }
2043                    }
2044                },
2045                BlockItem::Value(t) => {
2046                    if !self.accepted_tokens {
2047                        let msg = format!("found loose value {t}, expected only `key =`");
2048                        let sev = Severity::Error.at_most(self.max_severity);
2049                        report(ErrorKey::Structure, sev).msg(msg).loc(t).push();
2050                        warned = true;
2051                    }
2052                }
2053                BlockItem::Block(b) => {
2054                    if !self.accepted_blocks {
2055                        let msg = "found sub-block, expected only `key =`";
2056                        let sev = Severity::Error.at_most(self.max_severity);
2057                        report(ErrorKey::Structure, sev).msg(msg).loc(b).push();
2058                        warned = true;
2059                    }
2060                }
2061            }
2062        }
2063        self.no_warn_remaining();
2064        warned
2065    }
2066
2067    fn expect_eq_qeq(&self, key: &Token, cmp: Comparator) {
2068        #[allow(clippy::collapsible_else_if)]
2069        if self.allow_questionmark_equals {
2070            if !matches!(cmp, Comparator::Equals(Single | Question)) {
2071                let msg = format!("expected `{key} =` or `?=`, found `{cmp}`");
2072                let sev = Severity::Error.at_most(self.max_severity);
2073                report(ErrorKey::Validation, sev).msg(msg).loc(key).push();
2074            }
2075        } else {
2076            if !matches!(cmp, Comparator::Equals(Single)) {
2077                let msg = format!("expected `{key} =`, found `{cmp}`");
2078                let sev = Severity::Error.at_most(self.max_severity);
2079                report(ErrorKey::Validation, sev).msg(msg).loc(key).push();
2080            }
2081        }
2082    }
2083}
2084
2085impl Drop for Validator<'_> {
2086    fn drop(&mut self) {
2087        self.warn_remaining();
2088    }
2089}