Skip to content

Commit

Permalink
refactor: change to offcial format parser #13
Browse files Browse the repository at this point in the history
  • Loading branch information
phodal committed Nov 7, 2022
1 parent e94fd6f commit 6a11835
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 35 deletions.
2 changes: 2 additions & 0 deletions extensions/ext-computing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ salsa = { git = "https://github.com/salsa-rs/salsa", package = "salsa-2022" }
pest = "2.3.1"
pest_derive = "2.3.1"

lazy_static = "1.4.0"

[dev-dependencies]
actix-web = "4"
tokio = { version = "1", features = ["full"] }
Expand Down
19 changes: 10 additions & 9 deletions extensions/ext-computing/src/expr/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,24 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
program = _{ SOI ~ stmt ~ EOI }
program = _{ SOI ~ expr ~ EOI }

stmt = _{ assign | expr }
assign = { ident ~ "=" ~ expr }
expr = { prefix* ~ atom ~ postfix* ~ (operation ~ atom)* }
atom = _{ constants | function | ident | convert | num | "(" ~ expr ~ ")" }
stmt = _{ assign | expr }
assign = { ident ~ "=" ~ expr }
expr = { prefix* ~ primary ~ postfix* ~ (infix ~ prefix* ~ primary ~ postfix* )* }
primary = _{ constants | function | ident | convert | num | "(" ~ expr ~ ")" }
infix = _{ sub | add | mul | div | pow | percentOf | percentOn | rightShift | leftShift | modulus }
prefix = _{ neg }
postfix = _{ fac }

operation = _{ sub | add | mul | div | pow | percentOf | percentOn | rightShift | leftShift | modulus }
add = { "+" | "with" | "plus" | "add" }
sub = { "-" | "without" | "subtract" | "minus" }
mul = { "*" | "times" | "multiply by" | "mul" }
div = { "/" | "divide by" | "divide" }
pow = { "^" | "power" }
modulus = { "%" | "mod" }

prefix = _{ neg }
neg = { "-" } // Negation
postfix = _{ fac }
fac = { "!" } // Factorial
rightShift = { ">>" }

Expand All @@ -46,7 +46,6 @@ percentOn = { "percent on" | "%" ~ "on" }

function = { ident ~ "(" ~ expr ~ ")" }

WHITESPACE = _{ " " | "\t" }
ident = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* ~ "'"* }
int = { ("+" | "-")? ~ ASCII_DIGIT+ }
num = @{ int ~ ("." ~ ASCII_DIGIT*)? ~ (^"e" ~ int)? }
Expand Down Expand Up @@ -155,3 +154,5 @@ YOTTABYTE = { "yottabytes" | "yottabyte"| ^"yb" }

siunit = { AREA | DIGITALINFORMATION | SPEED | MASS | ANGLE | TIME | LENGTH | TEMPERATURE }
convert = { num ~ siunit ~ ( "to" | "as" | "in" ) ~ siunit }

WHITESPACE = _{ " " | "\t" | NEWLINE }
51 changes: 25 additions & 26 deletions extensions/ext-computing/src/expr/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,35 @@ use pest::pratt_parser::*;
#[grammar = "expr/grammar.pest"]
struct Calculator;

lazy_static! {
static ref PRATT_PARSER: PrattParser<Rule> = {
// Precedence is defined lowest to highest
PrattParser::new()
.op(Op::infix(Rule::add, Assoc::Left) | Op::infix(Rule::sub, Assoc::Left))
.op(Op::infix(Rule::mul, Assoc::Left) | Op::infix(Rule::div, Assoc::Left))
.op(Op::infix(Rule::pow, Assoc::Right))
.op(Op::postfix(Rule::fac))
.op(Op::prefix(Rule::neg))
};
}

pub fn parse(input: &str) -> f64 {
let parse_result = Calculator::parse(Rule::program, input);
match parse_result {
Ok(r) => eval(r),
match Calculator::parse(Rule::program, input) {
Ok(mut pairs) => parse_expr(pairs.next().unwrap().into_inner()),
Err(_) => f64::NAN,
}
}

fn eval(pairs: Pairs<Rule>) -> f64 {
let pratt =
PrattParser::new()
.op(Op::infix(Rule::add, Assoc::Left) | Op::infix(Rule::sub, Assoc::Left))
.op(Op::infix(Rule::mul, Assoc::Left) | Op::infix(Rule::div, Assoc::Left))
.op(Op::infix(Rule::pow, Assoc::Right))
.op(Op::postfix(Rule::fac))
.op(Op::prefix(Rule::neg));

parse_expr(pairs, &pratt)
}

fn parse_expr(pairs: Pairs<Rule>, pratt: &PrattParser<Rule>) -> f64 {
pratt
// can be follow: <https://github.com/pest-parser/book/blob/master/examples/pest-calculator/src/main.rs>
fn parse_expr(pairs: Pairs<Rule>) -> f64 {
PRATT_PARSER
.map_primary(|primary| match primary.as_rule() {
Rule::expr => parse_expr(primary.into_inner()),
Rule::int => primary.as_str().parse().unwrap(),
Rule::expr => parse_expr(primary.into_inner(), pratt), // from "(" ~ expr ~ ")"
Rule::num => primary.as_str().parse().unwrap(),
_ => panic!("unimplemented, {:?}", primary.as_rule()),
})
.map_prefix(|op, rhs| match op.as_rule() {
.map_prefix(|op, rhs: f64| match op.as_rule() {
Rule::neg => -rhs,
_ => panic!("unimplemented, {:?}", op.as_rule()),
})
Expand All @@ -58,14 +58,13 @@ mod tests {
use super::*;

#[test]
#[ignore]
fn it_works() {
assert_eq!(parse("1 + 2"), 3.0);
// assert_eq!(parse("1 + 2 * 3"), 7.0);
// assert_eq!(parse("(1 + 2) * 3"), 9.0);
// assert_eq!(parse("1 + 2 * 3 + 4"), 11.0);
// assert_eq!(parse("1 + 2 * (3 + 4)"), 15.0);
// assert_eq!(parse("1 + 2 * (3 + 4) / 5"), 3.0);
// assert_eq!(parse("1 + 2 * (3 + 4) / 5 - 6"), -3.0);
assert_eq!(parse("1 + 2 * 3"), 7.0);
assert_eq!(parse("(1 + 2) * 3"), 9.0);
assert_eq!(parse("1 + 2 * 3 + 4"), 11.0);
assert_eq!(parse("1 + 2 * (3 + 4)"), 15.0);
assert_eq!(parse("1 + 2 * (3 + 4) / 5"), 3.0);
assert_eq!(parse("1 + 2 * (3 + 4) / 5 - 6"), -3.0);
}
}
3 changes: 3 additions & 0 deletions extensions/ext-computing/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
#[macro_use]
extern crate lazy_static;

extern crate pest;
#[macro_use]
extern crate pest_derive;
Expand Down

0 comments on commit 6a11835

Please sign in to comment.