1use crate::util::shell::Shell;
2use anyhow::{anyhow, Result};
3use rust_decimal::prelude::*;
4use rust_decimal_macros::dec;
5use std::collections::HashMap;
6
7pub mod parser;
8pub struct Program {
9 pub commands: parser::Ast,
10 pub current_line: usize,
11 pub variable: HashMap<String, Data>,
12 pub function: HashMap<String, parser::Ast>,
13 pub std_commands: Vec<String>,
14}
15
16#[derive(Clone, PartialEq, Debug)]
17pub enum Data {
18 String(String),
19 Number(Decimal),
20 Array(Vec<Data>),
21 Bool(bool),
22}
23
24impl Data {
25 fn as_number(&self) -> Decimal {
26 match self {
27 Data::Number(i) => *i,
28 Data::Bool(b) => {
29 if *b {
30 dec!(1)
31 } else {
32 dec!(0)
33 }
34 }
35 _ => panic!("Data is not convertable"),
36 }
37 }
38 fn as_string(&self) -> String {
39 match self {
40 Data::Number(i) => i.normalize().to_string(),
41 Data::String(i) => i.clone(),
42 Data::Bool(b) => b.to_string(),
43 _ => panic!("Data is not convertable"),
44 }
45 }
46}
47
48macro_rules! matchcmd {
49 ($id:expr, $errmessage:expr, {$($function:expr => $body:block),+}) => {
50 match $id.as_str() {
51 $(
52 #[cfg(feature = $function)]
53 $function => $body,
54 )+
55 _ => Err(anyhow!($errmessage)),
56 }
57 };
58}
59
60macro_rules! fep {
61 ($program:ident, $args:expr, $parseto:ident, $writer:ident $body:block) => {
62 for arg in $args {
63 let $parseto = arg.evaluate(&$program, $writer).unwrap();
64 $body
65 }
66 };
67}
68
69macro_rules! unrecov_err {
70 ($shell:ident, $($errormessage:tt)*) => {
71 let mesg = format!($($errormessage)*);
72 let _ = $shell.error(format!("Unrecoverable error: {}", mesg));
73 panic!("Unrecoverable error!")
74 }
75}
76
77impl Program {
78 pub fn run_loop(
79 &mut self,
80 mut writer: &mut impl std::io::Write,
81 shell: &mut Shell,
82 ) -> Result<Data> {
83 match &self.commands {
84 parser::Ast::Block(commands) => {
85 for command in commands {
86 match command.1 {
87 parser::Ast::Set { id, expr } => {
88 let value = expr.evaluate(&self, writer);
89 match id.as_ref() {
90 parser::Ast::ArrayCall { id: array_id, k } => {
91 let index = k
92 .evaluate(&self, writer)
93 .unwrap()
94 .as_number()
95 .to_usize()
96 .unwrap();
97
98 let array = self.variable.get_mut(array_id);
99 if let Some(array) = array {
100 if let Data::Array(elements) = array {
101 elements[index] = value.unwrap();
102 } else {
103 unrecov_err!(
104 shell,
105 "Variable {} is not an array, cannot modify!",
106 array_id
107 );
108 }
109 } else {
110 unrecov_err!(
111 shell,
112 "Variable (array) not found: {}",
113 array_id
114 );
115 }
116 }
117 _ => {
118 self.variable.insert(id.to_string(), value.unwrap());
119 }
120 };
121 }
122 parser::Ast::If { condition, block } => {
123 let conditionresult = condition.evaluate(&self, writer);
124 match conditionresult.unwrap() {
125 Data::Bool(e) => {
126 if e {
127 let mut program = Program {
128 commands: *block.clone(),
129 current_line: 0,
130 variable: self.variable.clone(),
131 function: self.function.clone(),
132 std_commands: self.std_commands.clone(),
133 };
134 if let Ok(_) = program.run_loop(writer, shell) {
135 self.variable = program.variable;
136 } else {
137 panic!("Code block within If-else panicked!");
138 }
139 }
140 }
141 _ => unimplemented!(),
142 };
143 }
144 parser::Ast::FunctionDefinition { id, params, body } => {
145 if self.function.contains_key(id) | self.std_commands.contains(id) {
146 panic!("Function `{}` already exist!", id);
147 }
148 self.function.insert(
149 id.clone(),
150 parser::Ast::FunctionDefinition {
151 id: id.clone(),
152 params: params.clone(),
153 body: body.clone(),
154 },
155 );
156 }
157 parser::Ast::FunctionCall { id, args } => {
158 let std_functions = self.std_commands.clone();
159 if std_functions.contains(id) {
160 matchcmd!(id, "Function isn't enabled.", {
161 "print" => {
162 fep!(self, args, value, writer {
163 println!("{}", value.as_string());
164 write!(&mut writer, "{}", value.as_string()).unwrap();
165 });
166 Ok(Data::Number(dec!(0)))
167 },
168 "return" => {
169 if let Some(arg) = args.first() {
170 let value = arg.evaluate(&self, writer).unwrap();
171 Ok(value)
172 } else {
173 Err(anyhow!("Need to return only one value!"))
174 }
175 }
176 }
177 );
178 } else if let Some(func) = self.function.get(id) {
179 match func {
180 parser::Ast::FunctionDefinition { params, body, .. } => {
181 if params.len() < args.len() {
182 panic!("Too many argument!");
183 }
184 if params.len() > args.len() {
185 panic!("Not enough argument!");
186 }
187 let mut local_variables = HashMap::new();
188 for (i, arg) in args.iter().enumerate() {
189 let (name, dtype) = ¶ms[i];
190 let value = arg.evaluate(&self, writer).unwrap();
191 match dtype.as_str() {
192 "Integer" => {
193 if let Data::Number(_) = value {
194 } else {
195 panic!("Wrong type for function: expected {}!", dtype);
196 }
197 }
198 "String" => {
199 if let Data::String(_) = value {
200 } else {
201 panic!("Wrong type for function: expected {}!", dtype);
202 }
203 }
204 "Array" => {
205 if let Data::Array(_) = value {
206 } else {
207 panic!("Wrong type for function: expected {}!", dtype);
208 }
209 }
210 "Bool" => {
211 if let Data::Bool(_) = value {
212 } else {
213 panic!("Wrong type for function: expected {}!", dtype);
214 }
215 }
216 _ => panic!("Type does not exist: {}! Only types exist are Integer, String, Bool and Array", dtype),
217 }
218 local_variables.insert(name.clone(), value);
219 }
220 let mut program = Program {
221 commands: *body.clone(),
222 current_line: 0,
223 variable: local_variables,
224 function: self.function.clone(),
225 std_commands: self.std_commands.clone(),
226 };
227 if let Ok(returncode) = program.run_loop(writer, shell) {
228 } else {
229 panic!("Function `{}` panicked!", id);
230 }
231 }
232 _ => panic!("`{}` is not a function!", id),
233 }
234 } else {
235 panic!("Function `{}` is not defined!", id);
236 }
237 }
238 _ => {}
239 }
240 }
241 }
242 _ => unimplemented!(),
243 }
244 Ok(Data::Number(dec!(0)))
245 }
246}
247
248trait Evaluate {
249 fn evaluate(&self, program: &Program, writer: &mut impl std::io::Write) -> Result<Data>;
250}
251
252impl Evaluate for parser::Ast {
253 fn evaluate(&self, program: &Program, mut writer: &mut impl std::io::Write) -> Result<Data> {
254 let variables = &program.variable;
255 match self {
256 parser::Ast::Int(i) => Ok(Data::Number(*i)),
257 parser::Ast::Bool(b) => Ok(Data::Bool(*b)),
258 parser::Ast::Identifier(id) => match variables.get(id) {
259 Some(value) => Ok(value.clone()),
260 None => Err(anyhow!("Error: variable not found: {}", id)),
261 },
262 parser::Ast::BinaryOp { op, left, right } => {
263 let left_value = left.evaluate(program, writer).unwrap();
264 let right_value = right.evaluate(program, writer).unwrap();
265 let f1 = left_value.as_number();
266 let f2 = right_value.as_number();
267 match op.as_str() {
268 "+" => Ok(Data::Number(f1 + f2)),
269 "-" => Ok(Data::Number(f1 - f2)),
270 "*" => Ok(Data::Number(f1 * f2)),
271 "/" => Ok(Data::Number(f1 / f2)),
272 "==" => Ok(Data::Bool(f1 == f2)),
273 "!=" => Ok(Data::Bool(f1 != f2)),
274 "<" => Ok(Data::Bool(f1 < f2)),
275 ">" => Ok(Data::Bool(f1 > f2)),
276 "<=" => Ok(Data::Bool(f1 <= f2)),
277 ">=" => Ok(Data::Bool(f1 >= f2)),
278 _ => panic!("{} is not a valid binary operator", op),
279 }
280 }
281 parser::Ast::String(i) => Ok(Data::String(i.clone())),
282 parser::Ast::Array(elements) => {
283 let mut array_data = Vec::new();
284 for element in elements {
285 let element_data = element.evaluate(program, writer).unwrap();
286 array_data.push(element_data);
287 }
288 Ok(Data::Array(array_data))
289 }
290 parser::Ast::ArrayCall { id, k } => {
291 if let Some(array) = variables.get(id) {
292 if let Data::Array(elements) = array {
293 let index = k
294 .evaluate(program, writer)
295 .unwrap()
296 .as_number()
297 .to_usize()
298 .unwrap();
299 if index >= elements.len() {
300 panic!("Error: array index out of bounds");
301 }
302 Ok(elements[index].clone())
303 } else {
304 Err(anyhow!(format!(
305 "Variable {} is not an array, cannot modify!",
306 id
307 )))
308 }
309 } else {
310 panic!("Error: array variable not found: {}", id);
311 }
312 }
313
314 parser::Ast::FunctionCall { id, args } => {
315 let std_functions = program.std_commands.clone();
316 if std_functions.contains(id) {
317 matchcmd!(id, "Function isn't enabled or it can't be evaluated.", {
318 "return" => {
319 if let Some(arg) = args.first() {
320 let value = arg.evaluate(&program, writer).unwrap();
321 Ok(value)
322 } else {
323 Err(anyhow!("Need to return only one value!"))
324 }
325 }
326 }
327 )
328 } else if let Some(func) = program.function.get(id) {
329 match func {
330 parser::Ast::FunctionDefinition { params, body, .. } => {
331 if params.len() < args.len() {
332 panic!("Too many argument!",);
333 }
334 if params.len() > args.len() {
335 panic!("Not enough argument!",);
336 }
337 let mut local_variables = HashMap::new();
338 for (i, arg) in args.iter().enumerate() {
339 let (name, dtype) = ¶ms[i];
340 let value = arg.evaluate(program, writer).unwrap();
341 match dtype.as_str() {
342 "Integer" => {
343 if let Data::Number(_) = value {
344 } else {
345 panic!("Wrong type for function: expected {}!", dtype);
346 }
347 }
348 "String" => {
349 if let Data::String(_) = value {
350 } else {
351 panic!("Wrong type for function: expected {}!", dtype);
352 }
353 }
354 "Array" => {
355 if let Data::Array(_) = value {
356 } else {
357 panic!("Wrong type for function: expected {}!", dtype);
358 }
359 }
360 "Bool" => {
361 if let Data::Bool(_) = value {
362 } else {
363 panic!("Wrong type for function: expected {}!", dtype);
364 }
365 }
366 _ => panic!("Type does not exist: {}! Only types exist are Integer, String, Bool and Array", dtype),
367 }
368 local_variables.insert(name.clone(), value);
369 }
370 let mut program = Program {
371 commands: *body.clone(),
372 current_line: 0,
373 variable: local_variables,
374 function: program.function.clone(),
375 std_commands: program.std_commands.clone(),
376 };
377 if let Ok(returncode) = program.run_loop(writer, &mut Shell::new()) {
378 Ok(returncode)
379 } else {
380 panic!("Function `{}` panicked!", id);
381 }
382 }
383 _ => panic!("`{}` is not a function!", id),
384 }
385 } else {
386 panic!("Function `{}` is not defined!", id);
387 }
388 }
389 _ => panic!("Invalid AST node"),
390 }
391 }
392}