Less Simple Math

7318fea4-6106-4edc-99fa-d96d515f2133


use std::env;/* For amplify [amplify.connorcode.com] github.com/basicprogrammer10/amplify * Tokenize * Parse AST * Evaluate # EX 1 5*6+3-1       |      /-\    /+\  1  /*\  3 5   6 # EX 2 7*2+9*5-6         |        /-\      /+\  6    /    \  /*\   /*\ 7   2 9   5*/*/*/*/// 61+21-1218+72-7274fn main() {    for i in env::args().skip(1) {        let tokens = tokenize(&i);        let tree = create_tree(tokens);        let result = evaluate(tree);        println!("{result}");    }}#[derive(Debug, Clone)]enum Token {    Number(i32),    Op(Ops),    Group(Vec<Token>),    Tree(Ops, Box<Token>, Box<Token>),}#[derive(Debug, Clone, Copy)]enum Ops {    Add,    Sub,    Mul,}fn evaluate(tree: Token) -> i32 {    match tree {        Token::Tree(op, left, right) => {            let left = evaluate(*left);            let right = evaluate(*right);            match op {                Ops::Add => left + right,                Ops::Sub => left - right,                Ops::Mul => left * right,            }        }        Token::Number(n) => n,        _ => panic!("Invalid token"),    }}fn create_tree(mut tokens: Vec<Token>) -> Token {    fn get_max_prio(tokens: &[Token]) -> usize {        tokens            .iter()            .filter_map(|x| match x {                Token::Op(i) => Some(i.prio()),                _ => None,            })            .max()            .unwrap()    }    fn contains_non_tree(tokens: &[Token]) -> bool {        tokens            .iter()            .filter(|x| !matches!(x, Token::Tree(_, _, _)))            .count()            > 0    }    while contains_non_tree(&tokens) {        let max_prio = get_max_prio(&tokens);        let mut i = 0;        while i < tokens.len() {            if let Token::Op(op) = tokens[i] {                if op.prio() < max_prio {                    i += 1;                    continue;                }                let left = tokens.remove(i - 1).make_tree();                let right = tokens.remove(i).make_tree();                tokens[i - 1] = Token::Tree(op, Box::new(left), Box::new(right));                break;            }            i += 1;        }    }    debug_assert!(tokens.len() == 1);    tokens[0].clone()}fn tokenize(inp: &str) -> Vec<Token> {    let mut out = Vec::new();    let mut working = String::new();    let mut in_group = false;    for i in inp.chars() {        if !i.is_ascii_digit() && !working.is_empty() && !in_group {            out.push(Token::Number(working.parse().unwrap()));            working.clear();        }        match i {            // Groups            '(' => in_group = true,            ')' => {                in_group = false;                out.push(Token::Group(tokenize(&working)));                working.clear();            }            i if in_group => working.push(i),            // Operations            '+' => out.push(Token::Op(Ops::Add)),            '-' => out.push(Token::Op(Ops::Sub)),            '*' => out.push(Token::Op(Ops::Mul)),            // Numbers            i if i.is_ascii_digit() => working.push(i),            _ => panic!("INVALID CHAR: {}", i),        }    }    if !working.is_empty() {        out.push(Token::Number(working.parse().unwrap()));    }    out}impl Ops {    fn prio(&self) -> usize {        match self {            Ops::Add | Ops::Sub => 1,            Ops::Mul => 2,        }    }}impl Token {    fn make_tree(self) -> Token {        match self {            Token::Group(tokens) => create_tree(tokens),            _ => self,        }    }}