1use 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}