-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcondition_parser.cpp
More file actions
120 lines (98 loc) · 3.17 KB
/
condition_parser.cpp
File metadata and controls
120 lines (98 loc) · 3.17 KB
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "condition_parser.h"
#include "token.h"
#include <map>
using namespace std;
template <class It>
shared_ptr<Node> ParseComparison(It& current, It end) {
if (current == end) {
throw logic_error("Expected column name: date or event");
}
Token& column = *current;
if (column.type != TokenType::COLUMN) {
throw logic_error("Expected column name: date or event");
}
++current;
if (current == end) {
throw logic_error("Expected comparison operation");
}
Token& op = *current;
if (op.type != TokenType::COMPARE_OP) {
throw logic_error("Expected comparison operation");
}
++current;
if (current == end) {
throw logic_error("Expected right value of comparison");
}
Comparison cmp;
if (op.value == "<") {
cmp = Comparison::Less;
} else if (op.value == "<=") {
cmp = Comparison::LessOrEqual;
} else if (op.value == ">") {
cmp = Comparison::Greater;
} else if (op.value == ">=") {
cmp = Comparison::GreaterOrEqual;
} else if (op.value == "==") {
cmp = Comparison::Equal;
} else if (op.value == "!=") {
cmp = Comparison::NotEqual;
} else {
throw logic_error("Unknown comparison token: " + op.value);
}
const string& value = current->value;
++current;
if (column.value == "date") {
istringstream is(value);
return make_shared<DateComparisonNode>(cmp, ParseDate(is));
} else {
return make_shared<EventComparisonNode>(cmp, value);
}
}
template <class It>
shared_ptr<Node> ParseExpression(It& current, It end, unsigned precedence) {
if (current == end) {
return shared_ptr<Node>();
}
shared_ptr<Node> left;
if (current->type == TokenType::PAREN_LEFT) {
++current; // consume '('
left = ParseExpression(current, end, 0u);
if (current == end || current->type != TokenType::PAREN_RIGHT) {
throw logic_error("Missing right paren");
}
++current; // consume ')'
} else {
left = ParseComparison(current, end);
}
const map<LogicalOperation, unsigned> precedences = {
{LogicalOperation::Or, 1}, {LogicalOperation::And, 2}
};
while (current != end && current->type != TokenType::PAREN_RIGHT) {
if (current->type != TokenType::LOGICAL_OP) {
throw logic_error("Expected logic operation");
}
const auto logical_operation = current->value == "AND" ? LogicalOperation::And
: LogicalOperation::Or;
const auto current_precedence = precedences.at(logical_operation);
if (current_precedence <= precedence) {
break;
}
++current; // consume op
left = make_shared<LogicalOperationNode>(
logical_operation, left, ParseExpression(current, end, current_precedence)
);
}
return left;
}
shared_ptr<Node> ParseCondition(istream& is) {
auto tokens = Tokenize(is);
auto current = tokens.begin();
auto top_node = ParseExpression(current, tokens.end(), 0u);
if (!top_node) {
top_node = make_shared<EmptyNode>();
}
if (current != tokens.end()) {
throw logic_error("Unexpected tokens after condition");
}
return top_node;
}