Skip to content

Commit 83e9c90

Browse files
committed
refactor: update Node and Token classes for improved encapsulation and consistency
1 parent 9ec071d commit 83e9c90

File tree

7 files changed

+132
-53
lines changed

7 files changed

+132
-53
lines changed

cucumber_cpp/library/cucumber_expression/Ast.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#include "cucumber_cpp/library/cucumber_expression/Ast.hpp"
22
#include "cucumber_cpp/library/cucumber_expression/Errors.hpp"
33
#include <cctype>
4+
#include <cstddef>
45
#include <map>
56
#include <ranges>
67
#include <string>
8+
#include <utility>
79
#include <variant>
810
#include <vector>
911

@@ -25,6 +27,31 @@ namespace cucumber_cpp::library::cucumber_expression
2527
}
2628
}
2729

30+
Node::Node(NodeType type,
31+
std::size_t start,
32+
std::size_t end,
33+
std::variant<std::string, std::vector<Node>> children)
34+
: type{ type }
35+
, start{ start }
36+
, end{ end }
37+
, children{ std::move(children) }
38+
{}
39+
40+
NodeType Node::Type() const
41+
{
42+
return type;
43+
}
44+
45+
std::size_t Node::Start() const
46+
{
47+
return start;
48+
}
49+
50+
std::size_t Node::End() const
51+
{
52+
return end;
53+
}
54+
2855
std::string Node::Text()
2956
{
3057
return static_cast<const Node*>(this)->Text();
@@ -56,6 +83,38 @@ namespace cucumber_cpp::library::cucumber_expression
5683
return std::get<std::vector<Node>>(children);
5784
}
5885

86+
const std::variant<std::string, std::vector<Node>>& Node::GetLeafNodes() const
87+
{
88+
return children;
89+
}
90+
91+
Token::Token(TokenType type, std::string text, std::size_t start, std::size_t end)
92+
: type{ type }
93+
, text{ std::move(text) }
94+
, start{ start }
95+
, end{ end }
96+
{}
97+
98+
TokenType Token::Type() const
99+
{
100+
return type;
101+
}
102+
103+
std::string Token::Text() const
104+
{
105+
return text;
106+
}
107+
108+
std::size_t Token::Start() const
109+
{
110+
return start;
111+
}
112+
113+
std::size_t Token::End() const
114+
{
115+
return end;
116+
}
117+
59118
bool Token::IsEscapeCharacter(unsigned char ch)
60119
{
61120
return ch == '\\';

cucumber_cpp/library/cucumber_expression/Ast.hpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,35 +34,55 @@ namespace cucumber_cpp::library::cucumber_expression
3434

3535
struct Node
3636
{
37-
NodeType type;
38-
std::size_t start;
39-
std::size_t end;
40-
std::variant<std::monostate, std::string, std::vector<Node>> children;
37+
Node(NodeType type,
38+
std::size_t start,
39+
std::size_t end,
40+
std::variant<std::string, std::vector<Node>> children);
41+
42+
NodeType Type() const;
43+
std::size_t Start() const;
44+
std::size_t End() const;
4145

4246
std::string Text();
4347
std::string Text() const;
4448

4549
std::vector<Node>& Children();
4650
const std::vector<Node>& Children() const;
4751

52+
const std::variant<std::string, std::vector<Node>>& GetLeafNodes() const;
53+
4854
bool operator==(const Node& other) const = default;
55+
56+
private:
57+
NodeType type;
58+
std::size_t start;
59+
std::size_t end;
60+
std::variant<std::string, std::vector<Node>> children;
4961
};
5062

5163
struct Token
5264
{
53-
TokenType type;
54-
std::string text;
55-
std::size_t start;
56-
std::size_t end;
65+
Token(TokenType type, std::string text, std::size_t start, std::size_t end);
5766

58-
bool operator==(const Token& other) const = default;
67+
TokenType Type() const;
68+
std::string Text() const;
69+
std::size_t Start() const;
70+
std::size_t End() const;
5971

6072
static bool IsEscapeCharacter(unsigned char ch);
6173
static TokenType TypeOf(unsigned char ch);
6274
static bool CanEscape(unsigned char ch);
6375
static std::string NameOf(TokenType type);
6476
static std::string SymbolOf(TokenType type);
6577
static std::string PurposeOf(TokenType type);
78+
79+
bool operator==(const Token& other) const = default;
80+
81+
private:
82+
TokenType type;
83+
std::string text;
84+
std::size_t start;
85+
std::size_t end;
6686
};
6787
}
6888

cucumber_cpp/library/cucumber_expression/Errors.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ namespace cucumber_cpp::library::cucumber_expression
1717

1818
std::string PointAtLocated(const auto& node)
1919
{
20-
auto pointer = PointAt(node.start);
21-
if (node.start + 1 < node.end)
20+
auto pointer = PointAt(node.Start());
21+
if (node.Start() + 1 < node.End())
2222
{
23-
for (auto i = node.start + 1; i < node.end; ++i)
23+
for (auto i = node.Start() + 1; i < node.End(); ++i)
2424
pointer += "-";
2525
pointer += "^";
2626
}
@@ -66,7 +66,7 @@ namespace cucumber_cpp::library::cucumber_expression
6666

6767
AlternationNotAllowedInOptional::AlternationNotAllowedInOptional(std::string_view expression, const Token& token)
6868
: Error{
69-
token.start,
69+
token.Start(),
7070
expression,
7171
PointAtLocated(token),
7272
R"(An alternation can not be used inside an optional)",
@@ -77,7 +77,7 @@ Otherwise rephrase your expression or consider using a regular expression instea
7777

7878
InvalidParameterTypeNameInNode::InvalidParameterTypeNameInNode(std::string_view expression, const Token& token)
7979
: Error{
80-
token.start,
80+
token.Start(),
8181
expression,
8282
PointAtLocated(token),
8383
R"(Parameter names may not contain '{', '}', '(', ')', '\' or '/')",
@@ -87,7 +87,7 @@ Otherwise rephrase your expression or consider using a regular expression instea
8787

8888
MissingEndToken::MissingEndToken(std::string_view expression, TokenType beginToken, TokenType endToken, const Token& token)
8989
: Error{
90-
token.start,
90+
token.Start(),
9191
expression,
9292
PointAtLocated(token),
9393
std::format(R"(The '{}' does not have a matching '{}')", Token::SymbolOf(beginToken), Token::SymbolOf(endToken)),
@@ -97,17 +97,17 @@ Otherwise rephrase your expression or consider using a regular expression instea
9797

9898
NoEligibleParsers::NoEligibleParsers(std::span<const Token> tokens)
9999
: std::runtime_error{
100-
std::format("No eligible parsers for [{}]", std::accumulate(tokens.begin() + 1, tokens.end(), Token::NameOf(tokens.begin()->type),
100+
std::format("No eligible parsers for [{}]", std::accumulate(tokens.begin() + 1, tokens.end(), Token::NameOf(tokens.begin()->Type()),
101101
[](const auto& acc, const auto& token) -> std::string
102102
{
103-
return acc + ", " + Token::NameOf(token.type);
103+
return acc + ", " + Token::NameOf(token.Type());
104104
})),
105105
}
106106
{}
107107

108108
OptionalMayNotBeEmpty::OptionalMayNotBeEmpty(const Node& node, std::string_view expression)
109109
: Error{
110-
node.start,
110+
node.Start(),
111111
expression,
112112
PointAtLocated(node),
113113
"An optional must contain some text",
@@ -117,7 +117,7 @@ Otherwise rephrase your expression or consider using a regular expression instea
117117

118118
ParameterIsNotAllowedInOptional::ParameterIsNotAllowedInOptional(const Node& node, std::string_view expression)
119119
: Error{
120-
node.start,
120+
node.Start(),
121121
expression,
122122
PointAtLocated(node),
123123
"An optional may not contain a parameter type",
@@ -127,7 +127,7 @@ Otherwise rephrase your expression or consider using a regular expression instea
127127

128128
OptionalIsNotAllowedInOptional::OptionalIsNotAllowedInOptional(const Node& node, std::string_view expression)
129129
: Error{
130-
node.start,
130+
node.Start(),
131131
expression,
132132
PointAtLocated(node),
133133
"An optional may not contain an other optional",
@@ -138,7 +138,7 @@ For more complicated expressions consider using a regular expression instead.)",
138138

139139
AlternativeMayNotExclusivelyContainOptionals::AlternativeMayNotExclusivelyContainOptionals(const Node& node, std::string_view expression)
140140
: Error{
141-
node.start,
141+
node.Start(),
142142
expression,
143143
PointAtLocated(node),
144144
"An alternative may not exclusively contain optionals",
@@ -148,7 +148,7 @@ For more complicated expressions consider using a regular expression instead.)",
148148

149149
AlternativeMayNotBeEmpty::AlternativeMayNotBeEmpty(const Node& node, std::string_view expression)
150150
: Error{
151-
node.start,
151+
node.Start(),
152152
expression,
153153
PointAtLocated(node),
154154
"Alternative may not be empty",
@@ -158,7 +158,7 @@ For more complicated expressions consider using a regular expression instead.)",
158158

159159
UndefinedParameterTypeError::UndefinedParameterTypeError(const Node& node, std::string_view expression, std::string_view undefinedParameterName)
160160
: Error{
161-
node.start,
161+
node.Start(),
162162
expression,
163163
PointAtLocated(node),
164164
std::format(R"('Undefined parameter type {}')", undefinedParameterName),

cucumber_cpp/library/cucumber_expression/Expression.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ namespace cucumber_cpp::library::cucumber_expression
6161

6262
std::string Expression::RewriteToRegex(const Node& node)
6363
{
64-
switch (node.type)
64+
switch (node.Type())
6565
{
6666
case NodeType::text:
6767
return EscapeRegex(node.Text());

cucumber_cpp/library/cucumber_expression/Expression.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ namespace cucumber_cpp::library::cucumber_expression
4545
{
4646
return std::views::filter(node.Children(), [type](const Node& child)
4747
{
48-
return child.type == type;
48+
return child.Type() == type;
4949
});
5050
}
5151

cucumber_cpp/library/cucumber_expression/ExpressionParser.cpp

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace cucumber_cpp::library::cucumber_expression
3636
if (position > tokens.size())
3737
return type == TokenType::endOfLine;
3838

39-
return tokens[position].type == type;
39+
return tokens[position].Type() == type;
4040
}
4141

4242
bool LookingAtAny(std::span<const Token> tokens, std::size_t position, std::vector<TokenType> types)
@@ -56,18 +56,18 @@ namespace cucumber_cpp::library::cucumber_expression
5656
if (index == 0)
5757
{
5858
const auto& rightSeparator = separators[index];
59-
retval.emplace_back(NodeType::alternative, start, rightSeparator.start, alternatives[index]);
59+
retval.emplace_back(NodeType::alternative, start, rightSeparator.Start(), alternatives[index]);
6060
}
6161
else if (index == max - 1)
6262
{
6363
const auto& leftSeparator = separators[index - 1];
64-
retval.emplace_back(NodeType::alternative, leftSeparator.end, end, alternatives[index]);
64+
retval.emplace_back(NodeType::alternative, leftSeparator.End(), end, alternatives[index]);
6565
}
6666
else
6767
{
6868
const auto& rightSeparator = separators[index];
6969
const auto& leftSeparator = separators[index - 1];
70-
retval.emplace_back(NodeType::alternative, leftSeparator.end, rightSeparator.start, alternatives[index]);
70+
retval.emplace_back(NodeType::alternative, leftSeparator.End(), rightSeparator.Start(), alternatives[index]);
7171
}
7272
}
7373
return retval;
@@ -80,7 +80,7 @@ namespace cucumber_cpp::library::cucumber_expression
8080

8181
for (const auto& node : alternation)
8282
{
83-
if (node.type == NodeType::alternative)
83+
if (node.Type() == NodeType::alternative)
8484
{
8585
separators.push_back(node);
8686
alternatives.emplace_back();
@@ -105,15 +105,15 @@ namespace cucumber_cpp::library::cucumber_expression
105105
ExpressionParser::SubParser parseText = { [](const ExpressionParser::ParserState& parser, const ExpressionParser::SubParser& /* subParser */) -> ExpressionParser::Result
106106
{
107107
const auto& token = parser.tokens[parser.current];
108-
if (MatchToken(token.type).in(TokenType::whiteSpace, TokenType::text, TokenType::endParameter, TokenType::endOptional))
108+
if (MatchToken(token.Type()).in(TokenType::whiteSpace, TokenType::text, TokenType::endParameter, TokenType::endOptional))
109109
return { 1, Node{
110110
NodeType::text,
111-
token.start,
112-
token.end,
113-
token.text,
111+
token.Start(),
112+
token.End(),
113+
token.Text(),
114114
} };
115115

116-
if (token.type == TokenType::alternation)
116+
if (token.Type() == TokenType::alternation)
117117
throw AlternationNotAllowedInOptional{ parser.expression, token };
118118

119119
return { 0, std::nullopt };
@@ -122,18 +122,18 @@ namespace cucumber_cpp::library::cucumber_expression
122122
ExpressionParser::SubParser parseName = { [](const ExpressionParser::ParserState& parser, const ExpressionParser::SubParser& /* subParser */) -> ExpressionParser::Result
123123
{
124124
const auto& token = parser.tokens[parser.current];
125-
if (MatchToken(token.type).in(TokenType::whiteSpace, TokenType::text))
125+
if (MatchToken(token.Type()).in(TokenType::whiteSpace, TokenType::text))
126126
return { 1, Node{
127127
NodeType::text,
128-
token.start,
129-
token.end,
130-
token.text,
128+
token.Start(),
129+
token.End(),
130+
token.Text(),
131131
} };
132132

133-
if (MatchToken(token.type).in(TokenType::beginParameter, TokenType::endParameter, TokenType::beginOptional, TokenType::endOptional, TokenType::alternation))
133+
if (MatchToken(token.Type()).in(TokenType::beginParameter, TokenType::endParameter, TokenType::beginOptional, TokenType::endOptional, TokenType::alternation))
134134
throw InvalidParameterTypeNameInNode{ parser.expression, token };
135135

136-
if (MatchToken(token.type).in(TokenType::startOfLine, TokenType::endOfLine))
136+
if (MatchToken(token.Type()).in(TokenType::startOfLine, TokenType::endOfLine))
137137
return { 0, std::nullopt };
138138

139139
return { 0, std::nullopt };
@@ -153,9 +153,9 @@ namespace cucumber_cpp::library::cucumber_expression
153153
auto token = tokens[parser.current];
154154
return Result(1, Node{
155155
NodeType::alternative,
156-
token.start,
157-
token.end,
158-
token.text,
156+
token.Start(),
157+
token.End(),
158+
token.Text(),
159159
});
160160
} };
161161

@@ -169,12 +169,12 @@ namespace cucumber_cpp::library::cucumber_expression
169169
auto subCurrent = parser.current + consumed;
170170
if (std::ranges::none_of(ast, [](const auto& node)
171171
{
172-
return node.type == NodeType::alternative;
172+
return node.Type() == NodeType::alternative;
173173
}))
174174
return { 0, std::nullopt };
175175

176-
auto start = tokens[parser.current].start;
177-
auto end = tokens[subCurrent].start;
176+
auto start = tokens[parser.current].Start();
177+
auto end = tokens[subCurrent].Start();
178178

179179
return { consumed, Node{
180180
NodeType::alternation,
@@ -213,8 +213,8 @@ namespace cucumber_cpp::library::cucumber_expression
213213
throw MissingEndToken{ parser.expression, beginToken, endToken, parser.tokens[parser.current] };
214214

215215
// consumed endToken
216-
auto start = parser.tokens[parser.current].start;
217-
auto end = parser.tokens[subCurrent].end;
216+
auto start = parser.tokens[parser.current].Start();
217+
auto end = parser.tokens[subCurrent].End();
218218
consumed = subCurrent + 1 - parser.current;
219219
return { consumed, Node{
220220
type,

0 commit comments

Comments
 (0)