tiger_lib/
defines.rs

1//! Utility code for managing the in-game defines
2
3use crate::block::BV;
4use crate::datatype::Datatype;
5use crate::everything::Everything;
6use crate::item::Item;
7use crate::report::{ErrorKey, err, warn};
8use crate::token::Token;
9use crate::validator::Validator;
10
11/// The expected value of a define in `common/defines`.
12#[derive(Debug, Clone, Copy)]
13#[allow(dead_code)]
14pub enum DefineType {
15    Boolean,
16    Integer,
17    Number,
18    Date,
19    String,
20    Item(Item),
21    SingleQuotedItem(Item),
22    Choice(&'static [&'static str]),
23    UnknownList,
24    IntegerList,
25    NumberList,
26    StringList,
27    ItemList(Item),
28    ItemOrEmptyList(Item),
29    /// Color is a list of 4 numbers, presumably in RGBA format.
30    Color,
31    /// Color3 is a list of 3 numbers, presumably in RGB format.
32    Color3,
33}
34
35impl From<DefineType> for Datatype {
36    fn from(dt: DefineType) -> Self {
37        match dt {
38            DefineType::Boolean => Datatype::bool,
39            DefineType::Integer | DefineType::Number => Datatype::CFixedPoint,
40            DefineType::Date => Datatype::Date,
41            DefineType::String
42            | DefineType::Item(_)
43            | DefineType::SingleQuotedItem(_)
44            | DefineType::Choice(_) => Datatype::CString,
45            DefineType::UnknownList
46            | DefineType::IntegerList
47            | DefineType::NumberList
48            | DefineType::StringList
49            | DefineType::ItemList(_)
50            | DefineType::ItemOrEmptyList(_) => Datatype::Unknown,
51            DefineType::Color3 => Datatype::CVector3f,
52            DefineType::Color => Datatype::CVector4f,
53        }
54    }
55}
56
57impl DefineType {
58    pub fn validate(self, bv: &BV, data: &Everything) {
59        match self {
60            DefineType::Boolean => {
61                if let Some(token) = bv.expect_value() {
62                    if !token.is("yes") && !token.is("no") {
63                        let msg = "expected `yes` or `no`";
64                        err(ErrorKey::Validation).msg(msg).loc(token).push();
65                    }
66                }
67            }
68            DefineType::Integer => {
69                bv.expect_value().map(Token::expect_integer);
70            }
71            DefineType::Number => {
72                bv.expect_value().map(Token::expect_precise_number);
73            }
74            DefineType::Date => {
75                bv.expect_value().map(Token::expect_date);
76            }
77            DefineType::String => {
78                bv.expect_value();
79            }
80            DefineType::Item(itype) => {
81                if let Some(token) = bv.expect_value() {
82                    if !(itype == Item::Sound && token.as_str().is_empty()) {
83                        data.verify_exists(itype, token);
84                    }
85                }
86            }
87            DefineType::SingleQuotedItem(itype) => {
88                if let Some(token) = bv.expect_value() {
89                    if let Some(sfx) = token.strip_prefix("'") {
90                        if let Some(bare) = sfx.strip_suffix("'") {
91                            data.verify_exists(itype, &bare);
92                        }
93                    }
94                }
95            }
96            DefineType::Choice(choices) => {
97                if let Some(token) = bv.expect_value() {
98                    if !choices.contains(&token.as_str()) {
99                        let msg = format!("expected one of {}", choices.join(", "));
100                        err(ErrorKey::Choice).msg(msg).loc(token).push();
101                    }
102                }
103            }
104            DefineType::UnknownList | DefineType::StringList => {
105                bv.expect_block();
106            }
107            DefineType::IntegerList => {
108                if let Some(block) = bv.expect_block() {
109                    let mut vd = Validator::new(block, data);
110                    for value in vd.values() {
111                        value.expect_integer();
112                    }
113                }
114            }
115            DefineType::NumberList => {
116                if let Some(block) = bv.expect_block() {
117                    let mut vd = Validator::new(block, data);
118                    for value in vd.values() {
119                        value.expect_precise_number();
120                    }
121                }
122            }
123            DefineType::ItemList(itype) => {
124                if let Some(block) = bv.expect_block() {
125                    let mut vd = Validator::new(block, data);
126                    for value in vd.values() {
127                        data.verify_exists(itype, value);
128                    }
129                }
130            }
131            DefineType::ItemOrEmptyList(itype) => {
132                if let Some(block) = bv.expect_block() {
133                    let mut vd = Validator::new(block, data);
134                    for value in vd.values() {
135                        if !value.as_str().is_empty() {
136                            data.verify_exists(itype, value);
137                        }
138                    }
139                }
140            }
141            DefineType::Color => {
142                if let Some(block) = bv.expect_block() {
143                    let mut vd = Validator::new(block, data);
144                    let mut count = 0;
145                    for value in vd.values() {
146                        value.expect_precise_number();
147                        count += 1;
148                    }
149                    if count != 4 {
150                        let msg = "expected exactly 4 values for color";
151                        warn(ErrorKey::Colors).msg(msg).loc(block).push();
152                    }
153                }
154            }
155            DefineType::Color3 => {
156                if let Some(block) = bv.expect_block() {
157                    let mut vd = Validator::new(block, data);
158                    let mut count = 0;
159                    for value in vd.values() {
160                        value.expect_precise_number();
161                        count += 1;
162                    }
163                    if count != 3 {
164                        let msg = "expected exactly 3 values for this color";
165                        warn(ErrorKey::Colors).msg(msg).loc(block).push();
166                    }
167                }
168            }
169        }
170    }
171}