Skip to content

Commit 206f8e0

Browse files
committed
Implemented escape function.
Fixed multiline strings to discard whitespaces after a newline character.
1 parent 385d04f commit 206f8e0

File tree

1 file changed

+79
-4
lines changed

1 file changed

+79
-4
lines changed

Source/cppcson.cpp

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,70 @@ static const std::vector<Value> EMPTY_VECTOR;
77
static const std::map<std::string, Value> EMPTY_MAP;
88

99
static std::string escape(const std::string &str) {
10-
// TODO: escape
11-
return "";
10+
std::string result = "'";
11+
12+
if (!str.empty()) {
13+
result.reserve(2 + str.length());
14+
15+
size_t pos = 0;
16+
size_t nextUnprocessed = 0;
17+
18+
while (true) {
19+
pos = str.find_first_of("\"\'\b\f\n\r\t\\", pos);
20+
if (pos == std::string::npos) {
21+
break;
22+
}
23+
24+
if (pos != nextUnprocessed) {
25+
result += str.substr(nextUnprocessed, pos - nextUnprocessed);
26+
}
27+
28+
switch (str[pos]) {
29+
case '"': {
30+
result += "\\\"";
31+
break;
32+
}
33+
case '\'': {
34+
result += "\\'";
35+
break;
36+
}
37+
case '\b': {
38+
result += "\\b";
39+
break;
40+
}
41+
case '\f': {
42+
result += "\\f";
43+
break;
44+
}
45+
case '\n': {
46+
result += "\\n";
47+
break;
48+
}
49+
case '\r': {
50+
result += "\\r";
51+
break;
52+
}
53+
case '\t': {
54+
result += "\\t";
55+
break;
56+
}
57+
case '\\': {
58+
result += "\\\\";
59+
break;
60+
}
61+
}
62+
63+
++pos;
64+
nextUnprocessed = pos;
65+
}
66+
67+
if (nextUnprocessed != str.length()) {
68+
result += str.substr(nextUnprocessed);
69+
}
70+
}
71+
72+
result += "'";
73+
return result;
1274
}
1375

1476
static std::string escapeKey(const std::string &str) {
@@ -767,6 +829,7 @@ class Parser {
767829
auto isMultiline = false;
768830
long lastCodeUnit = -1;
769831
auto lastCodeUnitLocation = Location::unknown();
832+
auto newLine = false;
770833

771834
auto c = lookaheadChar();
772835
if (c == startChar) {
@@ -834,6 +897,14 @@ class Parser {
834897
text += '\'';
835898
break;
836899
}
900+
case 'b': {
901+
text += '\b';
902+
break;
903+
}
904+
case 'f': {
905+
text += '\f';
906+
break;
907+
}
837908
case 'n': {
838909
text += '\n';
839910
break;
@@ -908,11 +979,14 @@ class Parser {
908979
Location(escapeLine, escapeColumn));
909980
}
910981
}
911-
} else {
982+
} else if (!isspace(c) || !newLine) {
912983
text += c;
913984
}
985+
986+
newLine = (newLine && (c == ' ' || c == '\t')) || c == '\n';
914987
}
915988

989+
text.shrink_to_fit();
916990
return Token(TokenKind::String, combine(startLocation, endLine, endColumn),
917991
text);
918992
}
@@ -929,6 +1003,7 @@ class Parser {
9291003
Location location(startLocation.getStartLine(),
9301004
startLocation.getStartColumn(), endLine, endColumn);
9311005

1006+
text.shrink_to_fit();
9321007
if (text == "true") {
9331008
return Token(TokenKind::True, location);
9341009
} else if (text == "false") {
@@ -1111,7 +1186,7 @@ class Parser {
11111186
if (path != ".") {
11121187
itemPath += ".";
11131188
}
1114-
itemPath += itemKey;
1189+
itemPath += escapeKey(itemKey);
11151190

11161191
expect(TokenKind::Colon);
11171192

0 commit comments

Comments
 (0)