Skip to content

Commit 9c75aa1

Browse files
chore(sourcepp): add more parser utility functions, bump bufferstream
1 parent 441fa1b commit 9c75aa1

File tree

7 files changed

+132
-50
lines changed

7 files changed

+132
-50
lines changed

include/sourcepp/parser/Binary.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ class BufferStream;
1111
namespace sourcepp::parser::binary {
1212

1313
/**
14-
* Reads an integer from the stream, seeks there, reads a string, and seeks back
15-
* @param stream The BufferStream to modify
16-
* @param str String contents are read into this
17-
* @param offsetFrom The seek direction when reading the string
14+
* Reads an integer from the stream, seeks there, reads a string, and seeks back.
15+
* @param stream The BufferStream to modify.
16+
* @param str String contents are read into this.
17+
* @param offsetFrom The seek direction when reading the string.
1818
* @param subtractFromOffset This offset is subtracted from the read integer. Defaults to the size of an
19-
* integer since an integer was read from the stream before seeking to the string
19+
* integer since an integer was read from the stream before seeking to the string.
2020
*/
2121
void readStringAtOffset(BufferStream& stream, std::string& str, std::ios::seekdir offsetFrom = std::ios::cur, std::size_t subtractFromOffset = sizeof(int32_t));
2222

include/sourcepp/parser/Text.h

Lines changed: 66 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,72 +13,108 @@ constexpr std::string_view DEFAULT_MULTI_LINE_COMMENT_END = "*/";
1313
constexpr std::string_view DEFAULT_STRING_START = "\"";
1414
constexpr std::string_view DEFAULT_STRING_END = "\"";
1515
extern const std::unordered_map<char, char> DEFAULT_ESCAPE_SEQUENCES;
16+
extern const std::unordered_map<char, char> NO_ESCAPE_SEQUENCES;
1617

1718
/**
18-
* If a char is a newline character
19-
* @param c The char
20-
* @return The char is a newline character
19+
* If a char is a newline character.
20+
* @param c The char.
21+
* @return The char is a newline character.
2122
*/
2223
[[nodiscard]] bool isNewLine(char c);
2324

2425
/**
25-
* If a char is a whitespace character
26-
* @param c The char
27-
* @return The char is a whitespace character
26+
* If a char is a whitespace character.
27+
* @param c The char.
28+
* @return The char is a whitespace character.
2829
*/
2930
[[nodiscard]] bool isWhitespace(char c);
3031

3132
/**
32-
* If a char is a numerical character (0-9)
33-
* @param c The char
34-
* @return The char is a numerical character
33+
* If a char is a numerical character (0-9).
34+
* @param c The char.
35+
* @return The char is a numerical character.
3536
*/
3637
[[nodiscard]] bool isNumber(char c);
3738

3839
/**
39-
* If a single line comment is detected, eat its contents
40-
* @param stream The BufferStream to modify
40+
* Eat all whitespace after the current stream position.
41+
* @param stream The BufferStream to modify.
42+
*/
43+
void eatWhitespace(BufferStream& stream);
44+
45+
/**
46+
* If a single line comment is detected, eat its contents.
47+
* This function does not handle the detection of single line comments!
48+
* @param stream The BufferStream to modify.
4149
*/
4250
void eatSingleLineComment(BufferStream& stream);
4351

4452
/**
45-
* If a multi line comment is detected, eat its contents
46-
* @param stream The BufferStream to modify
47-
* @param multiLineCommentEnd The multi line comment ending to search for
53+
* If a multi line comment is detected, eat its contents.
54+
* This function does not handle the detection of multi line comments!
55+
* @param stream The BufferStream to modify.
56+
* @param multiLineCommentEnd The multi line comment ending to search for.
4857
*/
4958
void eatMultiLineComment(BufferStream& stream, std::string_view multiLineCommentEnd = DEFAULT_MULTI_LINE_COMMENT_END);
5059

5160
/**
52-
* Eat all whitespace and single line comments after the current stream position
53-
* @param stream The BufferStream to modify
54-
* @param singleLineCommentStart The single line comment start sequence. Leave empty to skip checking for single line comments
61+
* Eat all whitespace and single line comments after the current stream position.
62+
* @param stream The BufferStream to modify.
63+
* @param singleLineCommentStart The single line comment start sequence. Leave empty to skip checking for single line comments.
5564
*/
5665
void eatWhitespaceAndSingleLineComments(BufferStream& stream, std::string_view singleLineCommentStart = DEFAULT_SINGLE_LINE_COMMENT_START);
5766

5867
/**
59-
* Eat all whitespace and multi line comments after the current stream position
60-
* @param stream The BufferStream to modify
61-
* @param multiLineCommentStart The multi line comment start sequence. Leave empty to skip checking for multi line comments
68+
* Eat all whitespace and multi line comments after the current stream position.
69+
* @param stream The BufferStream to modify.
70+
* @param multiLineCommentStart The multi line comment start sequence. Leave empty to skip checking for multi line comments.
6271
*/
6372
void eatWhitespaceAndMultiLineComments(BufferStream& stream, std::string_view multiLineCommentStart = DEFAULT_MULTI_LINE_COMMENT_START);
6473

6574
/**
66-
* Eat all whitespace and comments after the current stream position
67-
* @param stream The BufferStream to modify
68-
* @param singleLineCommentStart The single line comment start sequence. Leave empty to skip checking for single line comments
69-
* @param multiLineCommentStart The multi line comment start sequence. Leave empty to skip checking for multi line comments
75+
* Eat all whitespace and comments after the current stream position.
76+
* @param stream The BufferStream to modify.
77+
* @param singleLineCommentStart The single line comment start sequence. Leave empty to skip checking for single line comments.
78+
* @param multiLineCommentStart The multi line comment start sequence. Leave empty to skip checking for multi line comments.
7079
*/
7180
void eatWhitespaceAndComments(BufferStream& stream, std::string_view singleLineCommentStart = DEFAULT_SINGLE_LINE_COMMENT_START, std::string_view multiLineCommentStart = DEFAULT_MULTI_LINE_COMMENT_START);
7281

7382
/**
74-
* Read a string starting at the current stream position
83+
* If the given char exists at the current position, skip over it
7584
* @param stream The BufferStream to modify
76-
* @param backing The BufferStream to store the string data in
77-
* @param start The starting string chars. If any char matches this, the string will be treated as "quoted" and will include spaces
78-
* @param end The ending string chars. If any char matches this, and a starting char is detected, the string will terminate
79-
* @param escapeSequences Characters that will be escaped if a backslash is present before them. To disable escapes, pass an empty map
80-
* @return A view over the string written to the backing stream
85+
* @param c The char to compare
86+
* @return If the char exists at the current position
87+
*/
88+
[[nodiscard]] bool tryToEatChar(BufferStream& stream, char c);
89+
90+
/**
91+
* Read a string starting at the current stream position.
92+
* @param stream The BufferStream to modify.
93+
* @param backing The BufferStream to store the string data in.
94+
* @param start The starting string chars. If any processed char is in this string, the string will be treated as "quoted" and will include spaces.
95+
* @param end The ending string chars. If any processed char is in this string, and a starting char is detected, the string will terminate.
96+
* @param escapeSequences Characters that will be escaped if a backslash is present before them. To disable escapes, pass an empty map.
97+
* @return A view over the string written to the backing stream.
8198
*/
8299
[[nodiscard]] std::string_view readStringToBuffer(BufferStream& stream, BufferStream& backing, std::string_view start = DEFAULT_STRING_START, std::string_view end = DEFAULT_STRING_END, const std::unordered_map<char, char>& escapeSequences = DEFAULT_ESCAPE_SEQUENCES);
83100

101+
/**
102+
* Read a string starting at the current stream position.
103+
* @param stream The BufferStream to modify.
104+
* @param backing The BufferStream to store the string data in.
105+
* @param escapeSequences Characters that will be escaped if a backslash is present before them. To disable escapes, pass an empty map.
106+
* @return A view over the string written to the backing stream.
107+
*/
108+
[[nodiscard]] std::string_view readUnquotedStringToBuffer(BufferStream& stream, BufferStream& backing, const std::unordered_map<char, char>& escapeSequences = DEFAULT_ESCAPE_SEQUENCES);
109+
110+
/**
111+
* Read a string starting at the current stream position.
112+
* @param stream The BufferStream to modify.
113+
* @param backing The BufferStream to store the string data in.
114+
* @param end The ending string chars. If any processed char is in this string, the string will terminate.
115+
* @param escapeSequences Characters that will be escaped if a backslash is present before them. To disable escapes, pass an empty map.
116+
* @return A view over the string written to the backing stream.
117+
*/
118+
[[nodiscard]] std::string_view readUnquotedStringToBuffer(BufferStream& stream, BufferStream& backing, std::string_view end, const std::unordered_map<char, char>& escapeSequences = DEFAULT_ESCAPE_SEQUENCES);
119+
84120
} // namespace sourcepp::parser::text

include/sourcepp/string/String.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
namespace sourcepp::string {
88

9-
bool contains(std::string_view s, char c);
9+
[[nodiscard]] bool contains(std::string_view s, char c);
10+
11+
[[nodiscard]] bool iequals(std::string_view s1, std::string_view s2);
1012

1113
void ltrim(std::string& s);
1214

@@ -20,13 +22,13 @@ void rtrim(std::string& s, std::string_view c);
2022

2123
void trim(std::string& s, std::string_view c);
2224

23-
std::vector<std::string> split(std::string_view s, char delim);
25+
[[nodiscard]] std::vector<std::string> split(std::string_view s, char delim);
2426

2527
void toLower(std::string& input);
2628

2729
void toUpper(std::string& input);
2830

29-
std::string padNumber(int number, int width, char pad = '0');
31+
[[nodiscard]] std::string padNumber(int number, int width, char pad = '0');
3032

3133
void normalizeSlashes(std::string& path, bool stripTerminalSlashes = true);
3234

src/kvpp/kvpp.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ void KV1Element::readElements(BufferStreamReadOnly& stream, BufferStream& backin
8686
while (true) {
8787
// Check if the block is over
8888
parser::text::eatWhitespaceAndSingleLineComments(stream);
89-
if (static_cast<char>(stream.peek(0)) == '}') {
89+
if (stream.peek<char>() == '}') {
9090
stream.skip();
9191
break;
9292
}
@@ -98,20 +98,20 @@ void KV1Element::readElements(BufferStreamReadOnly& stream, BufferStream& backin
9898
parser::text::eatWhitespaceAndSingleLineComments(stream);
9999
}
100100
// Read value
101-
if (stream.peek<char>(0) != '{') {
101+
if (stream.peek<char>() != '{') {
102102
elements.back().value = parser::text::readStringToBuffer(stream, backing, parser::text::DEFAULT_STRING_START, parser::text::DEFAULT_STRING_END, escapeSequences);
103103
parser::text::eatWhitespaceAndSingleLineComments(stream);
104104
}
105105
// Read conditional
106-
if (stream.peek<char>(0) == '[') {
106+
if (stream.peek<char>() == '[') {
107107
elements.back().conditional = parser::text::readStringToBuffer(stream, backing, "[", "]", escapeSequences);
108108
parser::text::eatWhitespaceAndSingleLineComments(stream);
109109
}
110110
// Read block
111-
if (stream.peek<char>(0) == '{') {
111+
if (stream.peek<char>() == '{') {
112112
stream.skip();
113113
parser::text::eatWhitespaceAndSingleLineComments(stream);
114-
if (stream.peek<char>(0) != '}') {
114+
if (stream.peek<char>() != '}') {
115115
readElements(stream, backing, elements.back().children, escapeSequences);
116116
} else {
117117
stream.skip();

src/sourcepp/parser/Text.cpp

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ const std::unordered_map<char, char> DEFAULT_ESCAPE_SEQUENCES = {
2323
{'v', '\v'},
2424
};
2525

26+
const std::unordered_map<char, char> NO_ESCAPE_SEQUENCES = {};
27+
2628
} // namespace parser::text
2729

2830
bool parser::text::isNewLine(char c) {
@@ -37,6 +39,11 @@ bool parser::text::isNumber(char c) {
3739
return std::isdigit(c);
3840
}
3941

42+
void parser::text::eatWhitespace(BufferStream& stream) {
43+
while (isWhitespace(stream.read<char>())) {}
44+
stream.seek(-1, std::ios::cur);
45+
}
46+
4047
void parser::text::eatSingleLineComment(BufferStream& stream) {
4148
while (!isNewLine(stream.read<char>())) {}
4249
}
@@ -57,12 +64,11 @@ void parser::text::eatWhitespaceAndMultiLineComments(BufferStream& stream, std::
5764

5865
// NOLINTNEXTLINE(*-no-recursion)
5966
void parser::text::eatWhitespaceAndComments(BufferStream& stream, std::string_view singleLineCommentStart, std::string_view multiLineCommentStart) {
60-
while (isWhitespace(stream.read<char>())) {}
61-
stream.seek(-1, std::ios::cur);
67+
eatWhitespace(stream);
6268

6369
if (!singleLineCommentStart.empty()) {
6470
if (std::ranges::equal(stream.read_span<char>(singleLineCommentStart.length()), singleLineCommentStart)) {
65-
text::eatSingleLineComment(stream);
71+
eatSingleLineComment(stream);
6672
eatWhitespaceAndComments(stream, singleLineCommentStart, multiLineCommentStart);
6773
return;
6874
} else {
@@ -72,7 +78,7 @@ void parser::text::eatWhitespaceAndComments(BufferStream& stream, std::string_vi
7278

7379
if (!multiLineCommentStart.empty()) {
7480
if (std::ranges::equal(stream.read_span<char>(multiLineCommentStart.length()), multiLineCommentStart)) {
75-
text::eatMultiLineComment(stream);
81+
eatMultiLineComment(stream);
7682
eatWhitespaceAndComments(stream, singleLineCommentStart, multiLineCommentStart);
7783
return;
7884
} else {
@@ -81,6 +87,14 @@ void parser::text::eatWhitespaceAndComments(BufferStream& stream, std::string_vi
8187
}
8288
}
8389

90+
bool parser::text::tryToEatChar(BufferStream& stream, char c) {
91+
if (stream.peek<char>() != c) {
92+
return false;
93+
}
94+
stream.skip();
95+
return true;
96+
}
97+
8498
std::string_view parser::text::readStringToBuffer(BufferStream& stream, BufferStream& backing, std::string_view start, std::string_view end, const std::unordered_map<char, char>& escapeSequences) {
8599
auto startSpan = backing.tell();
86100

@@ -92,10 +106,10 @@ std::string_view parser::text::readStringToBuffer(BufferStream& stream, BufferSt
92106
backing << c;
93107
}
94108

95-
for (c = stream.read<char>(); (stopAtWhitespace && !parser::text::isWhitespace(c)) || (!stopAtWhitespace && end.find(c) == std::string_view::npos); c = stream.read<char>()) {
109+
for (c = stream.read<char>(); (stopAtWhitespace && !isWhitespace(c)) || (!stopAtWhitespace && end.find(c) == std::string_view::npos); c = stream.read<char>()) {
96110
if (!escapeSequences.empty() && c == '\\') {
97111
auto n = stream.read<char>();
98-
if (stopAtWhitespace && parser::text::isWhitespace(n)) {
112+
if (stopAtWhitespace && isWhitespace(n)) {
99113
break;
100114
}
101115
if (escapeSequences.contains(n)) {
@@ -113,3 +127,29 @@ std::string_view parser::text::readStringToBuffer(BufferStream& stream, BufferSt
113127
backing << '\0';
114128
return {reinterpret_cast<const char*>(backing.data()) + startSpan, backing.tell() - 1 - startSpan};
115129
}
130+
131+
std::string_view parser::text::readUnquotedStringToBuffer(BufferStream& stream, BufferStream& backing, const std::unordered_map<char, char>& escapeSequences) {
132+
return readStringToBuffer(stream, backing, "", "", escapeSequences);
133+
}
134+
135+
std::string_view parser::text::readUnquotedStringToBuffer(BufferStream& stream, BufferStream& backing, std::string_view end, const std::unordered_map<char, char>& escapeSequences) {
136+
auto startSpan = backing.tell();
137+
138+
for (char c = stream.read<char>(); !isWhitespace(c) && end.find(c) == std::string_view::npos; c = stream.read<char>()) {
139+
if (!escapeSequences.empty() && c == '\\') {
140+
auto n = stream.read<char>();
141+
if (escapeSequences.contains(n)) {
142+
backing << escapeSequences.at(n);
143+
} else if (isWhitespace(n) || end.find(n) != std::string_view::npos) {
144+
break;
145+
} else {
146+
backing << c << n;
147+
}
148+
} else {
149+
backing << c;
150+
}
151+
}
152+
153+
backing << '\0';
154+
return {reinterpret_cast<const char*>(backing.data()) + startSpan, backing.tell() - 1 - startSpan};
155+
}

src/sourcepp/string/String.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ bool string::contains(std::string_view s, char c) {
1010
return std::find(s.begin(), s.end(), c) != s.end();
1111
}
1212

13+
bool string::iequals(std::string_view s1, std::string_view s2) {
14+
return std::ranges::equal(s1, s2, [](char a, char b) { return std::tolower(a) == std::tolower(b); });
15+
}
16+
1317
// https://stackoverflow.com/a/217605
1418

1519
void string::ltrim(std::string& s) {

0 commit comments

Comments
 (0)