gsbl/
lib.rs

1#[cfg(test)]
2mod tests;
3
4use std::fs::read_to_string;
5
6use lexer::tokenize;
7use token::{Token, TokenType};
8use std::slice::Iter;
9
10mod lexer;
11mod token;
12
13#[derive(Debug, PartialEq)]
14pub enum GsblError {
15    FailedToParseFile(String),
16    FailedToParseArray(String),
17    MalformedCode(String),
18}
19
20#[derive(Debug, PartialEq, Clone)]
21enum GsblValueType {
22    String,
23    Int,
24    Float,
25    Bool,
26    Table,
27    Array,
28}
29
30#[derive(Debug, PartialEq, Clone)]
31enum GsblValue {
32    String(String),
33    Int(i32),
34    Float(f32),
35    Bool(bool),
36    Table(GsblTable),
37    Array(Vec<GsblValue>)
38}
39
40#[derive(Debug, PartialEq, Clone)]
41struct Data {
42    name: String,
43    value: GsblValue,
44    value_type: GsblValueType
45}
46
47#[derive(Debug, PartialEq, Clone)]
48pub struct GsblTable { // this is used as a variable type, so it's named GSBL and not Table
49    data: Vec<Data>
50}
51
52impl GsblTable {
53    fn expect<'a>(tokens: &'a mut Iter<Token>, token_type: TokenType) -> Result<&'a Token, GsblError> {
54        let token = tokens.next().unwrap();
55        if token.token_type != token_type {
56            return Err(GsblError::MalformedCode(format!("Expected token {:?}, but found {:?}", token_type, token.token_type)));
57        }
58        Ok(token)
59    }
60
61    fn parse_table<'a>(
62        tokens: &'a mut Iter<Token>,
63        mut token: &'a Token
64    ) -> Result<GsblTable, GsblError> {
65        let mut table_data = Vec::new();
66
67        while token.token_type != TokenType::CloseBrace
68              && token.token_type != TokenType::EndOfFile {
69            if token.token_type == TokenType::Identifier {
70                table_data.push(Self::parse_variable(tokens, &token)?);
71            }
72            token = tokens.next().unwrap();
73        }
74
75        if token.token_type == TokenType::EndOfFile {
76            return Err(GsblError::MalformedCode("Unterminated table".to_string()));
77        }
78
79        Ok(GsblTable {data: table_data})
80    }
81
82    fn parse_array<'a>(
83        tokens: &'a mut Iter<Token>,
84        mut token: &'a Token
85    ) -> Result<Vec<GsblValue>, GsblError> {
86        let mut array_data = Vec::new();
87
88        let mut array_type = TokenType::Unknown;
89
90        while token.token_type != TokenType::CloseBracket
91            && token.token_type != TokenType::EndOfFile {
92            if array_type == TokenType::Unknown {
93                array_type = token.token_type.clone();
94            }
95            if array_type != token.token_type && token.token_type != TokenType::Comma {
96                return Err(GsblError::MalformedCode("Multiple data types inside array".to_string()));
97            }
98            array_data.push(match token.token_type {
99                TokenType::String => {
100                    GsblValue::String(token.value.clone())
101                },
102                TokenType::Int => {
103                    GsblValue::Int(token.value.parse::<i32>().unwrap())
104                },
105                TokenType::Float => {
106                    GsblValue::Float(token.value.parse::<f32>().unwrap())
107                },
108                TokenType::Bool => {
109                    GsblValue::Bool(token.value == "true")
110                },
111                TokenType::OpenBracket => {
112                    GsblValue::Array(Self::parse_array(tokens, token)?) // recursion, yippee!!
113                },
114                TokenType::Comma => {
115                    token = tokens.next().unwrap();
116                    continue;
117                }
118                _ => { return Err(GsblError::FailedToParseArray(format!("Unknown token inside array declaration: {:?}", token.token_type))); }
119            });
120            token = tokens.next().unwrap();
121        }
122
123        if token.token_type == TokenType::EndOfFile {
124            return Err(GsblError::MalformedCode("Unterminated array".to_string()));
125        }
126
127        Ok(array_data)
128    }
129
130    fn parse_variable<'a>(
131        tokens: &'a mut Iter<Token>,
132        mut token: &'a Token
133    ) -> Result<Data, GsblError> {
134        let var_name = token.value.clone();
135
136        Self::expect(tokens, TokenType::Equals)?;
137        token = tokens.next().unwrap();
138
139        let value_type: GsblValueType;
140
141        let data = Data {
142            name: var_name,
143            value: match token.token_type {
144                TokenType::String => {
145                    value_type = GsblValueType::String;
146                    GsblValue::String(token.value.clone())
147                },
148                TokenType::Int => {
149                    value_type = GsblValueType::Int;
150                    GsblValue::Int(token.value.parse::<i32>().unwrap())
151                },
152                TokenType::Float => {
153                    value_type = GsblValueType::Float;
154                    GsblValue::Float(token.value.parse::<f32>().unwrap())
155                },
156                TokenType::Bool => {
157                    value_type = GsblValueType::Bool;
158                    GsblValue::Bool(token.value == "true")
159                },
160                TokenType::OpenBrace => {
161                    token = tokens.next().unwrap();
162                    value_type = GsblValueType::Table;
163                    GsblValue::Table(Self::parse_table(tokens, token)?)
164                },
165                TokenType::OpenBracket => {
166                    token = tokens.next().unwrap();
167                    value_type = GsblValueType::Array;
168                    GsblValue::Array(Self::parse_array(tokens, token)?)
169                }
170                _ => { return Ok(Data { value: GsblValue::Int(0), value_type: GsblValueType::Int, name: "coolplaceholder".to_string()}); }
171            },
172                    value_type
173        };
174
175        Ok(data)
176    }
177
178    pub fn parse_file(file_path: &str) -> Result<Self, GsblError> {
179        let tokens = tokenize(&read_to_string(file_path).unwrap());
180
181        if !tokens.is_ok() {
182            return Err(tokens.unwrap_err());
183        }
184
185        let tokens = tokens.unwrap();
186        let mut tokens = tokens.iter();
187
188        let mut table: GsblTable = GsblTable { data: Vec::new() };
189
190        while let Some(token) = tokens.next() {
191            if token.token_type == TokenType::EndOfFile {
192                break;
193            }
194
195            if token.token_type == TokenType::MultilineComment || token.token_type == TokenType::Comment {
196                continue;
197            }
198            
199            if token.token_type == TokenType::OpenBrace {
200                table = Self::parse_table(&mut tokens, token)?;
201                break;
202            }
203        }
204        Ok(table)
205    }
206
207    
208    fn get_value<T>(&self, var_name: &str, value_type: GsblValueType, map_fn: impl Fn(&GsblValue) -> Option<T>) -> Option<T> {
209        for e in &self.data {
210            if e.name == var_name && e.value_type == value_type {
211                return map_fn(&e.value);
212            }
213        }
214        None
215    }
216
217    fn get_array<T>(&self, var_name: &str, map_fn: impl Fn(&GsblValue) -> Option<T>) -> Option<Vec<T>> {
218        for e in &self.data {
219            if e.name == var_name && e.value_type == GsblValueType::Array {
220                if let GsblValue::Array(a) = &e.value {
221                    return Some(
222                        a.iter()
223                            .filter_map(|value| map_fn(value))
224                            .collect()
225                    );
226                }
227            }
228        }
229        None
230    }
231
232    pub fn get_table(&self, var_name: &str) -> Option<GsblTable> {
233        self.get_value(var_name, GsblValueType::Table, |v| {
234            if let GsblValue::Table(t) = v {
235                Some((*t).clone())
236            } else {
237                None
238            }
239        })
240    }
241
242    pub fn get_string(&self, var_name: &str) -> Option<String> {
243        self.get_value(var_name, GsblValueType::String, |v| {
244            if let GsblValue::String(s) = v {
245                Some((*s).clone())
246            } else {
247                None
248            }
249        })
250    }
251
252    pub fn get_string_array(&self, var_name: &str) -> Option<Vec<String>> {
253        self.get_array(var_name, |v| {
254            if let GsblValue::String(s) = v {
255                Some((*s).clone())
256            } else {
257                None
258            }
259        })
260    }
261
262    pub fn get_int(&self, var_name: &str) -> Option<i32> {
263        self.get_value(var_name, GsblValueType::Int, |v| {
264            if let GsblValue::Int(i) = v {
265                Some(*i)
266            } else {
267                None
268            }
269        })
270    }
271
272    pub fn get_int_array(&self, var_name: &str) -> Option<Vec<i32>> {
273        self.get_array(var_name, |v| {
274            if let GsblValue::Int(i) = v {
275                Some(*i)
276            } else {
277                None
278            }
279        })
280    }
281
282    pub fn get_float(&self, var_name: &str) -> Option<f32> {
283        self.get_value(var_name, GsblValueType::Float, |v| {
284            if let GsblValue::Float(f) = v {
285                Some(*f)
286            } else {
287                None
288            }
289        })
290    }
291
292    pub fn get_float_array(&self, var_name: &str) -> Option<Vec<f32>> {
293        self.get_array(var_name, |v| {
294            if let GsblValue::Float(f) = v {
295                Some(*f)
296            } else {
297                None
298            }
299        })
300    }
301
302    pub fn get_bool(&self, var_name: &str) -> Option<bool> {
303        self.get_value(var_name, GsblValueType::Bool, |v| {
304            if let GsblValue::Bool(b) = v {
305                Some(*b)
306            } else {
307                None
308            }
309        })
310    }
311
312    pub fn get_bool_array(&self, var_name: &str) -> Option<Vec<bool>> {
313        self.get_array(var_name, |v| {
314            if let GsblValue::Bool(b) = v {
315                Some(*b)
316            } else {
317                None
318            }
319        })
320    }
321}