Skip to content

Commit

Permalink
gtest additions and fixes
Browse files Browse the repository at this point in the history
- fix escaping/reading of special characters in json strings

Signed-off-by: Chris Dodd <cdodd@nvidia.com>
  • Loading branch information
ChrisDodd committed Feb 25, 2025
1 parent 57da1b0 commit 6adbb44
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 20 deletions.
2 changes: 1 addition & 1 deletion ir/json_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class JSONGenerator {
case OBJ_END:
BUG("invalid json output state for emit_tag");
}
out << '\"' << tag << "\" : ";
out << '\"' << cstring(tag).escapeJson() << "\" : ";
output_state = OBJ_AFTERTAG;
}

Expand Down
26 changes: 8 additions & 18 deletions ir/json_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,25 +295,15 @@ class JSONLoader {
v = as<JsonNumber>();
}
void unpack_json(big_int &v) { v = as<JsonNumber>().val; }
void unpack_json(std::string &v) {
if (is<JsonString>())
v = as<JsonString>();
}
void unpack_json(cstring &v) {
std::string tmp = as<JsonString>();
std::string::size_type p = 0;
while ((p = tmp.find('\\', p)) != std::string::npos) {
tmp.erase(p, 1);
switch (tmp[p]) {
case 'n':
tmp[p] = '\n';
break;
case 'r':
tmp[p] = '\r';
break;
case 't':
tmp[p] = '\t';
break;
}
p++;
}
if (!json->is<JsonNull>()) v = tmp;
if (is<JsonString>())
v = cstring(as<JsonString>());
else if (is<JsonNull>())
v = cstring();
}
void unpack_json(IR::ID &v) {
if (!json->is<JsonNull>()) v.name = as<JsonString>();
Expand Down
49 changes: 48 additions & 1 deletion ir/json_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ std::ostream &operator<<(std::ostream &out, const JsonData *json) {
}
out << "]";
} else if (auto *s = json->to<JsonString>()) {
out << "\"" << s->c_str() << "\"";
out << "\"" << cstring(*s).escapeJson() << "\"";

} else if (auto *num = json->to<JsonNumber>()) {
out << num->val;
Expand All @@ -68,6 +68,22 @@ std::ostream &operator<<(std::ostream &out, const JsonData *json) {
return out;
}

static int charcode(char *to, const char *p, int max) {
int ch = 0, i;
for (i = 0; i < max; ++i) {
if (p[i] >= '0' && p[i] <= '9')
ch = (ch << 4) + p[i] - '0';
else if (p[i] >= 'A' && p[i] <= 'F')
ch = (ch << 4) + p[i] - 'A' + 10;
else if (p[i] >= 'a' && p[i] <= 'f')
ch = (ch << 4) + p[i] - 'a' + 10;
else
break;
}
*to = ch;
return i;
}

std::istream &operator>>(std::istream &in, std::unique_ptr<JsonData> &json) {
while (in) {
char ch;
Expand Down Expand Up @@ -119,6 +135,37 @@ std::istream &operator>>(std::istream &in, std::unique_ptr<JsonData> &json) {
getline(in, more, '"');
s += more;
}
for (auto p = s.find('\\'); p != std::string::npos; p = s.find('\\', p)) {
s.erase(p, 1);
switch (s[p]) {
case '\\':
++p;
break;
case 'b':
s[p] = '\b';
break;
case 'f':
s[p] = '\f';
break;
case 'n':
s[p] = '\n';
break;
case 'r':
s[p] = '\r';
break;
case 't':
s[p] = '\t';
break;
case 'u':
s.erase(p+1, charcode(&s[p], &s[p+1], 4));
break;
case 'x':
s.erase(p+1, charcode(&s[p], &s[p+1], 2));
break;
default:
break;
}
}
json = std::make_unique<JsonString>(s);
return in;
}
Expand Down
67 changes: 67 additions & 0 deletions test/gtest/dumpjson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ limitations under the License.
#include "ir/visitor.h"

using namespace P4;
using namespace P4::literals;

TEST(IR, DumpJSON) {
auto c = new IR::Constant(2);
Expand All @@ -39,3 +40,69 @@ TEST(IR, DumpJSON) {
loader >> e2;
JSONGenerator(std::cout).emit(e2);
}


TEST(JSON, string_map) {
std::vector<string_map<std::string>> data; /* = {
FIXME -- should be able to initialize this as an initializer list
{ { "x", "\ttab" }, { "a", "\"" } },
{ { "?", "question" }, { "-", "dash" } } }; */
data.resize(2);
data[0]["x"] = "\ttab";
data[0]["a"] = "\"";
data[1]["?"] = "question";
data[1]["-"] = "dash";
data[1]["\x1c"] = "esc";

std::vector<string_map<std::string>> copy;

std::stringstream ss;
JSONGenerator(ss).emit(data);

// std::cout << ss.str();

JSONLoader(ss) >> copy;

EXPECT_EQ(data.size(), copy.size());
EXPECT_EQ(data[0], copy[0]);
EXPECT_EQ(data[1], copy[1]);
}

TEST(JSON, std_map) {
std::map<big_int, bitvec> data, copy;

data[big_int(1) << 100].setrange(100,100);
data[1] = bitvec(1);

std::stringstream ss;
JSONGenerator(ss).emit(data);

// std::cout << ss.str();

JSONLoader(ss) >> copy;

EXPECT_EQ(data, copy);
}

TEST(JSON, variant) {
std::vector<std::variant<int, std::string>> data, copy;

data.emplace_back(2);
data.emplace_back(10);
data.emplace_back("foobar");
data.emplace_back(10);
data.emplace_back(1);
data.emplace_back("x");

std::stringstream ss;
JSONGenerator(ss).emit(data);

// std::cout << ss.str();

JSONLoader(ss) >> copy;

EXPECT_EQ(data.size(), copy.size());
for (size_t i = 0; i < data.size() && i < copy.size(); ++i) {
EXPECT_EQ(data[i], copy[i]);
}
}

0 comments on commit 6adbb44

Please sign in to comment.