asciimath/
parser.rs

1use crate::{
2    ast::{Args, Evaluate, EvaluationResult, Node, Root, Scope},
3    error::Error,
4    lexer::tokenize,
5    tokens::{Operator, Token, TokenList},
6};
7use std::{collections::VecDeque, string::ToString};
8
9type NodeList = Vec<Node>;
10
11pub fn eval(expr: &str, scope: &Scope) -> EvaluationResult {
12    parse_tokens(tokenize(expr, scope)?, scope)?.eval()
13}
14
15pub fn compile<'a>(expr: &'a str, scope: &'a Scope) -> Result<Root<'a>, Error> {
16    parse_tokens(tokenize(expr, scope)?, scope)
17}
18
19fn encounter_func(f: String, operands: &mut NodeList) -> Result<(), Error> {
20    let mut args = Args::with_capacity(2);
21
22    // ASSUMPTION: at least one argument per function
23    args.push_front(
24        operands
25            .pop()
26            .ok_or(Error::NotEnoughFunctionParams(f.clone()))?,
27    );
28
29    while let Some(last) = operands.pop() {
30        if last.token != Token::Comma {
31            operands.push(last);
32            break;
33        }
34        else {
35            args.push_front(
36                operands
37                    .pop()
38                    .ok_or(Error::FunctionSyntaxError(f.clone()))?,
39            );
40        }
41    }
42
43    operands.push(Node::new(Token::Function(f), Some(args)));
44    Ok(())
45}
46
47fn right_paren(
48    operators: &mut TokenList,
49    operands: &mut NodeList,
50) -> Result<(), Error> {
51    while let Some(top) = operators.pop() {
52        match top {
53            Token::LeftParenthesis => match operators.last() {
54                Some(Token::Function(_)) => {},
55                _ => break,
56            },
57            Token::Function(f) => encounter_func(f, operands)?,
58            Token::Operator(op) => add_operator(op, operands)?,
59            _ => {},
60        }
61    }
62    Ok(())
63}
64
65fn add_operator(
66    operator: Operator,
67    operands: &mut NodeList,
68) -> Result<(), Error> {
69    let num_operands = operator.num_operands();
70
71    let mut args: VecDeque<Node> =
72        VecDeque::with_capacity(num_operands as usize);
73
74    for _ in 0..num_operands {
75        args.push_front(
76            operands
77                .pop()
78                .ok_or(Error::MissingOperands(operator.to_string()))?,
79        );
80    }
81    operands.push(Node::new(Token::Operator(operator), Some(args)));
82    Ok(())
83}
84
85fn encounter_operator(
86    cur_operator: Operator,
87    operators: &mut TokenList,
88    operands: &mut NodeList,
89) -> Result<(), Error> {
90    while let Some(top) = operators.pop() {
91        match top {
92            Token::Operator(top_operator) => {
93                if top_operator > cur_operator
94                    || (top_operator == cur_operator
95                        && !cur_operator.is_right_associative())
96                {
97                    add_operator(top_operator, operands)?
98                }
99                else {
100                    operators.push(Token::Operator(top_operator));
101                    break;
102                }
103            },
104            Token::Function(f) => encounter_func(f, operands)?,
105            _ => {
106                operators.push(top);
107                break;
108            },
109        }
110    }
111
112    operators.push(Token::Operator(cur_operator));
113    Ok(())
114}
115
116fn parse_tokens(tokens: TokenList, scope: &Scope) -> Result<Root, Error> {
117    let mut operators: TokenList = Vec::new();
118    let mut operands: NodeList = Vec::new();
119
120    for token in tokens {
121        match token {
122            Token::Number(num) => operands.push(Node {
123                token: Token::Number(num),
124                args: None,
125            }),
126            Token::Variable(var) => operands.push(Node {
127                token: Token::Variable(var),
128                args: None,
129            }),
130            Token::RightParenthesis => {
131                right_paren(&mut operators, &mut operands)?
132            },
133            Token::LeftParenthesis => operators.push(token),
134            Token::Operator(op1) => {
135                encounter_operator(op1, &mut operators, &mut operands)?;
136            },
137            Token::Function(f) => operators.push(Token::Function(f)),
138            Token::Comma => operands.push(Node::new(token, None)),
139        };
140    }
141
142    while let Some(Token::Operator(operator)) = operators.pop() {
143        add_operator(operator, &mut operands)?
144    }
145
146    // TODO: revisit this when the final output can also be a string
147    operands.pop().map_or_else(
148        || Err(Error::EmptyExpression),
149        |node| Ok(Root { node, scope }),
150    )
151}