smartcalc/compiler/
mod.rs

1/*
2 * smartcalc v1.0.8
3 * Copyright (c) Erhan BARIS (Ruslan Ognyanov Asenov)
4 * Licensed under the GNU General Public License v2.0.
5 */
6
7use core::any::Any;
8use core::any::TypeId;
9use core::ops::Deref;
10
11use alloc::rc::Rc;
12use alloc::string::String;
13use alloc::string::ToString;
14use alloc::format;
15
16use crate::session::Session;
17use crate::config::SmartCalcConfig;
18use crate::types::*;
19use crate::variable::VariableInfo;
20
21pub mod number;
22pub mod percent;
23pub mod money;
24pub mod time;
25pub mod duration;
26pub mod date;
27pub mod date_time;
28pub mod dynamic_type;
29
30#[derive(Clone)]
31#[derive(Copy)]
32pub enum OperationType {
33    Add,
34    Div,
35    Mul,
36    Sub
37}
38
39
40#[derive(Clone)]
41#[derive(Copy)]
42pub enum UnaryType {
43    Plus,
44    Minus
45}
46
47pub trait DataItem: alloc::fmt::Debug {
48    fn unary(&self, unary: UnaryType) -> Rc<dyn DataItem>;
49    fn is_same(&self, other: &dyn Any) -> bool;
50    fn as_token_type(&self) -> TokenType;
51    fn as_any(&self) -> &dyn Any;
52    fn get_number(&self, other: &dyn DataItem) -> f64;
53    fn get_underlying_number(&self) -> f64;
54    fn type_name(&self) -> &'static str;
55    fn type_id(&self) -> TypeId;
56    fn calculate(&self, config: &SmartCalcConfig, on_left: bool, other: &dyn DataItem, operation_type: OperationType) -> Option<Rc<dyn DataItem>>;
57    fn print(&self, config: &SmartCalcConfig, session: &Session) -> String;
58}
59
60pub struct Interpreter;
61
62impl Interpreter {
63    pub fn execute(config: &SmartCalcConfig, ast: Rc<SmartCalcAstType>, session: &Session) -> Result<Rc<SmartCalcAstType>, String> {
64        Interpreter::execute_ast(config, session, ast)
65    }
66
67    fn execute_ast(config: &SmartCalcConfig, session: &Session, ast: Rc<SmartCalcAstType>) -> Result<Rc<SmartCalcAstType>, String> {
68        match ast.deref() {
69            SmartCalcAstType::Binary { left, operator, right } => Interpreter::executer_binary(config, session, left.clone(), *operator, right.clone()),
70            SmartCalcAstType::Assignment { variable, expression } => Interpreter::executer_assignment(config, session, variable.clone(), expression.clone()),
71            SmartCalcAstType::Variable(variable)               => Ok(Interpreter::executer_variable(variable.clone())),
72            SmartCalcAstType::Item(_)                          => Ok(ast),
73            SmartCalcAstType::Month(_)                         => Ok(ast),
74            SmartCalcAstType::PrefixUnary(ch, ast)             => Interpreter::executer_unary(config, session, *ch, ast.clone()),
75            SmartCalcAstType::None                             => Ok(Rc::new(SmartCalcAstType::None)),
76            _ => {
77                log::debug!("Operation not implemented {:?}", ast);
78                Ok(Rc::new(SmartCalcAstType::None))
79            }
80        }
81    }
82
83    fn executer_variable(variable: Rc<VariableInfo>) -> Rc<SmartCalcAstType> {
84        variable.data.borrow().clone()
85    }
86
87    fn executer_assignment(config: &SmartCalcConfig, session: &Session, variable: Rc<VariableInfo>, expression: Rc<SmartCalcAstType>) -> Result<Rc<SmartCalcAstType>, String> {
88        let computed  = Interpreter::execute_ast(config, session, expression)?;
89        *variable.data.borrow_mut() = computed.clone();
90        Ok(computed)
91    }
92    
93    fn calculate_item(config: &SmartCalcConfig, operator: char, left: Rc<SmartCalcAstType>, right: Rc<SmartCalcAstType>) -> Result<Rc<SmartCalcAstType>, String> {
94        let left = match left.deref() {
95            SmartCalcAstType::Item(left) => left.clone(),
96            _ => return Err("Unknown calculation".to_string())
97        };
98        
99        let right = match right.deref() {
100            SmartCalcAstType::Item(right) => right.clone(),
101            _ => return Err("Unknown calculation".to_string())
102        };
103        
104        let result = match operator {
105            '+' => left.calculate(config, true, right.deref(), OperationType::Add),
106            '-' => left.calculate(config, true, right.deref(), OperationType::Sub),
107            '*' => left.calculate(config, true, right.deref(), OperationType::Mul),
108            '/' => left.calculate(config, true, right.deref(), OperationType::Div),
109            _ => return Err(format!("Unknown operator. ({})", operator))
110        };
111        
112        match result {
113            Some(item) => Ok(Rc::new(SmartCalcAstType::Item(item.clone()))),
114            None => Err("Unknown calculation".to_string())
115        }
116    }
117
118    fn executer_binary(config: &SmartCalcConfig, session: &Session, left: Rc<SmartCalcAstType>, operator: char, right: Rc<SmartCalcAstType>) -> Result<Rc<SmartCalcAstType>, String> {
119        let computed_left  = Interpreter::execute_ast(config, session, left)?;
120        let computed_right = Interpreter::execute_ast(config, session, right)?;
121
122        match (computed_left.deref(), computed_right.deref()) {
123            (SmartCalcAstType::Item(_), _)           | (_, SmartCalcAstType::Item(_))           => Interpreter::calculate_item(config, operator, computed_left.clone(), computed_right.clone()),
124            _ => Err("Uknown calculation result".to_string())
125        }
126    }
127
128    fn executer_unary(config: &SmartCalcConfig, session: &Session, operator: char, ast: Rc<SmartCalcAstType>) -> Result<Rc<SmartCalcAstType>, String> {
129        let computed = Interpreter::execute_ast(config, session, ast)?;
130
131        let result = match operator {
132            '+' => return Ok(computed),
133            '-' => match computed.deref() {
134                SmartCalcAstType::Item(item) => SmartCalcAstType::Item(item.unary(UnaryType::Minus)),
135                _ => return Err("Syntax error".to_string())
136            },
137            _ => return Err("Syntax error".to_string())
138        };
139
140        Ok(Rc::new(result))
141    }
142}