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 { 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)?) },
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}