-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcondition_parser.cpp
122 lines (97 loc) · 3.44 KB
/
condition_parser.cpp
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
121
122
//
// condition_parser.cpp
// DataBaseCourseProject
//
// Created by Sergei Ziuzev on 3/15/22.
// Copyright © 2022 Sergei Ziuzev. All rights reserved.
//
#include "headers/condition_parser.hpp"
//using namespace std;
template <class It> std::shared_ptr<Node> ParseComparison(It& current, It end) {
if (current == end) {
throw std::logic_error("Expected column name: date or event");
}
Token& column = *current;
if (column.type != TokenType::COLUMN) {
throw std::logic_error("Expected column name: date or event");
}
++current;
if (current == end) {
throw std::logic_error("Expected comparison operation");
}
Token& op = *current;
if (op.type != TokenType::COMPARE_OP) {
throw std::logic_error("Expected comparison operation");
}
++current;
if (current == end) {
throw std::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 std::logic_error("Unknown comparison token: " + op.value);
}
const std::string& value = current->value;
++current;
if (column.value == "date") {
std::istringstream is(value);
return std::make_shared<DateComparisonNode>(cmp, ParseDate(is));
} else {
return std::make_shared<EventComparisonNode>(cmp, value);
}
}
template <class It>
std::shared_ptr<Node> ParseExpression(It& current, It end, unsigned precedence) {
if (current == end) {
return std::shared_ptr<Node>();
}
std::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 std::logic_error("Missing right paren");
}
++current; // consume ')'
} else {
left = ParseComparison(current, end);
}
const std::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 std::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 = std::make_shared<LogicalOperationNode>(logical_operation, left, ParseExpression(current, end, current_precedence));
}
return left;
}
std::shared_ptr<Node> ParseCondition(std::istream& is) {
auto tokens = Tokenize(is);
auto current = tokens.begin();
auto top_node = ParseExpression(current, tokens.end(), 0u);
if (!top_node) {
top_node = std::make_shared<EmptyNode>();
}
if (current != tokens.end()) {
throw std::logic_error("Unexpected tokens after condition");
}
return top_node;
}