Package Logo
License: MIT

Mate is a library for parsing and calculating arithmetic expressions inputted as &str(string). Uses Lexer(similar to interpreted-programming languages' lexer) structure to parse string input in to token list, and Calculator structure to calculate final result from token list. Implements also a general wrapper structure that implements Lexer and Calculator inside of it. And makes it easy to calculate arithmetic expression's result directly without dealing with parsing and calculating manually. # Usage This crate is on [crates.io](http://crates.io/crates/mate-rs) and can be used by adding mate-rs to your dependencies in your project's `Cargo.toml`. ```toml [dependencies] mate-rs = "0.1.4" ``` ## Example: with `Mate` `Mate` is general wrapper structure for `Lexer` and `Calculator`. has only one method that used to `calculate` result via string(&str) input. ```rust use mate_rs::mate::Mate; let result = Mate::calculate("6 * 7"); match result { Ok(v) => assert_eq!(v, 42.0), Err(_) => { // Do something ... } }; ``` ## Example: with `Lexer` and `Calculator` `Lexer` is the main structure that parses string-input to token-list. `Calculator` is the structure that used to calculate final result via `Lexer`'s result. ```rust use mate_rs::{calculator::Calculator, lexer::Lexer}; // Generated tokens gonna be something like: // | // | Token( // | type: SUBEXP, // | tokens: [ // | Token( // | type: SUBEXP, // | tokens: [ // | Token(type: NUMBER, literal: "2") // | Token(type: PLUS, literal: "+") // | Token(type: NUMBER, literal: "5") // | ], // | ), // | Token(type: PRODUCT, literal: "*"), // | Token( // | type: SUBEXP, // | tokens: [ // | Token(type: NUMBER, literal: "5") // | Token(type: MINUS, literal: "-") // | Token(type: NUMBER, literal: "9") // | Token(type: PLUS, literal: "+") // | Token( // | type: SUBEXP, // | tokens: [ // | Token(type: NUMBER, literal: "8") // | Token(type: PLUS, literal: "-") // | Token(type: NUMBER, literal: "5") // | ], // | ), // | ], // | ), // | ], // | ), // | Token(type: PLUS, literal: "+") // | Token(type: NUMBER, literal: "35") // | let input = "[ (2 + 5) * (5 - 9 + (8 - 5)) ] + 35"; let tokens = Lexer::lex(input.clone()).unwrap(); // should handle error case also // Result will be calculated from tokens, by X/O/Y algorithm. // // ╭────────╮ ╭───────────╮ ╭────────╮ // │ NUMBER │ │ OPERATION │ │ NUMBER │ // ╰────────╯ ╰───────────╯ ╰────────╯ // ╰───╮ │ ╭───╯ // ▼ ▼ ▼ // X [+, -, *, /] Y // let result = Calculator::calculate(tokens, input.clone()); ``` --- # How it works Mate is all about two main structures, [Lexer] and [Calculator]. [Lexer] is the structure that takes care of parsing interpretting given string expression, and [Calculator] is the structure that takes care of calculating final result via parsed tokens. ## Lexer Loops through the given input string, reads and converts each character to an [Token] structure. We've several types of main tokens and they are: - `ILLEGAL` - illegal character. - `NUMBER` - number type. - `MINUS`, `PLUS`, `PRODUCT`, `DIVIDE`, `PERCENTAGE`, `POWER` - operations. - `LPAREN`, `RPAREN` - parentheses. - `LABS`, `LPAREN` - absolute values. - `SUBEXP` - sub expression, expressions inside of parentheses, abs, or combinations of division and multiplication. Lexer's `lex` functionality converts each character to one of these tokens. It combines multiplication or division operation related tokens into one sub-expression to keep the operation-priority right. And nests the parentheses, absolute values and powers with a custom level-to-expression algorithm. level-to-expression algorithm is mapping algorithm that maps concrete expression to it's nesting level. *For example if the given token list is* -> `(2 + 5) : (5 - 9 / (8 - 5))`. *Generated result will be:* mate **By doing that we make it easy to keep the operation-priority safe.** ## Calculator Calculator takes the parsed token-list and calculates final result of it. Uses custom `X/O/Y` algorithm a.k.a `X/OPERATION/Y` where `X` and `Y` are numbers, and `O` is operation. If cannot get the `X` or `Y` takes them as zero. ``` ╭────────╮ ╭───────────╮ ╭────────╮ │ NUMBER │ │ OPERATION │ │ NUMBER │ ╰────────╯ ╰───────────╯ ╰────────╯ ╰───╮ │ ╭───╯ ▼ ▼ ▼ X [+, -, *, /] Y ``` --- # Syntax The syntaxt of `Mate` kept as easy and basic as possible. It's just plain-text mathematics syntaxt with few customizations. Let's see some examples: ### Plus and Minus `2 + 5` and `2 - 5` are valid syntaxts. (in `x y` where x and y could be `NUMBER` or `SUBEXP`). ### Multiplication, Division and Percentage `4 * 2`, `4 / 2`, and `4 % 2` are valid syntaxts. (in `x y` where x and y could be `NUMBER` or `SUBEXP`). Also `4(10 / 2)` or `4(2)` is valid syntax in case of **multiplication**. ### Power `4 ^ 2` is valid syntaxt. (in `x y` where x and y could be `NUMBER` or `SUBEXP`). Also continues powers are accepted: `4 ^ 2 ^ 3` which gonna be automatically turned into `4 ^ (2 ^ 3)`. ### Parentheses `(2 * 5)` is valid syntaxt. (in `x y` where x and y could be `NUMBER` or `SUBEXP`). And, nested parentheses expressions are accepted: `(2 * ((5 * 2) / (9 - 5)))`. ### Absolute-Values `[2 - 12]` is valid syntaxt. (in `x y` where x and y could be `NUMBER` or `SUBEXP`). And, nested absolute-value expressions are accepted: `[7 - 14] * [5 - 9 / [5 - 3]]`. --- # Errors #### We do not need to say anything about errors, here is some of them: unknown-char-error expected-an-token-error