teolang/program/
mod.rs

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) = &params[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) = &params[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}