moo_math/
lib.rs

1// order of operations
2// parentheses
3// exponentiation
4// multiplication and division
5// addition and subtraction
6// number | function
7
8mod utils;
9
10use crate::utils::{IIter, Iter};
11use std::collections::HashMap;
12use std::f64;
13
14macro_rules! cast_opt_ok {
15    ($i:expr) => {
16        match $i {
17            Some(e) => e,
18            None => return Ok(None),
19        }
20    };
21}
22
23macro_rules! try_tokenize {
24    ($self:ident,$start:ident,$i:ident,$j:ident) => {{
25        let result = $i($self.source)?;
26        if result.is_some() {
27            let option = result.unwrap();
28            $self.shift(option.1);
29            return Ok(Some((Token::$j(option.0), $start, $self.index)));
30        }
31    }};
32}
33
34macro_rules! try_one_char {
35    ($self:ident,$start:ident,$ch:ident,$i:expr,$j:ident) => {{
36        if $ch == $i {
37            $self.shift(1);
38            return Ok(Some((Token::$j, $self.index - 1, $self.index)));
39        }
40    }};
41}
42
43type Function = fn(f64) -> f64;
44
45#[derive(Debug)]
46pub struct Program {
47    pub body: Expression,
48}
49
50#[derive(Debug)]
51pub enum Expression {
52    Primitive(Primitive),
53    ExpressionOperation((Box<Expression>, char, Box<Expression>)),
54}
55
56#[derive(Debug)]
57pub enum Primitive {
58    Function((Function, Box<Expression>)),
59    Identifier(String),
60    Number(f64),
61}
62
63impl Program {
64    fn run(&self, x: f64) -> f64 {
65        self.body.perform(x, 0.0)
66    }
67    fn runge_kutta(&self, x0: f64, y0: f64, step: f64) -> (f64, f64) {
68        let a1 = step * self.body.perform(x0, y0);
69        let a2 = step * self.body.perform(x0 + step / 2.0, y0 + a1 / 2.0);
70        let a3 = step * self.body.perform(x0 + step / 2.0, y0 + a2 / 2.0);
71        let a4 = step * self.body.perform(x0, y0 + a3);
72        (y0 + (a1 + 2.0 * a2 + 2.0 * a3 + a4) / 6.0, x0 + step)
73    }
74}
75
76impl Primitive {
77    fn typ(&self) -> &'static str {
78        use Primitive::*;
79        match self {
80            Function(_) => "Function",
81            Identifier(_) => "Identifier",
82            Number(_) => "Number",
83        }
84    }
85    fn perform(&self, x: f64, y: f64) -> f64 {
86        use Primitive::*;
87        match self {
88            Function(func) => {
89                (func.0)(func.1.perform(x, y))
90            }
91            Identifier(ident) => {
92                match ident.as_str() {
93                    "x" => x,
94                    "y" => y,
95                    _ => 0.0
96                }
97            }
98            Number(num) => *num
99        }
100    }
101}
102
103impl Expression {
104    fn perform(&self, x: f64, y: f64) -> f64 {
105        use Expression::*;
106        match self {
107            Primitive(primitive) => {
108                primitive.perform(x, y)
109            }
110            ExpressionOperation(expr) => {
111                match expr.1 {
112                    '+' => expr.0.perform(x, y) + expr.2.perform(x, y),
113                    '-' => expr.0.perform(x, y) - expr.2.perform(x, y),
114                    '*' => expr.0.perform(x, y) * expr.2.perform(x, y),
115                    '/' => expr.0.perform(x, y) / expr.2.perform(x, y),
116                    '^' => f64::powf(expr.0.perform(x, y), expr.2.perform(x, y)),
117                    _ => 0.0
118                }
119            }
120        }
121    }
122}
123
124pub enum Token {
125    Identifier(String),
126    Number(f64),
127    Add,
128    Sub,
129    Mult,
130    Div,
131    Pow,
132    LParent,
133    RParent,
134    Comma,
135}
136
137impl Token {
138    fn typ(&self) -> &'static str {
139        use Token::*;
140        match self {
141            Identifier(_) => "Identifier",
142            Number(_) => "Number",
143            Add | Sub | Mult | Div | Pow => "Operator",
144            LParent => "LParent",
145            RParent => "RParent",
146            Comma => "Comma",
147        }
148    }
149    fn to_string(&self) -> String {
150        use Token::*;
151        match self {
152            Number(num) => num.to_string(),
153            Add => "+".to_string(),
154            Sub => "-".to_string(),
155            Mult => "*".to_string(),
156            Div => "/".to_string(),
157            Pow => "^".to_string(),
158            LParent => "(".to_string(),
159            RParent => ")".to_string(),
160            Comma => "Comma".to_string(),
161            Identifier(ident) => ident.to_string(),
162        }
163    }
164}
165
166struct Tokenizer<'a> {
167    index: usize,
168    source: &'a str,
169}
170
171fn takes(source: &str, f: fn(ch: char) -> bool) -> Result<(&str, usize), &str> {
172    let mut i: usize = 0;
173    for ch in source.chars() {
174        if f(ch) {
175            i += 1;
176        } else {
177            break;
178        }
179    }
180    if i == 0 {
181        Err("No Matches".into())
182    } else {
183        Ok((&source[..i], i))
184    }
185}
186
187fn identifier(source: &str) -> Result<Option<(String, usize)>, &str> {
188    let mut i: usize = 0;
189    let mut chars = source.chars();
190    let ch = cast_opt_ok!(chars.next());
191    if !(ch.is_alphabetic() || ch == '_') {
192        return Ok(None);
193    }
194    i += 1;
195    for ch in chars {
196        if ch.is_alphanumeric() || ch == '_' {
197            i += 1;
198        } else {
199            break;
200        }
201    }
202    if i > 0 {
203        Ok(Some((source[..i].to_string(), i)))
204    } else {
205        Ok(None)
206    }
207}
208
209fn number(source: &str) -> Result<Option<(f64, usize)>, &str> {
210    let mut i: usize = 0;
211    let result = integer(source)?;
212    if result.is_none() {
213        return Ok(None);
214    }
215    let int = result.unwrap();
216    i += int.1;
217    let num_str;
218    if i < source.len() {
219        let mut chars = source.get(i..).unwrap().chars();
220        let ch = chars.next().unwrap();
221        if ch == '.' {
222            i += 1;
223            for ch in chars {
224                if ch == '.' {
225                    return Err("Unexpected number");
226                }
227                if ch.is_digit(10) {
228                    i += 1;
229                } else {
230                    break;
231                }
232            }
233            num_str = &source[..i];
234        } else {
235            num_str = int.0;
236        }
237    } else {
238        num_str = int.0;
239    }
240    return match num_str.replace("_", "").parse::<f64>() {
241        Ok(num) => Ok(Some((num, i))),
242        Err(_) => Err("Cannot to parse number"),
243    };
244}
245
246fn integer(source: &str) -> Result<Option<(&str, usize)>, &str> {
247    let mut i: usize = 0;
248    let mut chars = source.chars();
249    let ch = cast_opt_ok!(chars.next());
250    if ch == '0' {
251        return Ok(Some(("0", 1)));
252    }
253    if ch.is_digit(10) {
254        i += 1;
255        for ch in chars {
256            if ch.is_digit(10) || ch == '_' {
257                i += 1;
258            } else {
259                break;
260            }
261        }
262        return Ok(Some((&source[..i], i)));
263    }
264    return Ok(None);
265}
266
267impl<'a> Tokenizer<'a> {
268    fn new(src: &str) -> Tokenizer {
269        Tokenizer {
270            index: 0,
271            source: src,
272        }
273    }
274    fn next(&mut self) -> Result<Option<(Token, usize, usize)>, &str> {
275        if !self.source.is_empty() {
276            self.skip_whitespace();
277            if let Some(ch) = self.source.chars().next() {
278                let start = self.index;
279                try_tokenize!(self, start, number, Number);
280                try_tokenize!(self, start, identifier, Identifier);
281                try_one_char!(self, start, ch, '^', Pow);
282                try_one_char!(self, start, ch, '+', Add);
283                try_one_char!(self, start, ch, '-', Sub);
284                try_one_char!(self, start, ch, '*', Mult);
285                try_one_char!(self, start, ch, '/', Div);
286                try_one_char!(self, start, ch, '(', LParent);
287                try_one_char!(self, start, ch, ')', RParent);
288                try_one_char!(self, start, ch, ',', Comma);
289            }
290            Ok(None)
291        } else {
292            Ok(None)
293        }
294    }
295    fn skip_whitespace(&mut self) {
296        match takes(self.source, |a| a.is_whitespace()) {
297            Ok(e) => {
298                self.shift(e.1);
299            }
300            Err(_) => {}
301        };
302    }
303    fn shift(&mut self, length: usize) {
304        self.source = &self.source[length..];
305        self.index += length;
306    }
307}
308
309pub struct Moo<'a> {
310    functions: HashMap<&'a str, Function>,
311}
312
313impl<'a> Moo<'a> {
314    pub fn new(add_on: fn(functions: &mut HashMap<&str, Function>)) -> Moo<'a> {
315        let mut functions: HashMap<&str, Function> = HashMap::new();
316        functions.insert("sin", |v| {
317            f64::sin(v)
318        });
319        functions.insert("cos", |v| {
320            f64::cos(v)
321        });
322        functions.insert("abs", |v| {
323            f64::abs(v)
324        });
325        add_on(&mut functions);
326        Moo {
327            functions,
328        }
329    }
330    pub fn parse(&self, source: &str) -> Result<Option<Program>, &str> {
331        let mut tokenizer = Tokenizer::new(source);
332        let mut tokens: Vec<(Token, usize, usize)> = Vec::new();
333        loop {
334            let result = tokenizer.next();
335            if result.is_ok() {
336                match result.unwrap() {
337                    Some(token) => {
338                        tokens.push(token);
339                    }
340                    None => break,
341                }
342            } else {
343                break;
344            }
345        }
346        let token_iter = &mut Iter::new(&tokens);
347        Ok(self.ast_program(token_iter)?)
348    }
349    fn ast_program(&self, iter: &mut Iter<(Token, usize, usize)>) -> Result<Option<Program>, &str> {
350        let body = self.ast_additive_expression(iter)?;
351        if body.is_some() {
352            return Ok(Some(Program { body: body.unwrap() }));
353        }
354        return Ok(None);
355    }
356    fn ast_additive_expression(&self, iter: &mut Iter<(Token, usize, usize)>) -> Result<Option<Expression>, &str> {
357        let left = self.ast_multiplicative_expression(iter)?;
358        if left.is_none() {
359            return Ok(None);
360        }
361        if let Some(tnk) = iter.next() {
362            use crate::Token::*;
363            use crate::Expression::*;
364            match tnk.0 {
365                Add => {
366                    let right = self.ast_additive_expression(iter)?;
367                    if right.is_none() {
368                        return Err("ERROR 8");
369                    }
370                    return Ok(Some(ExpressionOperation((Box::new(left.unwrap()), '+', Box::new(right.unwrap())))));
371                }
372                Sub => {
373                    let right = self.ast_additive_expression(iter)?;
374                    if right.is_none() {
375                        return Err("ERROR 7");
376                    }
377                    return Ok(Some(ExpressionOperation((Box::new(left.unwrap()), '-', Box::new(right.unwrap())))));
378                }
379                _ => {
380                    iter.prev();
381                }
382            };
383        }
384        Ok(left)
385    }
386    fn ast_multiplicative_expression(&self, iter: &mut Iter<(Token, usize, usize)>) -> Result<Option<Expression>, &str> {
387        let left = self.ast_exponential_expression(iter)?;
388        if left.is_none() {
389            return Ok(None);
390        }
391        if let Some(tnk) = iter.next() {
392            use crate::Token::*;
393            use crate::Expression::*;
394            match tnk.0 {
395                Mult => {
396                    let right = self.ast_exponential_expression(iter)?;
397                    if right.is_none() {
398                        return Err("ERROR 6");
399                    }
400                    return Ok(Some(ExpressionOperation((Box::new(left.unwrap()), '*', Box::new(right.unwrap())))));
401                }
402                Div => {
403                    let right = self.ast_exponential_expression(iter)?;
404                    if right.is_none() {
405                        return Err("ERROR 5");
406                    }
407                    return Ok(Some(ExpressionOperation((Box::new(left.unwrap()), '/', Box::new(right.unwrap())))));
408                }
409                _ => {
410                    iter.prev();
411                }
412            };
413        }
414        Ok(left)
415    }
416
417    fn ast_exponential_expression(&self, iter: &mut Iter<(Token, usize, usize)>) -> Result<Option<Expression>, &str> {
418        use crate::Token::*;
419        use crate::Expression::*;
420        let left = self.ast_primitive(iter)?;
421        if left.is_none() {
422            return Ok(None);
423        }
424        if let Some(tnk) = iter.next() {
425            match tnk.0 {
426                Pow => {
427                    let right = self.ast_primitive(iter)?;
428                    if right.is_none() {
429                        return Err("ERROR 4");
430                    }
431                    return Ok(Some(ExpressionOperation((Box::new(left.unwrap()), '^', Box::new(right.unwrap())))));
432                }
433                _ => {
434                    iter.prev();
435                }
436            };
437        }
438        match left.unwrap() {
439            Primitive(left) => Ok(Some(Primitive(left))),
440            ExpressionOperation(left) => Ok(Some(ExpressionOperation(left)))
441        }
442    }
443
444    fn ast_primitive(&self, iter: &mut Iter<(Token, usize, usize)>) -> Result<Option<Expression>, &str> {
445        use crate::Token::*;
446        return if let Some(tnk) = iter.next() {
447            match &tnk.0 {
448                Identifier(ident) => {
449                    if ident.as_str() == "x" {
450                        return Ok(Some(Expression::Primitive(Primitive::Identifier(ident.clone()))));
451                    }
452                    return match self.functions.get(&ident.as_str()) {
453                        None => Err("ERROR 3"),
454                        Some(func) => {
455                            return match iter.next() {
456                                Some(token) => {
457                                    match token.0 {
458                                        LParent => {}
459                                        _ => {
460                                            return Err("ERROR FUNCTION MUST HAVE OPEN BRACKET");
461                                        }
462                                    }
463                                    let w_input = self.ast_additive_expression(iter)?;
464                                    match w_input {
465                                        None => Err("Function must have input"),
466                                        Some(input) => {
467                                            match iter.next() {
468                                                Some(token) => {
469                                                    match token.0 {
470                                                        RParent => {}
471                                                        _ => return Err("Function expected ')'")
472                                                    }
473                                                }
474                                                None => return Err("Function expected ')'")
475                                            }
476                                            Ok(Some(Expression::Primitive(Primitive::Function((func.clone(), Box::new(input))))))
477                                        }
478                                    }
479                                }
480                                None => Err("Function expected '('"),
481                            };
482                        }
483                    };
484                }
485                Number(num) => {
486                    return Ok(Some(Expression::Primitive(Primitive::Number(num.clone()))));
487                }
488                LParent => {
489                    let expr = self.ast_additive_expression(iter)?;
490                    return match expr {
491                        Some(expr) => {
492                            match iter.next() {
493                                Some(token) => {
494                                    match token.0 {
495                                        RParent => {}
496                                        _ => return Err("Parenthesis expected ')'")
497                                    }
498                                }
499                                None => return Err("Parenthesis expected ')'")
500                            }
501                            Ok(Some(expr))
502                        }
503                        None => {
504                            match iter.next() {
505                                Some(token) => {
506                                    match token.0 {
507                                        RParent => Ok(None),
508                                        _ => return Err("Parenthesis expected ')'")
509                                    }
510                                }
511                                None => return Err("Parenthesis expected ')'")
512                            }
513                        }
514                    };
515                }
516                _ => {
517                    return Err("ERROR 1");
518                }
519            }
520        } else {
521            Ok(None)
522        };
523    }
524}
525
526#[cfg(test)]
527mod numeric_tests {
528    use super::*;
529
530    #[test]
531    fn number_integer() {
532        let mut tokenizer = Tokenizer::new(" 10");
533        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Number");
534    }
535
536    #[test]
537    fn number_zero_integer() {
538        let mut tokenizer = Tokenizer::new(" 0");
539        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Number");
540    }
541
542    #[test]
543    fn number_float() {
544        let mut tokenizer = Tokenizer::new(" 10.1");
545        let token = tokenizer.next().unwrap().unwrap().0;
546        println!("{}", token.to_string());
547        assert_eq!(token.typ(), "Number");
548    }
549
550    #[test]
551    fn number_zero_float() {
552        let mut tokenizer = Tokenizer::new(" 0.1");
553        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Number");
554    }
555
556    #[test]
557    fn number_underscore() {
558        let mut tokenizer = Tokenizer::new(" 1_10");
559        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Number");
560    }
561
562    #[test]
563    fn number_unexpected_err() {
564        let mut tokenizer = Tokenizer::new(" 10.1.1");
565        assert_eq!(tokenizer.next().err().unwrap(), "Unexpected number");
566    }
567}
568
569#[cfg(test)]
570mod identifier_tests {
571    use super::*;
572
573    #[test]
574    fn ident_x() {
575        let mut tokenizer = Tokenizer::new("x");
576        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Identifier");
577    }
578
579    #[test]
580    fn ident_cow() {
581        let mut tokenizer = Tokenizer::new("วัว");
582        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Identifier");
583    }
584
585    #[test]
586    fn ident_underscore() {
587        let mut tokenizer = Tokenizer::new("_cow");
588        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Identifier");
589    }
590
591    #[test]
592    fn ident_number() {
593        let mut tokenizer = Tokenizer::new("boon1_");
594        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Identifier");
595    }
596}
597
598#[cfg(test)]
599mod expr_tests {
600    use super::*;
601
602    #[test]
603    fn expr_1() {
604        let mut tokenizer = Tokenizer::new(" 10.6 + x");
605        let a = tokenizer.next().unwrap().unwrap().0;
606        let b = tokenizer.next().unwrap().unwrap().0;
607        let c = tokenizer.next().unwrap().unwrap().0;
608
609        println!("{}", a.to_string());
610        println!("{}", b.to_string());
611        println!("{}", c.to_string());
612
613        assert_eq!(a.typ(), "Number");
614        assert_eq!(b.typ(), "Operator");
615        assert_eq!(c.typ(), "Identifier");
616    }
617
618    #[test]
619    fn expr_2() {
620        let mut tokenizer = Tokenizer::new(" (10 / 5)");
621        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Parenthesis");
622        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Number");
623        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Operator");
624        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Number");
625        assert_eq!(tokenizer.next().unwrap().unwrap().0.typ(), "Parenthesis");
626    }
627}
628
629#[cfg(test)]
630mod parse_tests {
631    use super::*;
632    
633    #[test]
634    fn parse_1() {
635        use std::time::{Duration, SystemTime};
636        let moo = Moo::new(|functions| {
637            functions.insert("relu", |v| {
638                f64::max(0.0, v)
639            });
640        });
641        let now = SystemTime::now();
642        let program = moo.parse("1 + 4.9 ^ 0.2 * x").ok().unwrap().unwrap();
643        match now.elapsed() {
644            Ok(elapsed) => {
645                println!("{}ns", elapsed.as_nanos());
646            }
647            Err(e) => {
648                println!("Error: {e:?}");
649            }
650        }
651        println!("{}", program.run(1000.0));
652    }
653}