1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
 * smartcalc v1.0.8
 * Copyright (c) Erhan BARIS (Ruslan Ognyanov Asenov)
 * Licensed under the GNU General Public License v2.0.
 */


use alloc::rc::Rc;

use crate::compiler::date::DateItem;
use crate::compiler::date_time::DateTimeItem;
use crate::compiler::duration::DurationItem;
use crate::compiler::money::MoneyItem;
use crate::compiler::dynamic_type::DynamicTypeItem;
use crate::compiler::number::NumberItem;
use crate::compiler::percent::PercentItem;
use crate::compiler::time::TimeItem;
use crate::types::*;
use crate::syntax::util::*;
use crate::syntax::{SyntaxParser, SyntaxParserTrait};
use crate::syntax::binary::AddSubtractParser;
use core::ops::Deref;

pub struct PrimativeParser;

impl PrimativeParser {
    pub fn parse_basic_primatives(parser: &mut SyntaxParser) -> AstResult {
        let index_backup = parser.get_index();
        let token = parser.peek_token();

        if token.is_err() {
            return Err(("No more token", 0, 0));
        }

        let result = match token.unwrap().deref() {
            TokenType::Timezone(_, _) |
            TokenType::Text(_)   => {
                parser.consume_token();
                return Ok(SmartCalcAstType::None);
            },
            TokenType::DynamicType(number, dynamic_type)     => Ok(SmartCalcAstType::Item(Rc::new(DynamicTypeItem(*number, dynamic_type.clone())))),
            TokenType::Money(price, currency)     => Ok(SmartCalcAstType::Item(Rc::new(MoneyItem(*price, currency.clone())))),
            TokenType::Number(double, number_type)     => Ok(SmartCalcAstType::Item(Rc::new(NumberItem(*double, *number_type)))),
            TokenType::Field(field_type)  => Ok(SmartCalcAstType::Field(field_type.clone())),
            TokenType::Percent(percent)   => Ok(SmartCalcAstType::Item(Rc::new(PercentItem(*percent)))),
            TokenType::Time(time, tz)         => Ok(SmartCalcAstType::Item(Rc::new(TimeItem(*time, tz.clone())))),
            TokenType::Date(date, tz)         => Ok(SmartCalcAstType::Item(Rc::new(DateItem(*date, tz.clone())))),
            TokenType::DateTime(date_time, tz)         => Ok(SmartCalcAstType::Item(Rc::new(DateTimeItem(*date_time, tz.clone())))),
            TokenType::Duration(duration)         => Ok(SmartCalcAstType::Item(Rc::new(DurationItem(*duration)))),
            TokenType::Variable(variable) => Ok(SmartCalcAstType::Variable(variable.clone())),
            _ => {
                parser.consume_token();
                return Err(("No more token", 0, 0));
            }
        };

        match result {
            Ok(SmartCalcAstType::None) => {
                parser.set_index(index_backup);
                Ok(SmartCalcAstType::None)
            },
            Ok(ast) => {
                parser.consume_token();
                Ok(ast)
            },
            Err((message, line, column)) => Err((message, line, column))
        }
    }

    pub fn parse_parenthesis(parser: &mut SyntaxParser) -> AstResult {
        let index_backup = parser.get_index();
        if parser.match_operator(&['(']).is_some() {
            
            let ast = AddSubtractParser::parse(parser);
            if is_ast_empty(&ast) {
                parser.set_index(index_backup);
                return err_or_message(&ast, "Invalid expression");
            }

            if parser.match_operator(&[')']).is_none() {
                parser.set_index(index_backup);
                return Err(("Parentheses not closed", 0, 0));
            }

            return Ok(ast.unwrap());
        }

        parser.set_index(index_backup);
        Ok(SmartCalcAstType::None)
    }
}

impl SyntaxParserTrait for PrimativeParser {
    fn parse(parser: &mut SyntaxParser) -> AstResult {
        map_parser(parser, &[Self::parse_parenthesis, Self::parse_basic_primatives])
    }
}