1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use pest::Parser;
use crate::lexicon::Lexicon;
use crate::matching::MPMatching;
#[derive(Parser)]
#[grammar = "condition.pest"]
pub struct CParser;
impl<'a> CParser {
pub fn check_conditions(source: &str, matching: &MPMatching<'a>, lexicon: &'a Lexicon) -> bool {
let parse_result = CParser::parse(Rule::conditions, source);
if parse_result.is_err() {
panic!("These do not seem like conditions: \"{}\"\n\nerr: {}\n\nmatching: {:?}", source, parse_result.err().unwrap(), matching);
}
let mut pairs = parse_result.ok().unwrap();
for pair in pairs.next().unwrap().into_inner() {
let mut exprpair = pair.into_inner();
let t1pair = exprpair.next().expect("1st term");
let pred = exprpair.next().expect("the condition's pred");
match pred.as_rule() {
Rule::num_pred => {
let val1 = CParser::compile_num(t1pair, matching, lexicon);
let t2pair = exprpair.next().expect("2st term");
let val2 = CParser::compile_num(t2pair, matching, lexicon);
let pass = eval_num_condition(val1, pred.as_str(), val2);
if !pass {
return false;
}
},
Rule::str_pred => {
let val1 = CParser::compile_str(t1pair, matching, lexicon);
let t2pair = exprpair.next().expect("2st term");
let val2 = CParser::compile_str(t2pair, matching, lexicon);
let pass = eval_str_condition(val1, pred.as_str(), val2);
if !pass {
return false;
}
},
unknown_pred => panic!("Unexpected predicate: {:?}", unknown_pred),
}
}
true
}
fn compile_num(pair: pest::iterators::Pair<Rule>, matching: &MPMatching<'a>, lexicon: &Lexicon) -> f64 {
match pair.as_rule() {
Rule::v_decimal => {
pair.as_str().parse::<f64>().ok().expect("a number")
},
Rule::var => {
let var = lexicon.intern("var", pair.as_str(), true);
let number = matching.get(var).expect("number segment");
let result = number.text.parse::<f64>();
if result.is_err() {
panic!("This does not seem like a number: \"{}\"\n\nerr: {}\n\nmatching: {:?}", number.text, result.err().unwrap(), matching);
}
result.ok().unwrap()
},
unknown_expr => panic!("Unexpected expression: {:?}", unknown_expr),
}
}
fn compile_str(pair: pest::iterators::Pair<'a, Rule>, matching: &'a MPMatching<'a>, lexicon: &'a Lexicon) -> &'a str {
match pair.as_rule() {
Rule::v_string => {
pair.as_str()
},
Rule::var => {
let var = lexicon.intern("var", pair.as_str(), true);
&matching.get(var).expect("number segment").text
},
unknown_expr => panic!("Unexpected expression: {:?}", unknown_expr),
}
}
}
fn eval_num_condition(lhs: f64, op: &str, rhs: f64) -> bool {
match op {
"==" => lhs == rhs,
"!=" => lhs != rhs,
"<" => lhs < rhs,
">" => lhs > rhs,
"<=" => lhs <= rhs,
">=" => lhs >= rhs,
_ => panic!("Unexpected dyadic operator: {}", op),
}
}
fn eval_str_condition(lhs: &str, op: &str, rhs: &str) -> bool {
match op {
"eq=" => lhs == rhs,
"neq" => lhs != rhs,
"contains" => lhs.contains(rhs),
"startswith" => lhs.starts_with(rhs),
"endswith" => lhs.ends_with(rhs),
_ => panic!("Unexpected dyadic operator: {}", op),
}
}