summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-05-31 01:15:44 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2015-05-31 01:15:44 +0100
commit78faf65a4b0cea4e245d897a955b4336d14bebf1 (patch)
tree82f523697ba67b6fcc1fcaf39fd6db2eee41f4f2
parentSwitch to run rule, intead of test (diff)
downloadlibjsonpp-78faf65a4b0cea4e245d897a955b4336d14bebf1.tar.bz2
libjsonpp-78faf65a4b0cea4e245d897a955b4336d14bebf1.tar.xz
libjsonpp-78faf65a4b0cea4e245d897a955b4336d14bebf1.zip
Switch to using a flex based parser, not a hand-rolled character consumerlibjsonpp-0.9
-rw-r--r--libjsonpp/Jamfile.jam4
-rw-r--r--libjsonpp/json.ll153
-rw-r--r--libjsonpp/jsonFlexLexer.cpp102
-rw-r--r--libjsonpp/jsonFlexLexer.h44
-rw-r--r--libjsonpp/jsonpp.h10
-rw-r--r--libjsonpp/parse.cpp240
-rw-r--r--libjsonpp/pch.hpp4
-rw-r--r--libjsonpp/test1.cpp139
8 files changed, 437 insertions, 259 deletions
diff --git a/libjsonpp/Jamfile.jam b/libjsonpp/Jamfile.jam
index ce6a1f7..2983e68 100644
--- a/libjsonpp/Jamfile.jam
+++ b/libjsonpp/Jamfile.jam
@@ -1,5 +1,6 @@
import package ;
import testing ;
+import lex ;
alias glibmm : : : :
<cflags>"`pkg-config --cflags glibmm-2.4`"
@@ -15,10 +16,11 @@ cpp-pch pch : pch.hpp :
<library>glibmm
;
lib jsonpp :
- pch [ glob *.cpp : test*.cpp ]
+ pch [ glob *.cpp *.ll : test*.cpp ]
:
<include>.
<library>glibmm
+ <cflags>-Wno-error=sign-compare
: :
<include>.
;
diff --git a/libjsonpp/json.ll b/libjsonpp/json.ll
new file mode 100644
index 0000000..94be11f
--- /dev/null
+++ b/libjsonpp/json.ll
@@ -0,0 +1,153 @@
+%option batch
+%option c++
+%option noyywrap
+%option 8bit
+%option stack
+%option yylineno
+%option yyclass="json::jsonFlexLexer"
+
+%{
+#include "jsonFlexLexer.h"
+#include <boost/lexical_cast.hpp>
+#include <boost/bind.hpp>
+%}
+
+beginobj "{"
+endobj "}"
+beginarray "["
+endarray "]"
+beginstr "\""
+endstr "\""
+true "true"
+false "false"
+bool {true|false}
+null "null"
+number [-+]?[0-9]+(\.[0-9]+)?
+colon ":"
+separator ","
+escape "\\"
+
+%x OBJECT_ITEM
+%x OBJECT_NEXT
+%x ARRAY_ITEM
+%x ARRAY_NEXT
+%x COLON
+%x TEXT
+%x VALUE
+%x STRING
+%x ESCAPE
+
+%%
+
+<ARRAY_ITEM,VALUE>{true} {
+ PushBoolean(true);
+ yy_pop_state();
+}
+
+<ARRAY_ITEM,VALUE>{false} {
+ PushBoolean(false);
+ yy_pop_state();
+}
+
+<ARRAY_ITEM,VALUE>{number} {
+ PushNumber(boost::lexical_cast<double>(YYText()));
+ yy_pop_state();
+}
+
+<ARRAY_ITEM,VALUE>{null} {
+ PushNull();
+ yy_pop_state();
+}
+
+<ARRAY_ITEM,VALUE,OBJECT_ITEM>{beginstr} {
+ yy_push_state(STRING);
+}
+
+<ARRAY_ITEM,VALUE>{beginobj} {
+ BeginObject();
+ BEGIN(OBJECT_ITEM);
+}
+
+<ARRAY_ITEM,VALUE>{beginarray} {
+ BeginArray();
+ BEGIN(ARRAY_NEXT);
+ yy_push_state(ARRAY_ITEM);
+}
+
+<STRING>{endstr} {
+ yy_pop_state();
+ switch (YY_START) {
+ case ARRAY_ITEM:
+ case VALUE:
+ PushText(encodeBuf());
+ yy_pop_state();
+ break;
+ case OBJECT_ITEM:
+ name = encodeBuf();
+ BEGIN(COLON);
+ break;
+ }
+ buf.clear();
+}
+
+<OBJECT_NEXT>{endobj} {
+ PushObject();
+ yy_pop_state();
+}
+
+<ARRAY_ITEM,ARRAY_NEXT>{endarray} {
+ PushArray();
+ yy_pop_state();
+}
+
+<COLON>{colon} {
+ BEGIN(OBJECT_NEXT);
+ yy_push_state(VALUE);
+}
+
+<OBJECT_NEXT>{separator} {
+ BEGIN(OBJECT_ITEM);
+}
+
+<ARRAY_NEXT>{separator} {
+ yy_push_state(VALUE);
+}
+
+<STRING>{escape} {
+ yy_push_state(ESCAPE);
+}
+
+<ESCAPE>"\"" { buf += "\""; yy_pop_state(); }
+<ESCAPE>"\\" { buf += "\\"; yy_pop_state(); }
+<ESCAPE>"/" { buf += "/"; yy_pop_state(); }
+<ESCAPE>"b" { buf += "\b"; yy_pop_state(); }
+<ESCAPE>"f" { buf += "\f"; yy_pop_state(); }
+<ESCAPE>"n" { buf += "\n"; yy_pop_state(); }
+<ESCAPE>"r" { buf += "\r"; yy_pop_state(); }
+<ESCAPE>"t" { buf += "\t"; yy_pop_state(); }
+
+<ESCAPE>"u"[0-9a-fA-Z]{4} {
+ buf += Glib::ustring(1, gunichar(strtol(YYText() + 1, NULL, 16)));
+ yy_pop_state();
+}
+
+<STRING>. {
+ buf += YYText();
+}
+
+<*>[ \t\r\n\f] {
+}
+
+<*>. {
+ throw ParseError(YYText(), yylineno, YY_START);
+}
+
+%%
+
+json::jsonFlexLexer::jsonFlexLexer(std::istream & in, const std::string &) :
+ yyFlexLexer(&in, NULL)
+{
+ yy_push_state(VALUE);
+ acceptValues.push(boost::bind(&jsonFlexLexer::RootValue, this, _1));
+}
+
diff --git a/libjsonpp/jsonFlexLexer.cpp b/libjsonpp/jsonFlexLexer.cpp
new file mode 100644
index 0000000..ec924c4
--- /dev/null
+++ b/libjsonpp/jsonFlexLexer.cpp
@@ -0,0 +1,102 @@
+#include <FlexLexer.h>
+#include "jsonFlexLexer.h"
+#include <boost/bind.hpp>
+#include <glibmm/convert.h>
+
+namespace json {
+ ValuePtr
+ jsonFlexLexer::getValue() const
+ {
+ return values.top();
+ }
+
+ Value *
+ jsonFlexLexer::RootValue(const Value & value)
+ {
+ auto v = ValuePtr(new Value(value));
+ values.push(v);
+ return v.get();
+ }
+
+ Value *
+ jsonFlexLexer::ArrayAppend(Array * array, const Value & value)
+ {
+ auto v = ValuePtr(new Value(value));
+ array->push_back(v);
+ return v.get();
+ }
+
+ Value *
+ jsonFlexLexer::ObjectMember(Object * object, const Value & value)
+ {
+ auto v = ValuePtr(new Value(value));
+ (*object)[name] = v;
+ return v.get();
+ }
+
+ std::string
+ jsonFlexLexer::encodeBuf() const
+ {
+ if (!encoding.empty()) {
+ return Glib::convert(buf, "utf-8", encoding);
+ }
+ return buf;
+ }
+
+ void
+ jsonFlexLexer::BeginObject()
+ {
+ auto object = boost::get<Object>(acceptValues.top()(Object()));
+ acceptValues.push(boost::bind(&jsonFlexLexer::ObjectMember, this, object, _1));
+ }
+
+ void
+ jsonFlexLexer::BeginArray()
+ {
+ auto array = boost::get<Array>(acceptValues.top()(Array()));
+ acceptValues.push(boost::bind(&jsonFlexLexer::ArrayAppend, this, array, _1));
+ }
+
+ void
+ jsonFlexLexer::PushNull()
+ {
+ acceptValues.top()(Null());
+ }
+
+ void
+ jsonFlexLexer::PushBoolean(bool value)
+ {
+ acceptValues.top()(value);
+ }
+
+ void
+ jsonFlexLexer::PushNumber(double value)
+ {
+ acceptValues.top()(value);
+ }
+
+ void
+ jsonFlexLexer::PushText(const std::string & value)
+ {
+ acceptValues.top()(value);
+ }
+
+ void
+ jsonFlexLexer::PushArray()
+ {
+ acceptValues.pop();
+ }
+
+ void
+ jsonFlexLexer::PushObject()
+ {
+ acceptValues.pop();
+ }
+
+ void
+ jsonFlexLexer::LexerError(const char * msg)
+ {
+ throw ParseError(msg, 0, 0);
+ }
+}
+
diff --git a/libjsonpp/jsonFlexLexer.h b/libjsonpp/jsonFlexLexer.h
new file mode 100644
index 0000000..e3be204
--- /dev/null
+++ b/libjsonpp/jsonFlexLexer.h
@@ -0,0 +1,44 @@
+#ifndef JSONFLEXLEXER_H
+#define JSONFLEXLEXER_H
+
+#include <string>
+#include "jsonpp.h"
+#include <stack>
+#include <boost/function.hpp>
+
+namespace json {
+ class jsonFlexLexer : public yyFlexLexer {
+ public:
+ jsonFlexLexer(std::istream &, const std::string & enc);
+
+ int yylex();
+ ValuePtr getValue() const;
+ void LexerError(const char * msg) override;
+
+ void BeginObject();
+ void BeginArray();
+
+ void PushBoolean(bool);
+ void PushNumber(double);
+ void PushNull();
+ void PushText(const std::string &);
+ void PushArray();
+ void PushObject();
+
+ private:
+ Value * RootValue(const Value &);
+ Value * ArrayAppend(Array *, const Value &);
+ Value * ObjectMember(Object *, const Value &);
+
+ std::string encodeBuf() const;
+
+ std::string buf, name, encoding;
+ std::stack<ValuePtr> values;
+
+ typedef boost::function<Value *(const Value &)> AcceptValue;
+ std::stack<AcceptValue> acceptValues;
+ };
+}
+
+#endif
+
diff --git a/libjsonpp/jsonpp.h b/libjsonpp/jsonpp.h
index a872fd9..f105bea 100644
--- a/libjsonpp/jsonpp.h
+++ b/libjsonpp/jsonpp.h
@@ -11,7 +11,7 @@
namespace json {
class ParseError : public std::invalid_argument {
public:
- ParseError(gunichar);
+ ParseError(const char *, int, int);
};
typedef Glib::ustring String;
@@ -33,12 +33,10 @@ namespace json {
Object parseObject(Glib::ustring::const_iterator &);
Object parseObject(const Glib::ustring &);
- String parseString(Glib::ustring::const_iterator & s);
- Number parseNumber(Glib::ustring::const_iterator & s);
- Boolean parseBoolean(Glib::ustring::const_iterator & s);
- Null parseNull(Glib::ustring::const_iterator & s);
+ Value parseValue(std::istream &);
+ Value parseValue(std::istream &, const std::string & encoding);
+ Value parseValue(const Glib::ustring & s);
Value parseValue(Glib::ustring::const_iterator & s);
- Array parseArray(Glib::ustring::const_iterator &);
void serializeObject(const Object &, std::ostream & s, const std::string & encoding);
void serializeValue(const Value &, std::ostream & s, const std::string & encoding);
diff --git a/libjsonpp/parse.cpp b/libjsonpp/parse.cpp
index f127e9d..d74d8f0 100644
--- a/libjsonpp/parse.cpp
+++ b/libjsonpp/parse.cpp
@@ -1,229 +1,37 @@
#include <pch.hpp>
#include "jsonpp.h"
+#include <FlexLexer.h>
+#include "jsonFlexLexer.h"
namespace json {
- ParseError::ParseError(gunichar c) :
- std::invalid_argument(Glib::ustring("Parse error at or near ") + Glib::ustring(1, c))
+ ParseError::ParseError(const char * at, int l, int s) :
+ std::invalid_argument(Glib::ustring::compose("Parse error at or near %1 (line %2, state %3)", at, l, s))
{
}
- String parseString(Glib::ustring::const_iterator & s) {
- while (Glib::Unicode::isspace(*s)) s++;
- if (*s++ != '"') throw ParseError(*--s);
- String str;
- while (*s != '"') {
- if (*s == '\\') {
- ++s;
- switch (*s) {
- case '"':
- str += '"';
- break;
- case '\\':
- str += '\\';
- break;
- case '/':
- str += '/';
- break;
- case 'b':
- str += gunichar(8);
- break;
- case 'f':
- str += gunichar(12);
- break;
- case 'n':
- str += gunichar(10);
- break;
- case 'r':
- str += gunichar(13);
- break;
- case 't':
- str += gunichar(9);
- break;
- case 'u':
- {
- unsigned int c = 0;
- for (int n = 0; n < 4; n += 1) {
- c *= 16;
- if (*s >= '0' && *s <= '9') {
- c += (*s - '0');
- }
- else if (*s >= 'a' && *s <= 'f') {
- c += (*s - 'a');
- }
- else if (*s >= 'A' && *s <= 'F') {
- c += (*s - 'A');
- }
- else {
- throw ParseError(*s);
- }
- s++;
- }
- str += gunichar(c);
- s--;
- }
- break;
- default:
- throw ParseError(*s);
- }
- }
- else {
- str += *s;
- }
- s++;
- }
- if (*s++ != '"') throw ParseError(*--s);
- return str;
+
+ Value parseValue(std::istream & s) {
+ return parseValue(s, std::string());
}
- Number parseNumber(Glib::ustring::const_iterator & s) {
- while (Glib::Unicode::isspace(*s)) s++;
- bool neg = false;
- double v = 0;
- if (*s == '-') {
- neg = true;
- s++;
- }
- bool dot = false, e = false;
- double frac = 1;
- unsigned int digits = 0;
- while (true) {
- if (Glib::Unicode::isdigit(*s)) {
- if (dot) {
- frac /= 10;
- v += (frac * (*s - '0'));
- }
- else {
- v *= 10;
- v += (*s - '0');
- digits += 1;
- }
- }
- else if (*s == '.') {
- if (dot || e) throw ParseError(*s);
- dot = true;
- }
- else if (*s == 'e' || *s == 'E') {
- e = true;
- s++;
- bool eneg = false;
- if (*s == '+') {
- }
- else if (*s == '-') {
- eneg = true;
- s++;
- }
- int ev = 0;
- while (Glib::Unicode::isdigit(*s)) {
- ev *= 10;
- ev += (*s - '0');
- s++;
- }
- while (ev--) {
- if (eneg) {
- v /= 10;
- }
- else {
- v *= 10;
- }
- }
- break;
- }
- else {
- break;
- }
- s++;
- }
- if (digits < 1) throw ParseError(*s);
- return neg ? -v : v;
+
+ Value parseValue(std::istream & s, const std::string & enc) {
+ jsonFlexLexer jfl(s, enc);
+ while (jfl.yylex()) ;
+ return *jfl.getValue();
}
- Value parseValue(Glib::ustring::const_iterator & s) {
- while (Glib::Unicode::isspace(*s)) s++;
- switch (*s) {
- case '"':
- return parseString(s);
- case '{':
- return parseObject(s);
- case '[':
- return parseArray(s);
- case 'n':
- return parseNull(s);
- case 't':
- case 'f':
- return parseBoolean(s);
- default:
- return parseNumber(s);
- }
+
+ Value parseValue(const Glib::ustring & s) {
+ std::stringstream stream(s);
+ return parseValue(stream);
}
+
Object parseObject(const Glib::ustring & s) {
- Glib::ustring::const_iterator i = s.begin();
- Object o = parseObject(i);
- if (i != s.end()) throw ParseError(*i);
- return o;
- }
- Object parseObject(Glib::ustring::const_iterator & s) {
- Object o;
- while (Glib::Unicode::isspace(*s)) s++;
- if (*s != '{') throw ParseError(*s);
- do {
- s++;
- while (Glib::Unicode::isspace(*s)) s++;
- if (*s == '}') return o;
- String key = parseString(s);
- while (Glib::Unicode::isspace(*s)) s++;
- if (*s++ != ':') throw ParseError(*--s);
- if (!o.insert(Object::value_type(key, ValuePtr(new Value(parseValue(s))))).second) throw ParseError(*s);
- while (Glib::Unicode::isspace(*s)) s++;
- } while (*s == ',');
- if (*s == '}') {
- s++;
- while (Glib::Unicode::isspace(*s)) s++;
- return o;
- }
- throw ParseError(*s);
+ return boost::get<Object>(parseValue(s));
}
- Array parseArray(Glib::ustring::const_iterator & s) {
- Array a;
- while (Glib::Unicode::isspace(*s)) s++;
- if (*s != '[') throw ParseError(*s);
- do {
- s++;
- while (Glib::Unicode::isspace(*s)) s++;
- if (*s == ']') {
- s++;
- return a;
- }
- a.push_back(ValuePtr(new Value(parseValue(s))));
- while (Glib::Unicode::isspace(*s)) s++;
- } while (*s == ',');
- if (*s == ']') {
- s++;
- return a;
- }
- throw ParseError(*s);
- }
- Null parseNull(Glib::ustring::const_iterator & s) {
- while (Glib::Unicode::isspace(*s)) s++;
- if (*s++ != 'n') throw ParseError(*--s);
- if (*s++ != 'u') throw ParseError(*--s);
- if (*s++ != 'l') throw ParseError(*--s);
- if (*s++ != 'l') throw ParseError(*--s);
- return Null();
- }
- Boolean parseBoolean(Glib::ustring::const_iterator & s) {
- while (Glib::Unicode::isspace(*s)) s++;
- if (*s == 't') {
- s++;
- if (*s++ != 'r') throw ParseError(*--s);
- if (*s++ != 'u') throw ParseError(*--s);
- if (*s++ != 'e') throw ParseError(*--s);
- return true;
- }
- else if (*s == 'f') {
- s++;
- if (*s++ != 'a') throw ParseError(*--s);
- if (*s++ != 'l') throw ParseError(*--s);
- if (*s++ != 's') throw ParseError(*--s);
- if (*s++ != 'e') throw ParseError(*--s);
- return false;
- }
- throw ParseError(*s);
+
+ Value parseValue(Glib::ustring::const_iterator & s) {
+ Glib::ustring::const_iterator start = s;
+ while (*s++) ;
+ return parseValue(Glib::ustring(start, --s));
}
}
+
diff --git a/libjsonpp/pch.hpp b/libjsonpp/pch.hpp
index c0123d3..97eb890 100644
--- a/libjsonpp/pch.hpp
+++ b/libjsonpp/pch.hpp
@@ -3,9 +3,13 @@
#define JSON_PCH
#include <boost/variant.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
#include <glibmm/ustring.h>
+#include <glibmm/convert.h>
#include <map>
#include <list>
+#include <stack>
#endif
#endif
diff --git a/libjsonpp/test1.cpp b/libjsonpp/test1.cpp
index e0bdf8f..8b18e3b 100644
--- a/libjsonpp/test1.cpp
+++ b/libjsonpp/test1.cpp
@@ -14,65 +14,97 @@ const boost::filesystem::path root(XSTR(ROOT));
BOOST_AUTO_TEST_CASE( parse_bool_true )
{
const Glib::ustring val(" true ");
- auto itr = val.begin();
- BOOST_REQUIRE_EQUAL(true, json::parseBoolean(itr));
+ BOOST_REQUIRE_EQUAL(true, boost::get<bool>(json::parseValue(val)));
}
BOOST_AUTO_TEST_CASE( parse_bool_false )
{
const Glib::ustring val(" false ");
- auto itr = val.begin();
- BOOST_REQUIRE_EQUAL(false, json::parseBoolean(itr));
+ BOOST_REQUIRE_EQUAL(false, boost::get<bool>(json::parseValue(val)));
}
-BOOST_AUTO_TEST_CASE( parse_bool_invalid )
+BOOST_AUTO_TEST_CASE( parse_invalid_value )
{
const Glib::ustring val(" meh ");
- auto itr = val.begin();
- BOOST_CHECK_THROW(json::parseBoolean(itr), json::ParseError );
+ BOOST_CHECK_THROW(json::parseValue(val), json::ParseError );
+}
+
+BOOST_AUTO_TEST_CASE( parse_int_1 )
+{
+ const Glib::ustring val(" 1 ");
+ BOOST_REQUIRE_EQUAL(1, boost::get<json::Number>(json::parseValue(val)));
+}
+
+BOOST_AUTO_TEST_CASE( parse_int_neg48 )
+{
+ const Glib::ustring val(" -48 ");
+ BOOST_REQUIRE_EQUAL(-48, boost::get<json::Number>(json::parseValue(val)));
}
BOOST_AUTO_TEST_CASE( parse_int_48 )
{
const Glib::ustring val(" 48 ");
- auto itr = val.begin();
- BOOST_REQUIRE_EQUAL(48, json::parseNumber(itr));
+ BOOST_REQUIRE_EQUAL(48, boost::get<json::Number>(json::parseValue(val)));
}
BOOST_AUTO_TEST_CASE( parse_float_pi )
{
const Glib::ustring val(" 3.14159265359 ");
- auto itr = val.begin();
- BOOST_REQUIRE_CLOSE(3.14159, json::parseNumber(itr), 0.001);
+ BOOST_REQUIRE_CLOSE(3.14159, boost::get<json::Number>(json::parseValue(val)), 0.001);
}
BOOST_AUTO_TEST_CASE( parse_array )
{
- const Glib::ustring val(" [ 1, 2, 3, [ 4, 5 ], {\"val\": 6} ] ");
- auto itr = val.begin();
- auto arr = json::parseArray(itr);
- BOOST_REQUIRE_EQUAL(5, arr.size());
+ const Glib::ustring val(" [ 1, 2, 3, [ 4, 5 ], {\"val1\": 6, \"val2\": [7, 8]}, 9, 10 ] ");
+ auto arr = boost::get<json::Array>(json::parseValue(val));
+ BOOST_REQUIRE_EQUAL(7, arr.size());
+ auto itr = arr.begin();
+ BOOST_REQUIRE_EQUAL(1, boost::get<json::Number>(**itr++));
+ BOOST_REQUIRE_EQUAL(2, boost::get<json::Number>(**itr++));
+ BOOST_REQUIRE_EQUAL(3, boost::get<json::Number>(**itr++));
+ boost::get<json::Array>(**itr++);
+ boost::get<json::Object>(**itr++);
+ BOOST_REQUIRE_EQUAL(9, boost::get<json::Number>(**itr++));
+ BOOST_REQUIRE_EQUAL(10, boost::get<json::Number>(**itr++));
+}
+
+BOOST_AUTO_TEST_CASE( parse_array_of_strings )
+{
+ const Glib::ustring val(" [ \"en\", \"de\", \"ro\", \"es\", \"fa\" ] ");
+ boost::get<json::Array>(json::parseValue(val));
}
BOOST_AUTO_TEST_CASE( parse_null )
{
const Glib::ustring val(" null ");
- auto itr = val.begin();
- json::parseNull(itr);
+ boost::get<json::Null>(json::parseValue(val));
}
-BOOST_AUTO_TEST_CASE( parse_null_invalid )
+BOOST_AUTO_TEST_CASE( parse_empty_array )
{
- const Glib::ustring val(" meh ");
- auto itr = val.begin();
- BOOST_CHECK_THROW(json::parseBoolean(itr), json::ParseError);
+ const Glib::ustring val(" [ ] ");
+ BOOST_REQUIRE(boost::get<json::Array>(json::parseValue(val)).empty());
+
+}
+
+BOOST_AUTO_TEST_CASE( parse_broken_array )
+{
+ const Glib::ustring val(" [ 1, 2, ] ");
+ BOOST_CHECK_THROW(json::parseValue(val), json::ParseError );
+}
+
+BOOST_AUTO_TEST_CASE( parse_nonsense_in_array )
+{
+ const Glib::ustring val(" [ 1, 2, nonsense ] ");
+ BOOST_CHECK_THROW(json::parseValue(val), json::ParseError );
}
BOOST_AUTO_TEST_CASE( parse_object )
{
const Glib::ustring val(" { \"a\": 1, \"b\": 2 } ");
- auto itr = val.begin();
- auto obj = json::parseObject(itr);
+ auto value = json::parseValue(val);
+ BOOST_REQUIRE_EQUAL(3, value.which());
+ auto obj = boost::get<json::Object>(value);
BOOST_REQUIRE_EQUAL(2, obj.size());
BOOST_REQUIRE_EQUAL(1, boost::get<json::Number>(*obj["a"]));
BOOST_REQUIRE_EQUAL(2, boost::get<json::Number>(*obj["b"]));
@@ -81,15 +113,13 @@ BOOST_AUTO_TEST_CASE( parse_object )
BOOST_AUTO_TEST_CASE( parse_string_simple )
{
const Glib::ustring val(" \"simple string\" ");
- auto itr = val.begin();
- BOOST_REQUIRE_EQUAL("simple string", json::parseString(itr));
+ BOOST_REQUIRE_EQUAL("simple string", boost::get<json::String>(json::parseValue(val)));
}
BOOST_AUTO_TEST_CASE( parse_object_withStringContainingQuote )
{
const Glib::ustring val(" { \"key1\": \"value1\", \"key2\": \"value\\\"2\\\"\", \"key3\": 3 } ");
- auto itr = val.begin();
- auto obj = json::parseObject(itr);
+ auto obj = json::parseObject(val);
BOOST_REQUIRE_EQUAL(3, obj.size());
BOOST_REQUIRE_EQUAL("value1", boost::get<json::String>(*obj["key1"]));
BOOST_REQUIRE_EQUAL("value\"2\"", boost::get<json::String>(*obj["key2"]));
@@ -99,24 +129,61 @@ BOOST_AUTO_TEST_CASE( parse_object_withStringContainingQuote )
BOOST_AUTO_TEST_CASE( parse_string_invalid_missingOpeningQuote )
{
const Glib::ustring val(" simple string\" ");
- auto itr = val.begin();
- BOOST_CHECK_THROW(json::parseString(itr), json::ParseError);
+ BOOST_CHECK_THROW(json::parseValue(val), json::ParseError);
}
BOOST_AUTO_TEST_CASE( parse_string_escapedQuote )
{
const Glib::ustring val(" \"A \\\"quoted\\\" string.\" ");
- auto itr = val.begin();
- BOOST_REQUIRE_EQUAL("A \"quoted\" string.", json::parseString(itr));
+ BOOST_REQUIRE_EQUAL("A \"quoted\" string.", boost::get<json::String>(json::parseValue(val)));
+}
+
+BOOST_AUTO_TEST_CASE( parse_string_escapedWhitespace )
+{
+ const Glib::ustring val(" \"A whitespace\\t\\r\\n\\b\\f string.\" ");
+ BOOST_REQUIRE_EQUAL("A whitespace\t\r\n\b\f string.", boost::get<json::String>(json::parseValue(val)));
+}
+
+BOOST_AUTO_TEST_CASE( parse_string_escapedSlashes )
+{
+ const Glib::ustring val(" \"A whitespace\\\\ \\/ string.\" ");
+ BOOST_REQUIRE_EQUAL("A whitespace\\ / string.", boost::get<json::String>(json::parseValue(val)));
+}
+
+BOOST_AUTO_TEST_CASE( parse_string_literalUnicode )
+{
+ const Glib::ustring val(" \"A Űņĩćőđē string.\" ");
+ BOOST_REQUIRE_EQUAL("A Űņĩćőđē string.", boost::get<json::String>(json::parseValue(val)));
+}
+
+BOOST_AUTO_TEST_CASE( parse_string_unknownEscape )
+{
+ const Glib::ustring val(" \"A \\z string.\" ");
+ BOOST_CHECK_THROW(json::parseValue(val), json::ParseError);
+}
+
+BOOST_AUTO_TEST_CASE( parse_string_shortUnicodeEscape )
+{
+ const Glib::ustring val(" \"A \\u017 string.\" ");
+ BOOST_CHECK_THROW(json::parseValue(val), json::ParseError);
+}
+
+BOOST_AUTO_TEST_CASE( parse_string_escapedUnicode )
+{
+ const Glib::ustring val(" \"A \\u0170\\u0146\\u0129\\u0107\\u0151\\u0111\\u0113 string.\" ");
+ BOOST_REQUIRE_EQUAL("A Űņĩćőđē string.", boost::get<json::String>(json::parseValue(val)));
}
BOOST_AUTO_TEST_CASE( parse_sample_complexFile )
{
std::ifstream inFile((root / "initial" / "sample1.json").string());
- std::stringstream buffer;
- buffer << inFile.rdbuf();
- Glib::ustring doc(buffer.str());
- Glib::ustring::const_iterator itr = doc.begin();
- json::Value obj = json::parseValue(itr);
+ json::Value obj = json::parseValue(inFile, "utf-8");
+}
+
+BOOST_AUTO_TEST_CASE( parse_from_itr )
+{
+ const Glib::ustring val(" \"A \\u0170\\u0146\\u0129\\u0107\\u0151\\u0111\\u0113 string.\" ");
+ auto itr = val.begin();
+ BOOST_REQUIRE_EQUAL("A Űņĩćőđē string.", boost::get<json::String>(json::parseValue(itr)));
}