Skip to main content

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                    && !token.is("yes")
63                    && !token.is("no")
64                {
65                    let msg = "expected `yes` or `no`";
66                    err(ErrorKey::Validation).msg(msg).loc(token).push();
67                }
68            }
69            DefineType::Integer => {
70                bv.expect_value().map(Token::expect_integer);
71            }
72            DefineType::Number => {
73                bv.expect_value().map(Token::expect_precise_number);
74            }
75            DefineType::Date => {
76                bv.expect_value().map(Token::expect_date);
77            }
78            DefineType::String => {
79                bv.expect_value();
80            }
81            DefineType::Item(itype) => {
82                if let Some(token) = bv.expect_value()
83                    && !(itype == Item::Sound && token.as_str().is_empty())
84                {
85                    data.verify_exists(itype, token);
86                }
87            }
88            DefineType::SingleQuotedItem(itype) => {
89                if let Some(token) = bv.expect_value()
90                    && let Some(sfx) = token.strip_prefix("'")
91                    && let Some(bare) = sfx.strip_suffix("'")
92                {
93                    data.verify_exists(itype, &bare);
94                }
95            }
96            DefineType::Choice(choices) => {
97                if let Some(token) = bv.expect_value()
98                    && !choices.contains(&token.as_str())
99                {
100                    let msg = format!("expected one of {}", choices.join(", "));
101                    err(ErrorKey::Choice).msg(msg).loc(token).push();
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}