Skip to content

Commit

Permalink
upgrade pest, replace deprecated PrecClimber
Browse files Browse the repository at this point in the history
Also fix some lints.
  • Loading branch information
bonsairobo committed Dec 17, 2023
1 parent a2a71f9 commit 4993e72
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 48 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ publish = ["foresight-mining-software-corporation"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
once_cell = "1"
pest = "2"
pest_derive = "2"
once_cell = "1.19.0"
pest = "2.7.5"
pest_derive = "2.7.5"

rayon = { version = "1", optional = true }
88 changes: 43 additions & 45 deletions src/parse.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use std::collections::HashSet;

use crate::expression::{BindingId, BoolExpression, Expression, RealExpression};
use crate::StringExpression;

use once_cell::sync::Lazy;
use pest::iterators::{Pair, Pairs};
use pest::{prec_climber::*, Parser};
use pest::iterators::Pairs;
use pest::pratt_parser::{Assoc, Op, PrattParser};
use pest::Parser;
use pest_derive::Parser;
use std::collections::HashSet;

#[derive(Parser)]
#[grammar = "grammar.pest"] // relative to project `src`
struct ExpressionParser;

pub type ParseError = pest::error::Error<Rule>;
// Boxed because error is much larger than Ok variant in most results.
pub type ParseError = Box<pest::error::Error<Rule>>;

impl Expression {
/// Assume this expression is real-valued.
Expand Down Expand Up @@ -42,7 +42,6 @@ impl Expression {
pub fn parse_real_variable_names(input: &str) -> Result<HashSet<String>, ParseError> {
Ok(ExpressionParser::parse(Rule::calculation, input)?
.flatten()
.into_iter()
.filter(|p| (p.as_rule() == Rule::real_variable))
.map(|p| p.as_str().to_string())
.collect())
Expand All @@ -51,7 +50,6 @@ impl Expression {
pub fn parse_string_variable_names(input: &str) -> Result<HashSet<String>, ParseError> {
Ok(ExpressionParser::parse(Rule::calculation, input)?
.flatten()
.into_iter()
.filter(|p| (p.as_rule() == Rule::str_variable))
.map(|p| p.as_str().to_string())
.collect())
Expand All @@ -65,46 +63,46 @@ impl Expression {
/// [`Expression`] to be efficiently reused with many different data
/// bindings.
pub fn parse(input: &str, binding_map: impl Fn(&str) -> BindingId) -> Result<Self, ParseError> {
let pairs = ExpressionParser::parse(Rule::calculation, input)?;
Ok(climb_recursive(pairs, &binding_map))
let mut pairs = ExpressionParser::parse(Rule::calculation, input)?;
// HACK: Working around https://github.com/pest-parser/pest/issues/943
let inner_expr = pairs.next().unwrap().into_inner();
Ok(parse_recursive(inner_expr, &binding_map))
}
}

static PRECEDENCE_CLIMBER: Lazy<PrecClimber<Rule>> = Lazy::new(|| {
static PRATT_PARSER: Lazy<PrattParser<Rule>> = Lazy::new(|| {
use Assoc::*;
use Rule::*;

PrecClimber::new(vec![
Operator::new(and, Left) | Operator::new(or, Left),
Operator::new(str_eq, Left)
| Operator::new(str_neq, Left)
| Operator::new(real_eq, Left)
| Operator::new(real_neq, Left)
| Operator::new(less, Left)
| Operator::new(le, Left)
| Operator::new(greater, Left)
| Operator::new(ge, Left),
Operator::new(add, Left) | Operator::new(subtract, Left),
Operator::new(multiply, Left) | Operator::new(divide, Left),
Operator::new(power, Right),
])
PrattParser::new()
.op(Op::infix(and, Left) | Op::infix(or, Left))
.op(Op::infix(str_eq, Left)
| Op::infix(str_neq, Left)
| Op::infix(real_eq, Left)
| Op::infix(real_neq, Left)
| Op::infix(less, Left)
| Op::infix(le, Left)
| Op::infix(greater, Left)
| Op::infix(ge, Left))
.op(Op::infix(add, Left) | Op::infix(subtract, Left))
.op(Op::infix(multiply, Left) | Op::infix(divide, Left))
.op(Op::infix(power, Right))
});

fn climb_recursive(input: Pairs<Rule>, binding_map: &impl Fn(&str) -> BindingId) -> Expression {
PRECEDENCE_CLIMBER.climb(
input,
|pair: Pair<Rule>| match pair.as_rule() {
Rule::bool_expr => climb_recursive(pair.into_inner(), binding_map),
Rule::real_expr => climb_recursive(pair.into_inner(), binding_map),
Rule::string_expr => climb_recursive(pair.into_inner(), binding_map),
fn parse_recursive(pairs: Pairs<Rule>, binding_map: &impl Fn(&str) -> BindingId) -> Expression {
PRATT_PARSER
.map_primary(|pair| match pair.as_rule() {
Rule::bool_expr => parse_recursive(pair.into_inner(), binding_map),
Rule::real_expr => parse_recursive(pair.into_inner(), binding_map),
Rule::string_expr => parse_recursive(pair.into_inner(), binding_map),
Rule::real_literal => {
let literal_str = pair.as_str();
if let Ok(value) = literal_str.parse::<f64>() {
return Expression::Real(RealExpression::Literal(value));
}
panic!("Unexpected literal: {}", literal_str)
}
Rule::string_literal => climb_recursive(pair.into_inner(), binding_map),
Rule::string_literal => parse_recursive(pair.into_inner(), binding_map),
Rule::string_literal_value => {
let literal_str = pair.as_str();
if let Ok(value) = literal_str.parse::<String>() {
Expand All @@ -117,7 +115,7 @@ fn climb_recursive(input: Pairs<Rule>, binding_map: &impl Fn(&str) -> BindingId)
let unary = inner.next().unwrap();
match unary.as_rule() {
Rule::neg => Expression::Real(RealExpression::Neg(Box::new(
climb_recursive(inner, binding_map).unwrap_real(),
parse_recursive(inner, binding_map).unwrap_real(),
))),
x => panic!("Unexpected unary logic operator: {x:?}"),
}
Expand All @@ -127,7 +125,7 @@ fn climb_recursive(input: Pairs<Rule>, binding_map: &impl Fn(&str) -> BindingId)
let unary = inner.next().unwrap();
match unary.as_rule() {
Rule::not => Expression::Boolean(BoolExpression::Not(Box::new(
climb_recursive(inner, binding_map).unwrap_bool(),
parse_recursive(inner, binding_map).unwrap_bool(),
))),
x => panic!("Unexpected unary logic operator: {x:?}"),
}
Expand All @@ -139,8 +137,8 @@ fn climb_recursive(input: Pairs<Rule>, binding_map: &impl Fn(&str) -> BindingId)
Expression::String(StringExpression::Binding(binding_map(pair.as_str())))
}
x => panic!("Unexpected primary rule {x:?}"),
},
|lhs: Expression, op: Pair<Rule>, rhs: Expression| match op.as_rule() {
})
.map_infix(|lhs, op, rhs| match op.as_rule() {
Rule::add => Expression::Real(RealExpression::Add(
Box::new(lhs.unwrap_real()),
Box::new(rhs.unwrap_real()),
Expand Down Expand Up @@ -202,8 +200,8 @@ fn climb_recursive(input: Pairs<Rule>, binding_map: &impl Fn(&str) -> BindingId)
Box::new(rhs.unwrap_bool()),
)),
x => panic!("Unexpected operator {x:?}"),
},
)
})
.parse(pairs)
}

#[cfg(test)]
Expand All @@ -230,11 +228,11 @@ mod tests {
_ => unreachable!(),
}
}
Expression::parse("x == y", &binding_map).unwrap();
Expression::parse("x != y", &binding_map).unwrap();
Expression::parse("x > y", &binding_map).unwrap();
Expression::parse("x < y", &binding_map).unwrap();
Expression::parse("x <= y", &binding_map).unwrap();
Expression::parse("x >= y", &binding_map).unwrap();
Expression::parse("x == y", binding_map).unwrap();
Expression::parse("x != y", binding_map).unwrap();
Expression::parse("x > y", binding_map).unwrap();
Expression::parse("x < y", binding_map).unwrap();
Expression::parse("x <= y", binding_map).unwrap();
Expression::parse("x >= y", binding_map).unwrap();
}
}

0 comments on commit 4993e72

Please sign in to comment.