Skip to content

Commit 0a7c710

Browse files
committed
refactored sonar issues
1 parent 705aeb7 commit 0a7c710

File tree

14 files changed

+258
-270
lines changed

14 files changed

+258
-270
lines changed

cucumber_cpp/library/HookRegistry.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "cucumber_cpp/library/Body.hpp"
55
#include "cucumber_cpp/library/Context.hpp"
66
#include "cucumber_cpp/library/tag_expression/Model.hpp"
7-
#include "cucumber_cpp/library/tag_expression/TagExpressionParser.hpp"
7+
#include "cucumber_cpp/library/tag_expression/Parser.hpp"
88
#include <cstddef>
99
#include <functional>
1010
#include <memory>
@@ -62,7 +62,7 @@ namespace cucumber_cpp::library
6262
{
6363
Entry(HookType type, std::string_view expression, std::unique_ptr<Body> (&factory)(Context& context))
6464
: type(type)
65-
, tagExpression{ tag_expression::TagExpressionParser{}.Parse(expression) }
65+
, tagExpression{ tag_expression::Parse(expression) }
6666
, factory(factory)
6767
{}
6868

cucumber_cpp/library/tag_expression/CMakeLists.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ add_library(cucumber_cpp.library.tag_expression STATIC ${CCR_EXCLUDE_FROM_ALL})
55
target_sources(cucumber_cpp.library.tag_expression PRIVATE
66
Model.cpp
77
Model.hpp
8-
TagExpressionError.cpp
9-
TagExpressionError.hpp
10-
TagExpressionParser.cpp
11-
TagExpressionParser.hpp
8+
Error.cpp
9+
Error.hpp
10+
Parser.cpp
11+
Parser.hpp
1212
Token.cpp
1313
Token.hpp
1414
)
File renamed without changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef TAG_EXPRESSION_ERROR_HPP
2+
#define TAG_EXPRESSION_ERROR_HPP
3+
4+
#include <stdexcept>
5+
6+
namespace cucumber_cpp::library::tag_expression
7+
{
8+
struct Error : std::runtime_error
9+
{
10+
using std::runtime_error::runtime_error;
11+
};
12+
}
13+
14+
#endif

cucumber_cpp/library/tag_expression/Model.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#include "cucumber_cpp/library/tag_expression/Model.hpp"
22
#include <cstddef>
33
#include <format>
4+
#include <functional>
45
#include <memory>
56
#include <regex>
67
#include <set>
78
#include <string>
9+
#include <string_view>
810
#include <utility>
911

1012
namespace cucumber_cpp::library::tag_expression
@@ -30,7 +32,7 @@ namespace cucumber_cpp::library::tag_expression
3032

3133
LiteralExpression::operator std::string() const
3234
{
33-
auto replaceAll = [](std::string& str, const std::string& from, const std::string& to)
35+
auto replaceAll = [](std::string& str, std::string_view from, std::string_view to)
3436
{
3537
if (from.empty())
3638
return;
@@ -44,9 +46,9 @@ namespace cucumber_cpp::library::tag_expression
4446

4547
auto copy = name;
4648

47-
replaceAll(copy, "\\", "\\\\");
48-
replaceAll(copy, "(", "\\(");
49-
replaceAll(copy, ")", "\\)");
49+
replaceAll(copy, "\\", R"(\\)");
50+
replaceAll(copy, "(", R"(\()");
51+
replaceAll(copy, ")", R"(\))");
5052

5153
copy = std::regex_replace(copy, std::regex(R"((\s))"), R"(\$&)");
5254

cucumber_cpp/library/tag_expression/Model.hpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ namespace cucumber_cpp::library::tag_expression
1313
virtual ~Expression() = default;
1414

1515
virtual bool Evaluate(const std::set<std::string, std::less<>>& tags) const = 0;
16-
virtual operator std::string() const = 0;
16+
virtual explicit operator std::string() const = 0;
1717
};
1818

1919
struct TrueExpression : Expression
2020
{
2121
bool Evaluate(const std::set<std::string, std::less<>>& tags) const override;
22-
operator std::string() const override;
22+
explicit operator std::string() const override;
2323
};
2424

2525
struct LiteralExpression : Expression
2626
{
27-
LiteralExpression(std::string name);
27+
explicit LiteralExpression(std::string name);
2828

2929
bool Evaluate(const std::set<std::string, std::less<>>& tags) const override;
30-
operator std::string() const override;
30+
explicit operator std::string() const override;
3131

3232
private:
3333
std::string name;
@@ -38,7 +38,7 @@ namespace cucumber_cpp::library::tag_expression
3838
AndExpression(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right);
3939

4040
bool Evaluate(const std::set<std::string, std::less<>>& tags) const override;
41-
operator std::string() const override;
41+
explicit operator std::string() const override;
4242

4343
private:
4444
std::unique_ptr<Expression> left;
@@ -50,7 +50,7 @@ namespace cucumber_cpp::library::tag_expression
5050
OrExpression(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right);
5151

5252
bool Evaluate(const std::set<std::string, std::less<>>& tags) const override;
53-
operator std::string() const override;
53+
explicit operator std::string() const override;
5454

5555
private:
5656
std::unique_ptr<Expression> left;
@@ -59,10 +59,10 @@ namespace cucumber_cpp::library::tag_expression
5959

6060
struct NotExpression : Expression
6161
{
62-
NotExpression(std::unique_ptr<Expression> operand);
62+
explicit NotExpression(std::unique_ptr<Expression> operand);
6363

6464
bool Evaluate(const std::set<std::string, std::less<>>& tags) const override;
65-
operator std::string() const override;
65+
explicit operator std::string() const override;
6666

6767
private:
6868
std::unique_ptr<Expression> operand;
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#include "cucumber_cpp/library/tag_expression/Parser.hpp"
2+
#include "cucumber_cpp/library/tag_expression/Error.hpp"
3+
#include "cucumber_cpp/library/tag_expression/Model.hpp"
4+
#include "cucumber_cpp/library/tag_expression/Token.hpp"
5+
#include <cctype>
6+
#include <cstddef>
7+
#include <deque>
8+
#include <format>
9+
#include <locale>
10+
#include <memory>
11+
#include <stack>
12+
#include <string>
13+
#include <string_view>
14+
#include <utility>
15+
#include <vector>
16+
17+
namespace cucumber_cpp::library::tag_expression
18+
{
19+
namespace
20+
{
21+
void EnsureExpectedTokenType(TokenType tokenType, TokenType expected, std::string_view lastPart)
22+
{
23+
if (tokenType != expected)
24+
throw Error(std::format(R"(Syntax error. Expected {} after {})", tokenTypeMap.at(expected), lastPart));
25+
}
26+
27+
void RequireArgCount(const Token& token, std::deque<std::unique_ptr<Expression>>& expressions, std::size_t number)
28+
{
29+
if (expressions.size() < number)
30+
{
31+
32+
std::string expressionsStr{ "" };
33+
for (const auto& expr : expressions)
34+
{
35+
if (!expressionsStr.empty())
36+
expressionsStr += ", ";
37+
expressionsStr += static_cast<std::string>(*expr);
38+
}
39+
40+
throw Error(std::format(R"({}: Too few operands (expressions={{{}}}))", token.keyword, expressionsStr));
41+
}
42+
}
43+
44+
template<class T>
45+
void PushBinary(const Token& token, std::deque<std::unique_ptr<Expression>>& expressions)
46+
{
47+
RequireArgCount(token, expressions, 2);
48+
49+
auto term2 = std::move(expressions.back());
50+
expressions.pop_back();
51+
auto term1 = std::move(expressions.back());
52+
expressions.pop_back();
53+
54+
expressions.push_back(std::make_unique<T>(std::move(term1), std::move(term2)));
55+
}
56+
57+
template<class T>
58+
void PushUnary(const Token& token, std::deque<std::unique_ptr<Expression>>& expressions)
59+
{
60+
RequireArgCount(token, expressions, 1);
61+
62+
auto term = std::move(expressions.back());
63+
expressions.pop_back();
64+
65+
expressions.push_back(std::make_unique<T>(std::move(term)));
66+
}
67+
68+
void PushExpression(const Token& token, std::deque<std::unique_ptr<Expression>>& expressions)
69+
{
70+
if (token == OR)
71+
PushBinary<OrExpression>(token, expressions);
72+
else if (token == AND)
73+
PushBinary<AndExpression>(token, expressions);
74+
else if (token == NOT)
75+
PushUnary<NotExpression>(token, expressions);
76+
else
77+
throw Error(std::format("Unexpected token: {}", token.keyword));
78+
}
79+
80+
std::vector<std::string> Tokenize(std::string_view expression)
81+
{
82+
std::vector<std::string> tokens{};
83+
auto escaped = false;
84+
std::string token = {};
85+
86+
for (char ch : expression)
87+
{
88+
if (escaped)
89+
{
90+
if ((ch != '(' && ch != ')' && ch != '\\') && !std::isspace(ch, std::locale()))
91+
throw Error(std::format(R"(Tag expression "{}" could not be parsed because of syntax error: Illegal escape before "{}".)", expression, ch));
92+
token += ch;
93+
escaped = false;
94+
}
95+
else if (ch == '\\')
96+
escaped = true;
97+
else if (ch == '(' || ch == ')' || std::isspace(ch, std::locale()))
98+
{
99+
if (!token.empty())
100+
{
101+
tokens.push_back(std::move(token));
102+
token.clear();
103+
}
104+
if (ch != ' ')
105+
tokens.push_back(std::string{ ch });
106+
}
107+
else
108+
token += ch;
109+
}
110+
111+
if (!token.empty())
112+
tokens.push_back(std::move(token));
113+
114+
return tokens;
115+
}
116+
117+
const Token* SelectToken(std::string_view expression)
118+
{
119+
if (!tokenMap.contains(expression))
120+
return nullptr;
121+
122+
return &tokenMap.at(expression);
123+
}
124+
}
125+
126+
std::unique_ptr<Expression> Parse(std::string_view expression)
127+
{
128+
auto tokens = Tokenize(expression);
129+
130+
if (tokens.empty())
131+
return std::make_unique<TrueExpression>();
132+
133+
std::stack<Token> operations;
134+
std::deque<std::unique_ptr<Expression>> expressions;
135+
std::string lastPart = "BEGIN";
136+
auto expectedTokenType = TokenType::operand;
137+
138+
for (auto index = 0; index < tokens.size(); ++index)
139+
{
140+
const auto& part = tokens[index];
141+
142+
if (const auto* token = SelectToken(part); token == nullptr)
143+
{
144+
EnsureExpectedTokenType(TokenType::operand, expectedTokenType, lastPart);
145+
expressions.push_back(std::make_unique<LiteralExpression>(part));
146+
expectedTokenType = TokenType::operator_;
147+
}
148+
else if (*token == NOT || *token == OPEN_PARENTHESIS)
149+
{
150+
EnsureExpectedTokenType(TokenType::operand, expectedTokenType, lastPart);
151+
operations.push(*token);
152+
expectedTokenType = TokenType::operand;
153+
}
154+
else if (token->IsOperation())
155+
{
156+
EnsureExpectedTokenType(TokenType::operator_, expectedTokenType, lastPart);
157+
while (!operations.empty() && operations.top().IsOperation() && token->HasLowerPrecedenceThan(operations.top()))
158+
{
159+
auto lastOperation = operations.top();
160+
operations.pop();
161+
PushExpression(lastOperation, expressions);
162+
}
163+
operations.push(*token);
164+
expectedTokenType = TokenType::operand;
165+
}
166+
else if (*token == CLOSE_PARENTHESIS)
167+
{
168+
EnsureExpectedTokenType(TokenType::operator_, expectedTokenType, lastPart);
169+
while (!operations.empty() && operations.top() != OPEN_PARENTHESIS)
170+
{
171+
auto lastOperation = operations.top();
172+
operations.pop();
173+
PushExpression(lastOperation, expressions);
174+
}
175+
176+
if (operations.empty())
177+
throw Error(std::format("Missing '(': Too few open-parens in: {}", expression));
178+
179+
else if (operations.top() == OPEN_PARENTHESIS)
180+
{
181+
operations.pop();
182+
expectedTokenType = TokenType::operator_;
183+
}
184+
}
185+
186+
lastPart = part;
187+
}
188+
189+
while (!operations.empty())
190+
{
191+
auto lastOperation = operations.top();
192+
operations.pop();
193+
194+
if (lastOperation == OPEN_PARENTHESIS)
195+
throw Error(std::format("Unclosed '(': Too many open-parens in: {}", expression));
196+
197+
PushExpression(lastOperation, expressions);
198+
}
199+
200+
return std::move(expressions.back());
201+
}
202+
203+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef TAG_EXPRESSION_PARSER_HPP
2+
#define TAG_EXPRESSION_PARSER_HPP
3+
4+
#include "cucumber_cpp/library/tag_expression/Model.hpp"
5+
#include <memory>
6+
#include <string_view>
7+
8+
namespace cucumber_cpp::library::tag_expression
9+
{
10+
std::unique_ptr<Expression> Parse(std::string_view expression);
11+
}
12+
13+
#endif

cucumber_cpp/library/tag_expression/TagExpressionError.hpp

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)