equation_solver/
parse.rs

1use crate::{
2    error::{EquationError, EquationErrorType},
3    item::Item,
4    item::{FunctionalOperator, LeftAssociativeOperator},
5};
6
7/// A parse stream represents a string that is to be parsed into an equation.
8#[derive(Debug)]
9pub struct ParseStream(String);
10
11impl ParseStream {
12    /// Creates a new parse stream from a string.
13    pub fn new(stream: String) -> ParseStream {
14        ParseStream(stream)
15    }
16    /// Parses all items in the parse stream into a [`Vec<Item>`](crate::item::Item).
17    pub fn parse_items(&self) -> Result<Vec<Item>, EquationError> {
18        let mut depths: Vec<(Vec<Item>, Option<char>)> = Vec::new();
19        depths.push((Vec::new(), None));
20        let mut i = 0;
21        let mut current_numeric: Option<String> = None;
22        while i < self.0.len() {
23            let current_group = depths.last_mut().unwrap();
24            let c = self.0.chars().nth(i).ok_or(EquationError::new(
25                "Unexpected end of stream".to_string(),
26                EquationErrorType::UnexpectedToken,
27            ))?;
28            i += 1;
29
30            match (&current_numeric, c) {
31                (Some(val), c) if c == '.' || c.is_numeric() => {
32                    current_numeric = Some(
33                        {
34                            let mut x = val.clone();
35                            x.push(c);
36                            x
37                        }
38                        .to_owned(),
39                    );
40                    continue;
41                }
42                (None, c) if c.is_numeric() => {
43                    current_numeric = Some(c.to_string());
44                    continue;
45                }
46                (Some(val), _) => {
47                    current_group.0.push(Item::Value(val.parse().map_err(|_| {
48                        EquationError::new(
49                            "Invalid number".to_string(),
50                            EquationErrorType::UnexpectedToken,
51                        )
52                    })?));
53                    current_numeric = None;
54                    i -= 1;
55                    continue;
56                }
57                (None, c) if c.is_alphabetic() => {
58                    // peak the next character
59                    let mut temp_i = i;
60                    while temp_i < self.0.len() {
61                        let temp_c = self.0.chars().nth(temp_i).ok_or(EquationError::new(
62                            "Unexpected end of stream".to_string(),
63                            EquationErrorType::UnexpectedToken,
64                        ))?;
65                        temp_i += 1;
66                        if temp_c.is_alphabetic() {
67                            continue;
68                        } else {
69                            break;
70                        }
71                    }
72                    // special case
73                    if temp_i >= self.0.len() - 1 {
74                        temp_i = self.0.len() + 1;
75                    }
76                    let var_name = self.0.get((i - 1)..(temp_i - 1)).unwrap();
77                    // dbg!(var_name, &self.0, i, temp_i, self.0.len());
78                    current_group.0.push(match var_name {
79                        "log" => FunctionalOperator::Log.into(),
80                        "ln" => FunctionalOperator::Ln.into(),
81                        "sin" => FunctionalOperator::Sin.into(),
82                        "cos" => FunctionalOperator::Cos.into(),
83                        "tan" => FunctionalOperator::Tan.into(),
84                        "cot" => FunctionalOperator::Cot.into(),
85                        "sec" => FunctionalOperator::Sec.into(),
86                        "csc" => FunctionalOperator::Csc.into(),
87                        "arcsin" => FunctionalOperator::Arcsin.into(),
88                        "arccos" => FunctionalOperator::Arccos.into(),
89                        "arctan" => FunctionalOperator::Arctan.into(),
90                        "arccot" => FunctionalOperator::Arccot.into(),
91                        "arcsec" => FunctionalOperator::Arcsec.into(),
92                        "arccsc" => FunctionalOperator::Arccsc.into(),
93                        _ => var_name.to_string().into(),
94                    });
95                    i = temp_i - 1;
96                }
97                (None, c) if c == '(' || c == '[' => {
98                    depths.push((Vec::new(), Some(if c == '(' { ')' } else { ']' })));
99                }
100                (None, c) if Some(c) == current_group.1 => {
101                    let current_group = depths.pop().unwrap();
102                    if let Some(parent_group) = depths.last_mut() {
103                        parent_group.0.push(current_group.0.into());
104                    }
105                }
106                (None, c) => current_group.0.push(match c {
107                    '+' => LeftAssociativeOperator::Add.into(),
108                    '-' => LeftAssociativeOperator::Subtract.into(),
109                    '*' => LeftAssociativeOperator::Multiply.into(),
110                    '/' => LeftAssociativeOperator::Divide.into(),
111                    '^' => LeftAssociativeOperator::Power.into(),
112                    ' ' => continue,
113                    _ => {
114                        return Err(EquationError::new(
115                            "Unexpected token".to_string(),
116                            EquationErrorType::UnexpectedToken,
117                        ))
118                    }
119                }),
120            }
121
122            if c.is_numeric() && current_numeric.is_some() || c == '.' {
123                continue;
124            } else if c.is_numeric() {
125                current_numeric = Some(c.to_string());
126                continue;
127            }
128
129            if c == ' ' {
130                continue;
131            }
132        }
133        if let Some(val) = current_numeric {
134            depths
135                .last_mut()
136                .unwrap()
137                .0
138                .push(Item::Value(val.parse().map_err(|_| {
139                    EquationError::new(
140                        "Invalid number".to_string(),
141                        EquationErrorType::UnexpectedToken,
142                    )
143                })?));
144        }
145        if depths.len() != 1 {
146            return Err(EquationError::new(
147                "Unexpected end of stream (Missing Closing Delimiter)".to_string(),
148                EquationErrorType::MissingItems,
149            ));
150        }
151        Ok(depths.pop().unwrap().0)
152    }
153}