Commit 8ea70e3d authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Export folly::json::parse_error

Summary:
[Folly] Export `folly::json::parse_error` v.s. having it be a hidden type.

* Move class body to `.h`.
* Leave helper function, previously the constructor, in anonymous namespace in `.cpp`.

Reviewed By: vitaut

Differential Revision: D17578773

fbshipit-source-id: 0d50fdf662bbf67e844ff0ec9ef24975cea92f62
parent a8d1fd8e
...@@ -37,8 +37,21 @@ namespace folly { ...@@ -37,8 +37,21 @@ namespace folly {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
namespace json { namespace json {
namespace { namespace {
parse_error make_parse_error(
unsigned int line,
std::string const& context,
std::string const& expected) {
return parse_error(to<std::string>(
"json parse error on line ",
line,
!context.empty() ? to<std::string>(" near `", context, '\'') : "",
": ",
expected));
}
struct Printer { struct Printer {
explicit Printer( explicit Printer(
std::string& out, std::string& out,
...@@ -51,7 +64,7 @@ struct Printer { ...@@ -51,7 +64,7 @@ struct Printer {
case dynamic::DOUBLE: case dynamic::DOUBLE:
if (!opts_.allow_nan_inf && if (!opts_.allow_nan_inf &&
(std::isnan(v.asDouble()) || std::isinf(v.asDouble()))) { (std::isnan(v.asDouble()) || std::isinf(v.asDouble()))) {
throw std::runtime_error( throw json::parse_error(
"folly::toJson: JSON object value was a " "folly::toJson: JSON object value was a "
"NaN or INF"); "NaN or INF");
} }
...@@ -91,7 +104,7 @@ struct Printer { ...@@ -91,7 +104,7 @@ struct Printer {
private: private:
void printKV(const std::pair<const dynamic, dynamic>& p) const { void printKV(const std::pair<const dynamic, dynamic>& p) const {
if (!opts_.allow_non_string_keys && !p.first.isString()) { if (!opts_.allow_non_string_keys && !p.first.isString()) {
throw std::runtime_error( throw json::parse_error(
"folly::toJson: JSON object key was not a " "folly::toJson: JSON object key was not a "
"string"); "string");
} }
...@@ -193,19 +206,6 @@ struct Printer { ...@@ -193,19 +206,6 @@ struct Printer {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
struct FOLLY_EXPORT ParseError : std::runtime_error {
explicit ParseError(
unsigned int line,
std::string const& context,
std::string const& expected)
: std::runtime_error(to<std::string>(
"json parse error on line ",
line,
!context.empty() ? to<std::string>(" near `", context, '\'') : "",
": ",
expected)) {}
};
// Wraps our input buffer with some helper functions. // Wraps our input buffer with some helper functions.
struct Input { struct Input {
explicit Input(StringPiece range, json::serialization_opts const* opts) explicit Input(StringPiece range, json::serialization_opts const* opts)
...@@ -281,7 +281,7 @@ struct Input { ...@@ -281,7 +281,7 @@ struct Input {
void expect(char c) { void expect(char c) {
if (**this != c) { if (**this != c) {
throw ParseError( throw json::make_parse_error(
lineNum_, context(), to<std::string>("expected '", c, '\'')); lineNum_, context(), to<std::string>("expected '", c, '\''));
} }
++*this; ++*this;
...@@ -323,7 +323,7 @@ struct Input { ...@@ -323,7 +323,7 @@ struct Input {
} }
dynamic error(char const* what) const { dynamic error(char const* what) const {
throw ParseError(lineNum_, context(), what); throw json::make_parse_error(lineNum_, context(), what);
} }
json::serialization_opts const& getOpts() { json::serialization_opts const& getOpts() {
......
...@@ -166,6 +166,11 @@ void escapeString( ...@@ -166,6 +166,11 @@ void escapeString(
*/ */
std::string stripComments(StringPiece jsonC); std::string stripComments(StringPiece jsonC);
class FOLLY_EXPORT parse_error : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
// may be extened in future to include offset, col, etc. // may be extened in future to include offset, col, etc.
struct parse_location { struct parse_location {
uint32_t line{}; // 0-indexed uint32_t line{}; // 0-indexed
......
...@@ -25,6 +25,7 @@ using folly::dynamic; ...@@ -25,6 +25,7 @@ using folly::dynamic;
using folly::parseJson; using folly::parseJson;
using folly::parseJsonWithMetadata; using folly::parseJsonWithMetadata;
using folly::toJson; using folly::toJson;
using folly::json::parse_error;
TEST(Json, Unicode) { TEST(Json, Unicode) {
auto val = parseJson(u8"\"I \u2665 UTF-8\""); auto val = parseJson(u8"\"I \u2665 UTF-8\"");
...@@ -78,12 +79,12 @@ TEST(Json, Parse) { ...@@ -78,12 +79,12 @@ TEST(Json, Parse) {
EXPECT_TRUE(std::isnan(parseJson("NaN").asDouble())); EXPECT_TRUE(std::isnan(parseJson("NaN").asDouble()));
// case matters // case matters
EXPECT_THROW(parseJson("infinity"), std::runtime_error); EXPECT_THROW(parseJson("infinity"), parse_error);
EXPECT_THROW(parseJson("inf"), std::runtime_error); EXPECT_THROW(parseJson("inf"), parse_error);
EXPECT_THROW(parseJson("Inf"), std::runtime_error); EXPECT_THROW(parseJson("Inf"), parse_error);
EXPECT_THROW(parseJson("INF"), std::runtime_error); EXPECT_THROW(parseJson("INF"), parse_error);
EXPECT_THROW(parseJson("nan"), std::runtime_error); EXPECT_THROW(parseJson("nan"), parse_error);
EXPECT_THROW(parseJson("NAN"), std::runtime_error); EXPECT_THROW(parseJson("NAN"), parse_error);
auto array = parseJson("[12,false, false , null , [12e4,32, [], 12]]"); auto array = parseJson("[12,false, false , null , [12e4,32, [], 12]]");
EXPECT_EQ(array.size(), 5); EXPECT_EQ(array.size(), 5);
...@@ -91,12 +92,11 @@ TEST(Json, Parse) { ...@@ -91,12 +92,11 @@ TEST(Json, Parse) {
EXPECT_EQ(std::prev(array.end())->size(), 4); EXPECT_EQ(std::prev(array.end())->size(), 4);
} }
EXPECT_THROW(parseJson("\n[12,\n\nnotvalidjson"), std::runtime_error); EXPECT_THROW(parseJson("\n[12,\n\nnotvalidjson"), parse_error);
EXPECT_THROW(parseJson("12e2e2"), std::runtime_error); EXPECT_THROW(parseJson("12e2e2"), parse_error);
EXPECT_THROW( EXPECT_THROW(parseJson("{\"foo\":12,\"bar\":42} \"something\""), parse_error);
parseJson("{\"foo\":12,\"bar\":42} \"something\""), std::runtime_error);
// clang-format off // clang-format off
dynamic value = dynamic::object dynamic value = dynamic::object
...@@ -353,7 +353,7 @@ TEST(Json, ParseTrailingComma) { ...@@ -353,7 +353,7 @@ TEST(Json, ParseTrailingComma) {
EXPECT_EQ(arr, parseJson("[1, 2, ]", on)); EXPECT_EQ(arr, parseJson("[1, 2, ]", on));
EXPECT_EQ(arr, parseJson("[1, 2 , ]", on)); EXPECT_EQ(arr, parseJson("[1, 2 , ]", on));
EXPECT_EQ(arr, parseJson("[1, 2 ,]", on)); EXPECT_EQ(arr, parseJson("[1, 2 ,]", on));
EXPECT_THROW(parseJson("[1, 2,]", off), std::runtime_error); EXPECT_THROW(parseJson("[1, 2,]", off), parse_error);
dynamic obj = dynamic::object("a", 1); dynamic obj = dynamic::object("a", 1);
EXPECT_EQ(obj, parseJson("{\"a\": 1}", on)); EXPECT_EQ(obj, parseJson("{\"a\": 1}", on));
...@@ -361,7 +361,7 @@ TEST(Json, ParseTrailingComma) { ...@@ -361,7 +361,7 @@ TEST(Json, ParseTrailingComma) {
EXPECT_EQ(obj, parseJson("{\"a\": 1, }", on)); EXPECT_EQ(obj, parseJson("{\"a\": 1, }", on));
EXPECT_EQ(obj, parseJson("{\"a\": 1 , }", on)); EXPECT_EQ(obj, parseJson("{\"a\": 1 , }", on));
EXPECT_EQ(obj, parseJson("{\"a\": 1 ,}", on)); EXPECT_EQ(obj, parseJson("{\"a\": 1 ,}", on));
EXPECT_THROW(parseJson("{\"a\":1,}", off), std::runtime_error); EXPECT_THROW(parseJson("{\"a\":1,}", off), parse_error);
} }
TEST(Json, BoolConversion) { TEST(Json, BoolConversion) {
...@@ -389,7 +389,7 @@ TEST(Json, Produce) { ...@@ -389,7 +389,7 @@ TEST(Json, Produce) {
// We're not allowed to have non-string keys in json. // We're not allowed to have non-string keys in json.
EXPECT_THROW( EXPECT_THROW(
toJson(dynamic::object("abc", "xyz")(42.33, "asd")), std::runtime_error); toJson(dynamic::object("abc", "xyz")(42.33, "asd")), parse_error);
// Check Infinity/Nan // Check Infinity/Nan
folly::json::serialization_opts opts; folly::json::serialization_opts opts;
...@@ -604,7 +604,7 @@ TEST(Json, ParseNonStringKeys) { ...@@ -604,7 +604,7 @@ TEST(Json, ParseNonStringKeys) {
// check that we don't allow non-string keys as this violates the // check that we don't allow non-string keys as this violates the
// strict JSON spec (though it is emitted by the output of // strict JSON spec (though it is emitted by the output of
// folly::dynamic with operator <<). // folly::dynamic with operator <<).
EXPECT_THROW(parseJson("{1:[]}"), std::runtime_error); EXPECT_THROW(parseJson("{1:[]}"), parse_error);
// check that we can parse colloquial JSON if the option is set // check that we can parse colloquial JSON if the option is set
folly::json::serialization_opts opts; folly::json::serialization_opts opts;
...@@ -713,14 +713,14 @@ TEST(Json, ParseNumbersAsStrings) { ...@@ -713,14 +713,14 @@ TEST(Json, ParseNumbersAsStrings) {
EXPECT_EQ("-Infinity", parse("-Infinity")); EXPECT_EQ("-Infinity", parse("-Infinity"));
EXPECT_EQ("NaN", parse("NaN")); EXPECT_EQ("NaN", parse("NaN"));
EXPECT_THROW(parse("ThisIsWrong"), std::runtime_error); EXPECT_THROW(parse("ThisIsWrong"), parse_error);
EXPECT_THROW(parse("34-2"), std::runtime_error); EXPECT_THROW(parse("34-2"), parse_error);
EXPECT_THROW(parse(""), std::runtime_error); EXPECT_THROW(parse(""), parse_error);
EXPECT_THROW(parse("-"), std::runtime_error); EXPECT_THROW(parse("-"), parse_error);
EXPECT_THROW(parse("34-e2"), std::runtime_error); EXPECT_THROW(parse("34-e2"), parse_error);
EXPECT_THROW(parse("34e2.4"), std::runtime_error); EXPECT_THROW(parse("34e2.4"), parse_error);
EXPECT_THROW(parse("infinity"), std::runtime_error); EXPECT_THROW(parse("infinity"), parse_error);
EXPECT_THROW(parse("nan"), std::runtime_error); EXPECT_THROW(parse("nan"), parse_error);
} }
TEST(Json, SortKeys) { TEST(Json, SortKeys) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment