Skip to content
Browse files

Initial version.

Got to the point where I need to use source control
  • Loading branch information...
0 parents commit 9217c3432fe4f5d6e171c48db75c99ecba2d9ccb @martin-seomoz martin-seomoz committed Apr 16, 2012
2 .gitignore
@@ -0,0 +1,2 @@
+*.o
+build/*
10 Json/.gitignore
@@ -0,0 +1,10 @@
+# The following files are generated by bison
+*.tab.*
+location.hh
+position.hh
+stack.hh
+
+# The following files are generated by flex
+*.lex.*
+
+
161 Json/JsonDom.h
@@ -0,0 +1,161 @@
+
+#ifndef THORSANVIL_JSON_JSON_DOM
+#define THORSANVIL_JSON_JSON_DOM
+
+#include "JsonException.h"
+
+#include <boost/ptr_container/ptr_vector.hpp>
+#include <boost/ptr_container/ptr_map.hpp>
+
+namespace ThorsAnvil
+{
+ namespace Json
+ {
+
+/* Functions:
+ * Json-Dom Object
+ * JsonValue;
+ * JsonMap;
+ * JsonArray;
+ *
+ * Internal Objects
+ * JsonValue Traits for conversion on extraction
+ * struct ParseTrait
+ * JsonValue derived type for different internal objects:
+ * struct JsonValue
+ * struct JsonString
+ * struct JsonNumber
+ * struct JsonBool
+ * struct JsonNULL
+ * struct JsonMap
+ * struct JsonArray
+ *
+ */
+
+/*
+ * Classes that are used to build a DOM of a Json-Object
+ */
+struct JsonValue;
+typedef boost::ptr_map<std::string, JsonValue> JsonMap;
+typedef boost::ptr_vector<JsonValue> JsonArray;
+enum JsonObjectType { JsonMapObject, JsonArrayObject };
+struct JsonObject
+{
+ JsonObjectType type;
+ union
+ {
+ JsonMap* map;
+ JsonArray* array;
+ } data;
+};
+typedef std::pair<std::auto_ptr<std::string>,std::auto_ptr<JsonValue> > JsonMapValue;
+
+/*
+ * Json only supports three types:
+ * String
+ * double
+ * bool
+ *
+ * The ParseTraits class provides a mapping from all other POD types to these basic types.
+ * It is used in JsonValue::getValue() to retrieve a value of appropriate type from the
+ * JsonValue object which is then converted to the type you want.
+ *
+ * e.g.
+ * int x = pv->getValue<int>(); Will get the JsonValue() internal state as a long
+ * truncating the value towards zero. Normal long to int
+ * conversion will be done before returning the value
+ * which may overflow the value.
+ */
+template<typename T> struct ParseTrait {};
+
+template<> struct ParseTrait<long double> { typedef double GetType;};
+template<> struct ParseTrait<double> { typedef double GetType;};
+template<> struct ParseTrait<float> { typedef double GetType;};
+
+//template<> struct ParseTrait<long long> { typedef long GetType;};
+template<> struct ParseTrait<long> { typedef long GetType;};
+template<> struct ParseTrait<int> { typedef long GetType;};
+template<> struct ParseTrait<short> { typedef long GetType;};
+template<> struct ParseTrait<signed char> { typedef long GetType;};
+
+//template<> struct ParseTrait<unsigned long long>{ typedef long GetType;};
+template<> struct ParseTrait<unsigned long> { typedef long GetType;};
+template<> struct ParseTrait<unsigned int> { typedef long GetType;};
+template<> struct ParseTrait<unsigned short> { typedef long GetType;};
+template<> struct ParseTrait<unsigned char> { typedef long GetType;};
+
+template<> struct ParseTrait<bool> { typedef bool GetType;};
+
+template<> struct ParseTrait<std::string> { typedef std::string GetType;};
+
+
+/*
+ * The base type of all values extracted from Json
+ */
+struct JsonValue
+{
+ virtual ~JsonValue() {}
+
+ template<typename T>
+ T getValue() const
+ {
+ typename ParseTrait<T>::GetType value;
+ this->setValue(value);
+ return value;
+ }
+
+ private:
+ virtual void setValue(long&) const { throw InvalidConversion();}
+ virtual void setValue(double&) const { throw InvalidConversion();}
+ virtual void setValue(bool&) const { throw InvalidConversion();}
+ virtual void setValue(std::string&) const { throw InvalidConversion();}
+};
+struct JsonStringItem: JsonValue
+{
+ std::auto_ptr<std::string> value;
+ JsonStringItem(std::auto_ptr<std::string>& data): value(data) {}
+
+ private:
+ virtual void setValue(std::string& dst) const {dst = *value;}
+};
+struct JsonNumberItem: JsonValue
+{
+ std::auto_ptr<std::string> value;
+ JsonNumberItem(std::auto_ptr<std::string>& data): value(data) {}
+ private:
+ virtual void setValue(long& dst) const {dst = std::atol(value->c_str());}
+ virtual void setValue(double& dst) const {dst = std::atof(value->c_str());}
+};
+struct JsonBoolItem: JsonValue
+{
+ bool value;
+ JsonBoolItem(bool data): value(data) {}
+ private:
+ virtual void setValue(bool& dst) const {dst = value;}
+};
+struct JsonNULLItem: JsonValue
+{
+ private:
+ virtual void setValue(long& dst) const {dst= 0;}
+ virtual void setValue(double& dst) const {dst= 0.0;}
+ virtual void setValue(bool& dst) const {dst= false;}
+ virtual void setValue(std::string& dst) const {dst.clear();}
+};
+struct JsonMapItem: JsonValue
+{
+ std::auto_ptr<JsonMap> value;
+ JsonMapItem(std::auto_ptr<JsonMap>& data): value(data) {}
+ private:
+};
+struct JsonArrayItem: JsonValue
+{
+ std::auto_ptr<JsonArray> value;
+ JsonArrayItem(std::auto_ptr<JsonArray>& data): value(data) {}
+ private:
+};
+
+ }
+}
+
+#endif
+
31 Json/JsonException.h
@@ -0,0 +1,31 @@
+
+#ifndef THORSANVIL_JSON_JSON_EXCEPTION_H
+#define THORSANVIL_JSON_JSON_EXCEPTION_H
+
+#include <stdexcept>
+
+namespace ThorsAnvil
+{
+ namespace Json
+ {
+
+/*
+ * Exceptions
+ */
+class JsonException: public std::runtime_error
+{ public: JsonException(std::string const& msg) : std::runtime_error(msg) {}
+};
+
+// Throw when trying to get an integer from a string or string from an integer etc.
+class InvalidConversion: public JsonException
+{ public: InvalidConversion(): JsonException("Invalid Conversion"){}};
+// Thrown when there is something wrong with the input stream
+class ParsingError: public JsonException
+{ public: ParsingError(std::string const& msg): JsonException(msg) {}};
+
+
+ }
+}
+
+#endif
+
51 Json/Lexer.l
@@ -0,0 +1,51 @@
+
+%option c++
+%option noyywrap
+%option prefix="JsonBase"
+
+%{
+
+#define IN_LEXER
+#include "ParserShiftReduce.tab.hpp"
+#include "ParserInterface.h"
+
+%}
+
+DIGIT [0-9]
+DIGIT1 [1-9]
+INTNUM {DIGIT1}{DIGIT}*
+FRACT "."{DIGIT}+
+FLOAT ({INTNUM}|0){FRACT}?
+EXP [eE][+-]?{DIGIT}+
+NUMBER -?{FLOAT}{EXP}?
+
+UNICODE \\u[A-Fa-f0-9]{4}
+ESCAPECHAR \\["\\/bfnrt]
+CHAR [^"\\]|{ESCAPECHAR}|{UNICODE}
+STRING \"{CHAR}*\"
+
+WHITESPACE [ \t\n]
+
+
+%%
+
+\{ {return '{';}
+\} {return '}';}
+\[ {return '[';}
+\] {return ']';}
+, {return ',';}
+: {return ':';}
+true {return yy::ParserShiftReduce::token::JSON_TRUE;}
+false {return yy::ParserShiftReduce::token::JSON_FALSE;}
+null {return yy::ParserShiftReduce::token::JSON_NULL;}
+{STRING} {return yy::ParserShiftReduce::token::JSON_STRING;}
+{NUMBER} {return yy::ParserShiftReduce::token::JSON_NUMBER;}
+
+{WHITESPACE} {/*IGNORE*/}
+. {throw ThorsAnvil::Json::ParsingError("Invalid Character in Lexer");}
+
+%%
+
+
+
+
20 Json/LexerJson.cpp
@@ -0,0 +1,20 @@
+
+#include "LexerJson.h"
+#include "ParserInterface.h"
+
+using namespace ThorsAnvil::Json;
+
+LexerJson::LexerJson(std::istream& input)
+ : JsonBaseFlexLexer(&input, &std::cerr)
+{}
+
+int LexerJson::yylex(ParserInterface& pi)
+{
+ return pi.lexResult(JsonBaseFlexLexer::yylex());
+}
+
+void LexerJson::LexerError(const char* msg)
+{
+ throw ParsingError(msg);
+}
+
34 Json/LexerJson.h
@@ -0,0 +1,34 @@
+
+
+#ifndef THORS_ANVIL_JSON_PARSER_LEXER_JSON_H
+#define THORS_ANVIL_JSON_PARSER_LEXER_JSON_H
+
+
+#ifndef IN_LEXER
+#ifdef yyFlexLexer
+#undef yyFlexLexer
+#endif
+#define yyFlexLexer JsonBaseFlexLexer
+#include <FlexLexer.h>
+#endif
+
+namespace ThorsAnvil
+{
+ namespace Json
+ {
+
+class ParserInterface;
+class LexerJson: public JsonBaseFlexLexer
+{
+ public:
+ LexerJson(std::istream& input);
+ int yylex(ParserInterface& pi);
+
+ virtual void LexerError(const char* msg);
+};
+
+ }
+}
+
+#endif
+
12 Json/Makefile
@@ -0,0 +1,12 @@
+
+
+THORSANVIL_ROOT = $(realpath ../)
+
+TARGET = json.slib
+EXTRA_HEADERS = ParserShiftReduce.tab.hpp location.hh position.hh stack.hh
+CLEAN_EXTRA = location.hh position.hh stack.hh
+NOCOVERAGE = Lexer.lex ParserShiftReduce.tab
+
+include ${THORSANVIL_ROOT}/build/tools/Makefile
+
+
134 Json/ParserInterface.cpp
@@ -0,0 +1,134 @@
+
+#include "ParserInterface.h"
+#include "JsonException.h"
+#include "LexerJson.h"
+
+#include <boost/lexical_cast.hpp>
+
+#include <string>
+#include <iterator>
+template<typename C>
+struct TransformJsonStringIter: std::iterator<std::input_iterator_tag, char, ptrdiff_t, char*,char&>
+{
+ C& cont;
+ bool lastWasSlash;
+ int unicodeCount;
+ uint32_t unicodeValue;
+ TransformJsonStringIter(C& c)
+ : cont(c)
+ , lastWasSlash(false)
+ , unicodeCount(0)
+ {}
+ TransformJsonStringIter& operator++() {return *this;}
+ TransformJsonStringIter& operator*() {return *this;}
+ void operator=(char x)
+ {
+ if (unicodeCount)
+ {
+ if (unicodeCount == 6)
+ {
+ if (x != '\\') { throw ThorsAnvil::Json::ParsingError("Surrogate pair(No Slash): \\uD8xx Must be followed by \\uDCxx");}
+ --unicodeCount;
+ }
+ else if (unicodeCount == 5)
+ {
+ if (x != 'u') { throw ThorsAnvil::Json::ParsingError("Surrogate pair(No u): \\uD8xx Must be followed by \\uDCxx");}
+ --unicodeCount;
+ }
+ else
+ {
+ unicodeValue <<= 4;
+ unicodeValue += ('0' <= x && x <= '9') ? (x - '0') : 10 + (('A' <= x && x <= 'F') ? (x - 'A') : (x - 'a'));
+ --unicodeCount;
+ if (unicodeCount == 0)
+ {
+ if (unicodeValue <= 0x7F)
+ {
+ // Encode as single UTF-8 character
+ cont.push_back(unicodeValue);
+ }
+ else if (unicodeValue <= 0x7FF)
+ {
+ // Encode as two UTF-8 characters
+ cont.push_back(0xC0 |((unicodeValue >> 6)));
+ cont.push_back(0x80 |((unicodeValue >> 0) & 0x3F));
+ }
+ else if (unicodeValue <= 0xFFFF)
+ {
+ if ((unicodeValue & 0xFC00) != 0xD800)
+ {
+ // Encode as three UTF-8 characters
+ cont.push_back(0xE0 |((unicodeValue >> 12)));
+ cont.push_back(0x80 |((unicodeValue >> 6) & 0x3F));
+ cont.push_back(0x80 |((unicodeValue >> 0) & 0x3F));
+ }
+ else
+ {
+ // We have a found first part of surrogate pair
+ unicodeCount = 6;
+ }
+ }
+ else
+ {
+ // Surrogate pair
+ if ((unicodeValue & 0xFC00FC00) != 0xD800DC00){ throw ThorsAnvil::Json::ParsingError("Surrogate pair(No DC): \\uD8xx Must be followed by \\uDCxx");}
+
+ // Decode surrogate pair
+ unicodeValue = 0x00010000 | ((unicodeValue & 0x03FF0000) >> 6) | (unicodeValue & 0x000003FF);
+
+ // Encode as 4 UTF-8 characters
+ cont.push_back(0xF0 |((unicodeValue >> 18)));
+ cont.push_back(0x80 |((unicodeValue >> 12) & 0x3F));
+ cont.push_back(0x80 |((unicodeValue >> 6) & 0x3F));
+ cont.push_back(0x80 |((unicodeValue >> 0) & 0x3F));
+ }
+ }
+ }
+ }
+ else if (lastWasSlash)
+ {
+ switch(x)
+ {
+ case '"': cont.push_back('"'); break;
+ case '\\': cont.push_back('\\'); break;
+ case '/': cont.push_back('/'); break;
+ case 'b': cont.push_back('\b'); break;
+ case 'f': cont.push_back('\f'); break;
+ case 'n': cont.push_back('\n'); break;
+ case 'r': cont.push_back('\r'); break;
+ case 't': cont.push_back('\t'); break;
+ case 'u': unicodeCount = 4; unicodeValue = 0; break;
+ }
+ lastWasSlash = false;
+ }
+ else
+ {
+ if (x == '\\')
+ { lastWasSlash = true;
+ }
+ else
+ { cont.push_back(x);
+ }
+ }
+ }
+};
+template<typename C> TransformJsonStringIter<C> make_TransformJsonStringIter(C& cont) {return TransformJsonStringIter<C>(cont);}
+
+std::string ThorsAnvil::Json::getString(LexerJson& lexer)
+{
+ char const* begin = lexer.YYText();
+ char const* end = begin + lexer.YYLeng();
+
+ std::string result;
+ // Use begin+1 and end-1 to remove the quotes
+ std::copy(begin+1, end-1, make_TransformJsonStringIter(result));
+
+ return result;
+}
+std::string ThorsAnvil::Json::getNumber(LexerJson& lexer)
+{
+ return std::string(lexer.YYText(), lexer.YYLeng());
+}
+
+
+
165 Json/ParserInterface.h
@@ -0,0 +1,165 @@
+
+#ifndef THORSANVIL_JSON_PARSER_PARSER_INTERFACE_H
+#define THORSANVIL_JSON_PARSER_PARSER_INTERFACE_H
+
+#include "JsonDom.h"
+#include "JsonException.h"
+
+#include <string>
+
+
+namespace ThorsAnvil
+{
+ namespace Json
+ {
+
+ class LexerJson;
+ class ParserInterface;
+
+/* Functions:
+ * std::string getString(LexerJson& lexer);
+ * std::string getNumber(LexerJson& lexer);
+ * int yylex(void*, LexerJson& lexer,ThorsAnvil::Json::ParserInterface& paser);
+ *
+ * Exceptions:
+ * class InvalidConversion
+ * class ParsingError
+ *
+ * Interface for Parsing
+ * struct ParserInterface
+ * struct ParserLogInterface (generated debug output)
+ * struct ParserCleanInterface
+ * struct ParserDomInterface
+ *
+ */
+
+/*
+ * Useful free functions
+ */
+std::string getString(LexerJson& lexer);
+std::string getNumber(LexerJson& lexer);
+int yylex(void*, LexerJson& lexer,ThorsAnvil::Json::ParserInterface& paser);
+
+/*
+ * The interface injected into the parser that will do the work.
+ */
+struct ParserInterface
+{
+ ~ParserInterface() {}
+ virtual void doneMap(JsonMap* map) = 0;
+ virtual void doneAray(JsonArray* array) = 0;
+ virtual void mapOpen() = 0;
+ virtual void mapClose() = 0;
+ virtual JsonMap* mapCreate() = 0;
+ virtual JsonMap* mapCreate(JsonMapValue* val) = 0;
+ virtual JsonMap* mapAppend(JsonMap* map, JsonMapValue* val) = 0;
+ virtual JsonMapValue* mapCreateElement(std::string* k,JsonValue* val) = 0;
+ virtual std::string* mapKeyNote(std::string* k) = 0;
+ virtual void arrayOpen() = 0;
+ virtual void arrayClose() = 0;
+ virtual JsonArray* arrayCreate() = 0;
+ virtual JsonArray* arrayCreate(JsonValue* val) = 0;
+ virtual JsonArray* arrayAppend(JsonArray* arr, JsonValue* val) = 0;
+ virtual JsonArray* arrayNote(JsonArray* arr) = 0;
+ virtual JsonValue* arrayCreateElement(JsonValue* val) = 0;
+ virtual JsonValue* valueParseMap(JsonMap* map) = 0;
+ virtual JsonValue* valueParseArray(JsonArray* arr) = 0;
+ virtual JsonValue* valueParseString(std::string* str) = 0;
+ virtual JsonValue* valueParseNumber(std::string* num) = 0;
+ virtual JsonValue* valueParseBool(bool value) = 0;
+ virtual JsonValue* valueParseNULL() = 0;
+ virtual std::string* getStringLexer(LexerJson& lexer) = 0;
+ virtual std::string* getNumberLexer(LexerJson& lexer) = 0;
+ virtual int lexResult(int val) { return val;}
+};
+
+struct ParseLogInterface: ParserInterface
+{
+ virtual void doneMap(JsonMap*) {std::cout << "JsonObject: JsonMap\n";}
+ virtual void doneAray(JsonArray*) {std::cout << "JsonObject: JsonArray\n";}
+ virtual void mapOpen() {}
+ virtual void mapClose() {std::cout << "JsonMap: { JsonMapValueListOpt }\n";}
+ virtual JsonMap* mapCreate() {std::cout << "JsonMapValueListOpt: EMPTY\n"; return NULL;}
+ virtual JsonMap* mapCreate(JsonMapValue*) {std::cout << "JsonMapValueList: JsonMapValue\n"; return NULL;}
+ virtual JsonMap* mapAppend(JsonMap*, JsonMapValue*) {std::cout << "JsonMapValueList: JsonMapValueList , JsonMapValue\n"; return NULL;}
+ virtual JsonMapValue* mapCreateElement(std::string*,JsonValue*) {std::cout << "JsonMapValue: JSON_STRING : JsonValue\n"; return NULL;}
+ virtual std::string* mapKeyNote(std::string*) { return NULL;}
+ virtual void arrayOpen() {}
+ virtual void arrayClose() {std::cout << "JsonArray: [ JsonArrayValueListOpt ]\n";}
+ virtual JsonArray* arrayCreate() {std::cout << "JsonArrayValueListOpt: EMPTY\n"; return NULL;}
+ virtual JsonArray* arrayCreate(JsonValue*) {std::cout << "JsonArrayValueList: JsonArrayValue\n"; return NULL;}
+ virtual JsonArray* arrayAppend(JsonArray*, JsonValue*) {std::cout << "JsonArrayValueList: JsonArrayListItem JsonArrayValue\n"; return NULL;}
+ virtual JsonArray* arrayNote(JsonArray*) {std::cout << "JsonArrayListItem: JsonArrayValueList ','"; return NULL;}
+ virtual JsonValue* arrayCreateElement(JsonValue*) {std::cout << "JsonArrayValue: JsonValue\n"; return NULL;}
+ virtual JsonValue* valueParseMap(JsonMap*) {std::cout << "JsonValue: JsonMap\n"; return NULL;}
+ virtual JsonValue* valueParseArray(JsonArray*) {std::cout << "JsonValue: JsonArray\n"; return NULL;}
+ virtual JsonValue* valueParseString(std::string*) {std::cout << "JsonValue: JsonString\n"; return NULL;}
+ virtual JsonValue* valueParseNumber(std::string*) {std::cout << "JsonValue: JsonNumber\n"; return NULL;}
+ virtual JsonValue* valueParseBool(bool) {std::cout << "JsonValue: JsonTrue\n"; return NULL;}
+ virtual JsonValue* valueParseNULL() {std::cout << "JsonValue: JsonFalse\n"; return NULL;}
+ virtual std::string* getStringLexer(LexerJson&) {std::cout << "JsonString: JSON_STRING\n"; return NULL;}
+ virtual std::string* getNumberLexer(LexerJson&) {std::cout << "JsonNumber: JSON_NUMBER\n"; return NULL;}
+ virtual int lexResult(int val) {std::cout << "LEX(" << val << ")\n"; return val;}
+};
+
+struct ParserCleanInterface: ParserInterface
+{
+ virtual void doneMap(JsonMap* map) { delete map;}
+ virtual void doneAray(JsonArray* array) { delete array;}
+ virtual void mapOpen() {}
+ virtual void mapClose() {}
+ virtual JsonMap* mapCreate() { return NULL;}
+ virtual JsonMap* mapCreate(JsonMapValue* val) { delete val; return NULL;}
+ virtual JsonMap* mapAppend(JsonMap* map, JsonMapValue* val) { std::auto_ptr<JsonMapValue> aval(val); delete map; return NULL;}
+ virtual JsonMapValue* mapCreateElement(std::string* k,JsonValue* val) { std::auto_ptr<JsonValue> aval(val); delete k; return NULL;}
+ virtual std::string* mapKeyNote(std::string* k) { delete k; return NULL;}
+ virtual void arrayOpen() {}
+ virtual void arrayClose() {}
+ virtual JsonArray* arrayCreate() { return NULL;}
+ virtual JsonArray* arrayCreate(JsonValue* val) { delete val; return NULL;}
+ virtual JsonArray* arrayAppend(JsonArray* arr, JsonValue* val) { std::auto_ptr<JsonArray> aarr(arr); delete val; return NULL;}
+ virtual JsonArray* arrayNote(JsonArray* arr) { delete arr; return NULL;}
+ virtual JsonValue* arrayCreateElement(JsonValue* val) { delete val; return NULL;}
+ virtual JsonValue* valueParseMap(JsonMap* map) { delete map; return NULL;}
+ virtual JsonValue* valueParseArray(JsonArray* arr) { delete arr; return NULL;}
+ virtual JsonValue* valueParseString(std::string* str) { delete str; return NULL;}
+ virtual JsonValue* valueParseNumber(std::string* num) { delete num; return NULL;}
+ virtual JsonValue* valueParseBool(bool) { return NULL;}
+ virtual JsonValue* valueParseNULL() { return NULL;}
+ virtual std::string* getStringLexer(LexerJson&) { return NULL;}
+ virtual std::string* getNumberLexer(LexerJson&) { return NULL;}
+};
+
+struct ParserDomInterface: ParserCleanInterface
+{
+ virtual JsonMap* mapCreate() { return new JsonMap();}
+ virtual JsonMap* mapCreate(JsonMapValue* val) { std::auto_ptr<JsonMapValue>aval(val);std::auto_ptr<JsonMap> amap(new JsonMap());amap->insert(*(aval->first), aval->second);return amap.release();}
+ virtual JsonMap* mapAppend(JsonMap* map, JsonMapValue* val) { std::auto_ptr<JsonMapValue>aval(val);std::auto_ptr<JsonMap> amap(map); amap->insert(*(aval->first), aval->second);return amap.release();}
+ virtual JsonMapValue* mapCreateElement(std::string* k,JsonValue* val) { std::auto_ptr<JsonValue> aval(val);std::auto_ptr<std::string> ak(k);
+ std::auto_ptr<JsonMapValue> result(new JsonMapValue);result->first = ak;result->second = aval;
+ return result.release();
+ }
+ virtual std::string* mapKeyNote(std::string* k) { return k;}
+ virtual JsonArray* arrayCreate() { return new JsonArray();}
+ virtual JsonArray* arrayCreate(JsonValue* val) { std::auto_ptr<JsonValue> aval(val);std::auto_ptr<JsonArray> aarr(new JsonArray());aarr->push_back(aval); return aarr.release();}
+ virtual JsonArray* arrayAppend(JsonArray* arr, JsonValue* val) { std::auto_ptr<JsonValue> aval(val);std::auto_ptr<JsonArray> aarr(arr); aarr->push_back(aval); return aarr.release();}
+ virtual JsonArray* arrayNote(JsonArray* arr) { return arr;}
+ virtual JsonValue* arrayCreateElement(JsonValue* val) { std::auto_ptr<JsonValue> aval(val); return aval.release();}
+
+ virtual JsonValue* valueParseMap(JsonMap* map) { std::auto_ptr<JsonMap> amap(map); return new JsonMapItem(amap);}
+ virtual JsonValue* valueParseArray(JsonArray* arr) { std::auto_ptr<JsonArray> aarr(arr); return new JsonArrayItem(aarr);}
+ virtual JsonValue* valueParseString(std::string* str) { std::auto_ptr<std::string> astr(str); return new JsonStringItem(astr);}
+ virtual JsonValue* valueParseNumber(std::string* num) { std::auto_ptr<std::string> anum(num); return new JsonNumberItem(anum);}
+ virtual JsonValue* valueParseBool(bool value) { return new JsonBoolItem(value);}
+ virtual JsonValue* valueParseNULL() { return new JsonNULLItem();}
+
+ virtual std::string* getStringLexer(LexerJson& lexer) { return new std::string(getString(lexer));}
+ virtual std::string* getNumberLexer(LexerJson& lexer) { return new std::string(getNumber(lexer));}
+};
+
+
+ }
+}
+
+#endif
+
148 Json/ParserRecursive.cpp
@@ -0,0 +1,148 @@
+
+
+#include "ParserRecursive.h"
+#include "ParserShiftReduce.tab.hpp"
+
+using namespace ThorsAnvil::Json;
+
+int ParserRecursive::error(int /*val*/, std::string const& msg)
+{
+ throw ThorsAnvil::Json::ParsingError(msg);
+}
+
+int ParserRecursive::JsonValueParse(int val, std::auto_ptr<JsonValue>& value)
+{
+ switch(val)
+ {
+ case '{': {
+ std::auto_ptr<JsonMap> map;
+ int result = JsonMapParse(yylex(), map);
+ if (result == 0)
+ { value.reset(pi.valueParseMap(map.release()));
+ }
+ return result;
+ }
+ case '[': {
+ std::auto_ptr<JsonArray> array;
+ int result = JsonArrayParse(yylex(), array);
+ if (result == 0)
+ { value.reset(pi.valueParseArray(array.release()));
+ }
+ return result;
+ }
+ case yy::ParserShiftReduce::token::JSON_STRING: value.reset(pi.valueParseString(pi.getStringLexer(lexer)));return 0;
+ case yy::ParserShiftReduce::token::JSON_NUMBER: value.reset(pi.valueParseNumber(pi.getNumberLexer(lexer)));return 0;
+ case yy::ParserShiftReduce::token::JSON_TRUE: value.reset(pi.valueParseBool(true)); return 0;
+ case yy::ParserShiftReduce::token::JSON_FALSE: value.reset(pi.valueParseBool(false)); return 0;
+ case yy::ParserShiftReduce::token::JSON_NULL: value.reset(pi.valueParseNULL()); return 0;
+ default:break;
+ }
+ return error(val, "syntax error");
+}
+int ParserRecursive::JsonMapValueListParse(int val, std::auto_ptr<JsonMap>& map)
+{
+ if (val == yy::ParserShiftReduce::token::JSON_STRING)
+ {
+ std::auto_ptr<std::string> key(pi.getStringLexer(lexer));
+ if ((val = yylex()) == ':')
+ {
+ key.reset(pi.mapKeyNote(key.release()));
+ std::auto_ptr<JsonValue> value;
+ if ((val = JsonValueParse(yylex(), value)) == 0)
+ {
+ std::auto_ptr<JsonMapValue> mapValue(pi.mapCreateElement(key.release(), value.release()));
+ if (map.get() == NULL)
+ {
+ map.reset(pi.mapCreate(mapValue.release()));
+ }
+ else
+ {
+ map.reset(pi.mapAppend(map.release(), mapValue.release()));
+ }
+ val = yylex();
+ switch(val)
+ {
+ case '}': return 0;
+ case ',': return JsonMapValueListParse(yylex(), map);
+ default:break;
+ }
+ }
+ }
+ }
+ return error(val, "syntax error");
+}
+
+int ParserRecursive::JsonArrayValueListParse(int val, std::auto_ptr<JsonArray>& array)
+{
+ std::auto_ptr<JsonValue> value;
+ if ((val = JsonValueParse(val, value)) == 0)
+ {
+ value.reset(pi.arrayCreateElement(value.release()));
+ if (array.get() == NULL)
+ {
+ array.reset(pi.arrayCreate(value.release()));
+ }
+ else
+ {
+ array.reset(pi.arrayAppend(array.release(), value.release()));
+ }
+ val = yylex();
+ switch(val)
+ {
+ case ']': return 0;
+ case ',': array.reset(pi.arrayNote(array.release())); return JsonArrayValueListParse(yylex(), array);
+ default:break;
+ }
+ }
+ return error(val, "syntax error");
+}
+int ParserRecursive::JsonMapParse(int val, std::auto_ptr<JsonMap>& map)
+{
+ pi.mapOpen();
+ int result;
+ if (val == '}')
+ {
+ map.reset(pi.mapCreate());
+ result = 0; /* Empty Map */
+ }
+ else
+ {
+ result = JsonMapValueListParse(val, map);
+ }
+ pi.mapClose();
+ return result;
+}
+int ParserRecursive::JsonArrayParse(int val, std::auto_ptr<JsonArray>& array)
+{
+ pi.arrayOpen();
+ int result;
+ if (val == ']')
+ {
+ array.reset(pi.arrayCreate());
+ result = 0; /* Empty Array */
+ }
+ else
+ {
+ result = JsonArrayValueListParse(val, array);
+ }
+ pi.arrayClose();
+ return result;
+}
+int ParserRecursive::parseJosnObject(int val)
+{
+ int result;
+ std::auto_ptr<JsonMap> map;
+ std::auto_ptr<JsonArray> array;
+ switch(val)
+ {
+ case '{': result = JsonMapParse(yylex(), map); pi.doneMap(map.release()); return result;
+ case '[': result = JsonArrayParse(yylex(), array); pi.doneAray(array.release()); return result;
+ default:break;
+ }
+ return error(val, "syntax error");
+}
+int ParserRecursive::parse()
+{
+ return parseJosnObject(yylex());
+}
+
42 Json/ParserRecursive.h
@@ -0,0 +1,42 @@
+
+#ifndef THORSANVIL_jSON_PARSER_PARSE_RECURSIVE_H
+#define THORSANVIL_jSON_PARSER_PARSE_RECURSIVE_H
+
+#include "ParserInterface.h"
+#include "LexerJson.h"
+
+
+namespace ThorsAnvil
+{
+ namespace Json
+ {
+
+class LexerJson;
+
+class ParserRecursive
+{
+ LexerJson& lexer;
+ ParserInterface& pi;
+
+ int JsonValueParse(int val, std::auto_ptr<JsonValue>& value);
+ int JsonMapValueListParse(int val, std::auto_ptr<JsonMap>& ma);
+ int JsonArrayValueListParse(int val, std::auto_ptr<JsonArray>& array);
+ int JsonMapParse(int val, std::auto_ptr<JsonMap>& map);
+ int JsonArrayParse(int val, std::auto_ptr<JsonArray>& array);
+ int parseJosnObject(int val);
+
+ int yylex() { return lexer.yylex(pi);}
+ int error(int val, std::string const& msg);
+
+ public:
+ ParserRecursive(LexerJson& l, ParserInterface& p)
+ : lexer(l)
+ , pi(p)
+ {}
+ int parse();
+};
+ }
+}
+
+#endif
+
114 Json/ParserShiftReduce.y
@@ -0,0 +1,114 @@
+
+%skeleton "lalr1.cc"
+%require "2.1a"
+%defines
+%define "parser_class_name" "ParserShiftReduce"
+
+%{
+
+#include "ParserInterface.h"
+#include "LexerJson.h"
+#include <stdexcept>
+
+using ThorsAnvil::Json::ParserInterface;
+using ThorsAnvil::Json::JsonValue;
+
+using ThorsAnvil::Json::JsonMap;
+using ThorsAnvil::Json::JsonArray;
+using ThorsAnvil::Json::JsonMapValue;
+
+using ThorsAnvil::Json::LexerJson;
+
+%}
+
+%parse-param {LexerJson& lexer}
+%parse-param {ParserInterface& pi}
+%lex-param {LexerJson& lexer}
+%lex-param {ParserInterface& pi}
+
+%union {
+ JsonMap* jsonMap;
+ JsonArray* jsonArray;
+ JsonMapValue* jsonMapValue;
+ JsonValue* jsonValue;
+ std::string* jsonString;
+ std::string* jsonNumber;
+}
+
+%token JSON_STRING
+%token JSON_NUMBER
+%token JSON_TRUE
+%token JSON_FALSE
+%token JSON_NULL
+
+%type <jsonValue> JsonValue
+%type <jsonString> JsonString
+%type <jsonNumber> JsonNumber
+
+%type <jsonMap> JsonMap
+%type <jsonMap> JsonMapValueListOpt
+%type <jsonMap> JsonMapValueList
+%type <jsonMapValue> JsonMapValue
+%type <jsonString> JsonMapKey
+
+%type <jsonArray> JsonArray
+%type <jsonArray> JsonArrayValueListOpt
+%type <jsonArray> JsonArrayValueList
+%type <jsonArray> JsonArrayListItem
+%type <jsonValue> JsonArrayValue
+
+%%
+
+JsonData : JsonObject {return 0;}
+
+JsonObject : JsonMap {pi.doneMap($1);}
+ | JsonArray {pi.doneAray($1);}
+
+JsonMap : '{' {pi.mapOpen();}
+ JsonMapValueListOpt
+ '}' {pi.mapClose();$$=$3}
+JsonMapValueListOpt : {$$ = pi.mapCreate();}
+ | JsonMapValueList {$$ = $1;}
+JsonMapValueList : JsonMapValue {$$ = pi.mapCreate($1);}
+ | JsonMapValueList ',' JsonMapValue {$$ = pi.mapAppend($1, $3);}
+JsonMapValue : JsonMapKey JsonValue {$$ = pi.mapCreateElement($1, $2);}
+JsonMapKey : JsonString ':' {$$ = pi.mapKeyNote($1);}
+
+
+JsonArray : '[' {pi.arrayOpen();}
+ JsonArrayValueListOpt
+ ']' {pi.arrayClose();$$=$3;}
+JsonArrayValueListOpt : {$$ = pi.arrayCreate();}
+ | JsonArrayValueList {$$ = $1;}
+JsonArrayValueList : JsonArrayValue {$$ = pi.arrayCreate($1);}
+ | JsonArrayListItem JsonArrayValue {$$ = pi.arrayAppend($1, $2);}
+JsonArrayListItem : JsonArrayValueList ',' {$$ = pi.arrayNote($1);}
+JsonArrayValue : JsonValue {$$ = pi.arrayCreateElement($1);}
+
+JsonValue : JsonMap {$$ = pi.valueParseMap($1);}
+ | JsonArray {$$ = pi.valueParseArray($1);}
+ | JsonString {$$ = pi.valueParseString($1);}
+ | JsonNumber {$$ = pi.valueParseNumber($1);}
+ | JsonTrue {$$ = pi.valueParseBool(true);}
+ | JsonFalse {$$ = pi.valueParseBool(false);}
+ | JsonNull {$$ = pi.valueParseNULL();}
+
+JsonString : JSON_STRING {$$ = pi.getStringLexer(lexer);}
+JsonNumber : JSON_NUMBER {$$ = pi.getNumberLexer(lexer);}
+JsonTrue : JSON_TRUE
+JsonFalse : JSON_FALSE
+JsonNull : JSON_NULL
+
+
+%%
+
+int ThorsAnvil::Json::yylex(void*, LexerJson& lexer, ParserInterface& pi)
+{
+ return lexer.yylex(pi);
+}
+
+void yy::ParserShiftReduce::error(yy::location const&, std::string const& msg)
+{
+ throw ThorsAnvil::Json::ParsingError(msg);
+}
+
44 Json/ScannerDom.cpp
@@ -0,0 +1,44 @@
+
+#include "ScannerDom.h"
+#include "LexerJson.h"
+#include "ParserShiftReduce.tab.hpp"
+#include "ParserRecursive.h"
+
+using namespace ThorsAnvil::Json;
+
+class ScannerDomInterface: public ParserDomInterface
+{
+ JsonObjectType& objectTypeRef;
+ std::auto_ptr<JsonMap>& mapRef;
+ std::auto_ptr<JsonArray>& arrayRef;
+ public:
+ ScannerDomInterface(JsonObjectType& objectType, std::auto_ptr<JsonMap>& map, std::auto_ptr<JsonArray>& array)
+ : objectTypeRef(objectType)
+ , mapRef(map)
+ , arrayRef(array)
+ {}
+
+ virtual void doneMap(JsonMap* map) { mapRef.reset(map); objectTypeRef = JsonMapObject; }
+ virtual void doneAray(JsonArray* array) { arrayRef.reset(array);objectTypeRef = JsonArrayObject; }
+};
+
+template<typename Parser>
+JsonObjectType ScannerDom::parse(std::istream& stream)
+{
+ map.release();
+ array.release();
+
+ ScannerDomInterface scanner(objectType, map, array);
+ LexerJson lexer(stream);
+ Parser parser(lexer, scanner);
+
+ // If this fails it throws.
+ parser.parse();
+
+ return objectType;
+}
+
+template JsonObjectType ScannerDom::parse<yy::ParserShiftReduce>(std::istream& stream);
+template JsonObjectType ScannerDom::parse<ThorsAnvil::Json::ParserRecursive>(std::istream& stream);
+
+
29 Json/ScannerDom.h
@@ -0,0 +1,29 @@
+
+#ifndef THORSANVIL_JSON_PARSER_SCANNER_DOM_H
+#define THORSANVIL_JSON_PARSER_SCANNER_DOM_H
+
+#include "ParserInterface.h"
+
+
+namespace ThorsAnvil
+{
+ namespace Json
+ {
+
+ class ScannerDom
+ {
+ std::auto_ptr<JsonMap> map;
+ std::auto_ptr<JsonArray> array;
+ JsonObjectType objectType;
+
+ public:
+ template<typename Parser>
+ JsonObjectType parse(std::istream& stream);
+ std::auto_ptr<JsonMap>& getMap() { return map;}
+ std::auto_ptr<JsonArray>& getArray() { return array;}
+ };
+ }
+}
+
+#endif
+
154 Json/ScannerSax.cpp
@@ -0,0 +1,154 @@
+
+
+#include "ScannerSax.h"
+#include "LexerJson.h"
+#include "ParserShiftReduce.tab.hpp"
+#include "ParserRecursive.h"
+
+#include <sstream>
+#include <list>
+
+namespace ThorsAnvil
+{
+ namespace Json
+ {
+
+class ScannerSaxInterface: public ParserCleanInterface
+{
+ std::list<int> currentArrayIndex;
+ ScannerSax& parent;
+ public:
+ ScannerSaxInterface(ScannerSax& p): parent(p) {}
+ virtual void mapOpen() { parent.push_mapAction();}
+ virtual void mapClose() { parent.pop_mapAction();}
+ virtual std::string* mapKeyNote(std::string* k) { std::auto_ptr<std::string> ak(k); parent.preActivate(*ak); return ak.release();}
+ virtual JsonMapValue* mapCreateElement(std::string* k,JsonValue* val) { std::auto_ptr<std::string> ak(k); std::auto_ptr<JsonValue> aval(val); parent.activate(*ak, *aval); return NULL;}
+ virtual void arrayOpen() { currentArrayIndex.push_front(0); parent.push_arrAction(); parent.preActivate(currentArrayIndex.front());}
+ virtual void arrayClose() { currentArrayIndex.pop_front(); parent.pop_arrAction();}
+ virtual JsonArray* arrayNote(JsonArray* arr) { std::auto_ptr<JsonArray> aarr(arr); parent.preActivate(currentArrayIndex.front());return NULL;}
+ virtual JsonValue* arrayCreateElement(JsonValue* val) { std::auto_ptr<JsonValue> aval(val); parent.activate(currentArrayIndex.front()++, *aval);return NULL;}
+ virtual JsonValue* valueParseString(std::string* str) { std::auto_ptr<std::string> astr(str); return new JsonStringItem(astr);}
+ virtual JsonValue* valueParseNumber(std::string* num) { std::auto_ptr<std::string> anum(num); return new JsonNumberItem(anum);}
+ virtual JsonValue* valueParseBool(bool val) { return new JsonBoolItem(val);}
+ virtual JsonValue* valueParseNULL() { return new JsonNULLItem();}
+ virtual std::string* getStringLexer(LexerJson& lexer) { return new std::string(getString(lexer));}
+ virtual std::string* getNumberLexer(LexerJson& lexer) { return new std::string(getNumber(lexer));}
+};
+ }
+}
+
+using namespace ThorsAnvil::Json;
+
+ScannerSax::ScannerSax()
+ : mapActions(1, ScannerMapActionMap())
+ , arrActions(1, ScannerArrActionMap())
+ , mapAction(mapActions.begin())
+ , arrAction(arrActions.begin())
+{
+ mapActions.push_front(ScannerMapActionMap());
+ arrActions.push_front(ScannerArrActionMap());
+}
+
+ScannerSax::~ScannerSax()
+{
+}
+
+template<typename Parser>
+void ScannerSax::parse(std::istream& src)
+{
+ ScannerSaxInterface scanner(*this);
+ LexerJson lexer(src);
+ Parser parser(lexer, scanner);
+
+ parser.parse();
+}
+
+ActionRefNote ScannerSax::registerAction(std::string const& mapItem, std::auto_ptr<SaxAction> action)
+{
+ SaxAction*& location = mapActions.front()[mapItem];
+ location = action.release();
+ return &location;
+}
+
+ActionRefNote ScannerSax::registerAction(int index, std::auto_ptr<SaxAction> action)
+{
+ SaxAction*& location = arrActions.front()[index];
+ location = action.release();
+ return &location;
+}
+
+void ScannerSax::replaceAction(ActionRefNote oldActionRef, std::auto_ptr<SaxAction> action)
+{
+ SaxAction*& location = *reinterpret_cast<SaxAction**>(oldActionRef);
+ std::auto_ptr<SaxAction> oldLocation(location);
+ location = action.release();
+}
+
+SaxAction* ScannerSax::getAction(std::string const& mapItem)
+{
+ SaxAction* action = NULL;
+ ScannerMapActionMap::const_iterator find1;
+ ScannerMapActionMap::const_iterator find2;
+ if ((find1 = mapAction->find(mapItem)) != mapAction->end())
+ {
+ action = find1->second;
+ }
+ else if ((find2 = mapAction->find("\xFF")) != mapAction->end())
+ {
+ action = find2->second;
+ }
+ return action;
+}
+SaxAction* ScannerSax::getAction(int index)
+{
+ SaxAction* action = NULL;
+ ScannerArrActionMap::const_iterator find;
+ if ((find = arrAction->find(index)) != arrAction->end())
+ {
+ action = find->second;
+ }
+ else if ((find = arrAction->find(-1)) != arrAction ->end())
+ {
+ action = find->second;
+ }
+ return action;
+}
+
+void ScannerSax::preActivate(std::string const& mapItem)
+{
+ SaxAction* action = getAction(mapItem);
+ if (action != NULL)
+ {
+ action->doPreAction(*this);
+ }
+}
+void ScannerSax::preActivate(int index)
+{
+ SaxAction* action = getAction(index);
+ if (action != NULL)
+ {
+ action->doPreAction(*this);
+ }
+}
+
+void ScannerSax::activate(std::string const& mapItem, JsonValue const& value)
+{
+ SaxAction* action = getAction(mapItem);
+ if (action != NULL)
+ {
+ action->doAction(*this, value);
+ }
+}
+void ScannerSax::activate(int index, JsonValue const& value)
+{
+ SaxAction* action = getAction(index);
+ if (action != NULL)
+ {
+ action->doAction(*this, value);
+ }
+}
+
+template void ScannerSax::parse<yy::ParserShiftReduce>(std::istream& src);
+template void ScannerSax::parse<ThorsAnvil::Json::ParserRecursive>(std::istream& src);
+
+
94 Json/ScannerSax.h
@@ -0,0 +1,94 @@
+
+#ifndef THORSANVIL_JSON_PARSER_SCANNER_SAX_H
+#define THORSANVIL_JSON_PARSER_SCANNER_SAX_H
+
+#include "ParserInterface.h"
+#include <string>
+#include <istream>
+#include <list>
+#include <map>
+
+namespace ThorsAnvil
+{
+ namespace Json
+ {
+
+class ScannerSax;
+struct SaxAction
+{
+ virtual ~SaxAction() {}
+ virtual void doAction(ScannerSax&, JsonValue const&) = 0;
+ virtual void doPreAction(ScannerSax&) = 0;
+};
+
+
+class ScannerSaxInterface;
+typedef void* ActionRefNote;
+class ScannerSax
+{
+ template<typename Key>
+ class PtrMap: public std::map<Key, SaxAction*>
+ {
+ void clean()
+ {
+ for(typename std::map<Key, SaxAction*>::const_iterator loop = this->begin(); loop != this->end(); ++loop)
+ {
+ delete loop->second;
+ }
+ }
+ public:
+ // Note: Copy constructor only works for empty map.
+ // The copy constructor is only used to push these object into a list when they are empty
+ // So that works OK
+ ~PtrMap()
+ {
+ clean();
+ }
+ void clear()
+ {
+ clean();
+ std::map<Key, SaxAction*>::clear();
+ }
+ };
+ typedef PtrMap<std::string> ScannerMapActionMap;
+ typedef std::list<ScannerMapActionMap> ScannerMapActionList;
+ typedef PtrMap<int> ScannerArrActionMap;
+ typedef std::list<ScannerArrActionMap> ScannerArrActionList;
+
+ ScannerMapActionList mapActions;
+ ScannerArrActionList arrActions;
+
+ ScannerMapActionList::const_iterator mapAction;
+ ScannerArrActionList::const_iterator arrAction;
+
+ public:
+ ~ScannerSax();
+ ScannerSax();
+ template<typename Parser>
+ void parse(std::istream& src);
+ ActionRefNote registerAction(std::string const& mapItem, std::auto_ptr<SaxAction> action);
+ ActionRefNote registerAction(int index, std::auto_ptr<SaxAction> action);
+ void replaceAction(ActionRefNote oldActionRef, std::auto_ptr<SaxAction> action);
+
+ private:
+ friend class ScannerSaxInterface;
+ void preActivate(std::string const& mapItem);
+ void preActivate(int index);
+ void activate(std::string const& mapItem, JsonValue const& value);
+ void activate(int index, JsonValue const& value);
+
+ SaxAction* getAction(std::string const& item);
+ SaxAction* getAction(int index);
+
+ void push_mapAction() {mapActions.push_front(ScannerMapActionMap());--mapAction;}
+ void push_arrAction() {arrActions.push_front(ScannerArrActionMap());--arrAction;}
+ void pop_mapAction() {mapActions.pop_front();mapActions.front().clear();++mapAction;}
+ void pop_arrAction() {arrActions.pop_front();arrActions.front().clear();++arrAction;}
+};
+
+
+ }
+}
+
+#endif
+
198 Json/test/LexerJsonTest.cpp
@@ -0,0 +1,198 @@
+
+#include "gtest/gtest.h"
+#include "LexerJson.h"
+#include "ParserInterface.h"
+#include "ParserShiftReduce.tab.hpp"
+
+#include <boost/lexical_cast.hpp>
+#include <sstream>
+
+
+TEST(LexerJson, EmptyStream)
+{
+ std::stringstream jsonElements("");
+ ThorsAnvil::Json::LexerJson parser(jsonElements);
+ ThorsAnvil::Json::ParserCleanInterface cleanInterface;
+
+ ASSERT_TRUE(parser.yylex(cleanInterface) == 0);
+}
+
+TEST(LexerJson, BasicElements)
+{
+ std::stringstream jsonElements("{} [] , : true false null");
+ ThorsAnvil::Json::LexerJson parser(jsonElements);
+ ThorsAnvil::Json::ParserCleanInterface cleanInterface;
+
+ ASSERT_TRUE(parser.yylex(cleanInterface) == '{');
+ ASSERT_TRUE(parser.yylex(cleanInterface) == '}');
+ ASSERT_TRUE(parser.yylex(cleanInterface) == '[');
+ ASSERT_TRUE(parser.yylex(cleanInterface) == ']');
+ ASSERT_TRUE(parser.yylex(cleanInterface) == ',');
+ ASSERT_TRUE(parser.yylex(cleanInterface) == ':');
+ ASSERT_TRUE(parser.yylex(cleanInterface) == yy::ParserShiftReduce::token::JSON_TRUE);
+ ASSERT_TRUE(parser.yylex(cleanInterface) == yy::ParserShiftReduce::token::JSON_FALSE);
+ ASSERT_TRUE(parser.yylex(cleanInterface) == yy::ParserShiftReduce::token::JSON_NULL);
+}
+
+template<typename T>
+bool validateNumber(ThorsAnvil::Json::LexerJson& parser, ThorsAnvil::Json::ParserInterface& interface, T const& value)
+{
+ bool parseOK = parser.yylex(interface) == yy::ParserShiftReduce::token::JSON_NUMBER;
+ if (parseOK)
+ {
+ parseOK = boost::lexical_cast<T>(ThorsAnvil::Json::getNumber(parser)) == value;
+ }
+ return parseOK;
+}
+
+TEST(LexerJson, Number)
+{
+ // Definition of Json number: http://www.json.org/number.gif
+
+ std::stringstream jsonElements("0 0.1 0.9 0e1 0e99 0E+2 0E-3 -0 1 2.1 3.9 4e1 5e99 6E+2 7E-3 -8 9 10 21.1 32.9 43e1 54e99 65E+2 76E-3 -87 98");
+ ThorsAnvil::Json::LexerJson parser(jsonElements);
+ ThorsAnvil::Json::ParserCleanInterface cleanInterface;
+
+ ASSERT_TRUE(validateNumber<int>(parser, cleanInterface, 0));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 0.1));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 0.9));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 0e1));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 0e99));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 0e+2));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 0e-3));
+ ASSERT_TRUE(validateNumber<int>(parser, cleanInterface, -0));
+
+
+ ASSERT_TRUE(validateNumber<int>(parser, cleanInterface, 1));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 2.1));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 3.9));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 4e1));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 5e99));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 6e+2));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 7e-3));
+ ASSERT_TRUE(validateNumber<int>(parser, cleanInterface, -8));
+ ASSERT_TRUE(validateNumber<int>(parser, cleanInterface, 9));
+
+ ASSERT_TRUE(validateNumber<int>(parser, cleanInterface, 10));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 21.1));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 32.9));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 43e1));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 54e99));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 65e+2));
+ ASSERT_TRUE(validateNumber<double>(parser, cleanInterface, 76e-3));
+ ASSERT_TRUE(validateNumber<int>(parser, cleanInterface, -87));
+ ASSERT_TRUE(validateNumber<int>(parser, cleanInterface, 98));
+}
+
+bool validateString(ThorsAnvil::Json::LexerJson& parser, ThorsAnvil::Json::ParserInterface& interface, std::string const& value)
+{
+ bool parseOK = parser.yylex(interface) == yy::ParserShiftReduce::token::JSON_STRING;
+ if (parseOK)
+ {
+ parseOK = ThorsAnvil::Json::getString(parser) == value;
+ }
+ return parseOK;
+}
+TEST(LexerJson, String)
+{
+ std::stringstream jsonElements("\"Text\" \"\\\"\" \"\\\\\" \"\\/\" \"\\b\" \"\\f\" \"\\n\" \"\\r\" \"\\t\" \"\\u0020\" \"\\u00a0\" \"\\u1Fd5\" \"\\uD834\\uDD1E\"");
+ ThorsAnvil::Json::LexerJson parser(jsonElements);
+ ThorsAnvil::Json::ParserCleanInterface cleanInterface;
+
+
+ ASSERT_TRUE(validateString(parser, cleanInterface, "Text"));
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\""));
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\\"));
+ ASSERT_TRUE(validateString(parser, cleanInterface, "/"));
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\b"));
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\f"));
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\n"));
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\r"));
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\t"));
+
+
+ /*
+ * The Unicode code point 002O is encoded in UTF-8 as 20
+ * see http://www.fileformat.info/info/unicode/char/20/index.htm
+ */
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\x020"));
+
+
+ /*
+ * The Unicode code point 00AO is encoded in UTF-8 as C2 A0
+ * see http://www.fileformat.info/info/unicode/char/A0/index.htm
+ */
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\x0c2\x0a0"));
+
+ /*
+ * The Unicode code point 1FD5 is encoded in UTF-8 as E1 BF 95
+ * see http://www.fileformat.info/info/unicode/char/1FD5/index.htm
+ */
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\x0e1\x0bf\x095"));
+
+ /*
+ * The unicode code point 1D11E is encoded in UTF-8 as 0xF0 0x9D 0x84 0x9E
+ * Note it is encode in Json as UTF-16 surrogate pair 0xD834 0xDD1E
+ * http://www.fileformat.info/info/unicode/char/1D11E/index.htm
+ */
+ ASSERT_TRUE(validateString(parser, cleanInterface, "\x0F0\x09D\x084\x09E"));
+
+}
+
+TEST(LexerJson, InvalidCharacter)
+{
+ std::stringstream jsonElements("\\ ");
+ ThorsAnvil::Json::LexerJson parser(jsonElements);
+ ThorsAnvil::Json::ParserCleanInterface cleanInterface;
+
+ // Only valid chaacters are "{}[]:, true false null <number> <string>"
+ // Find '\' character so throw
+ ASSERT_THROW(parser.yylex(cleanInterface), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(LexerJson, InvalidSlash)
+{
+ std::stringstream jsonElements("\"\\ \"");
+ ThorsAnvil::Json::LexerJson parser(jsonElements);
+ ThorsAnvil::Json::ParserCleanInterface cleanInterface;
+
+ // Inside a string all characters are valid.
+ // But a '\' must be followed by a valid escape code
+ ASSERT_THROW(parser.yylex(cleanInterface), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(LexerJson, InvalidUnicode)
+{
+ std::stringstream jsonElements("\"\\uG \"");
+ ThorsAnvil::Json::LexerJson parser(jsonElements);
+ ThorsAnvil::Json::ParserCleanInterface cleanInterface;
+
+ ASSERT_THROW(parser.yylex(cleanInterface), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(LexerJson, InvalidUnicodeSurogatePair)
+{
+ std::stringstream jsonElements("\"\\uD801 \" \"\\uD801\\n\" \"\\uD801\\u0020\"");
+ ThorsAnvil::Json::LexerJson parser(jsonElements);
+ ThorsAnvil::Json::ParserCleanInterface cleanInterface;
+
+
+ ASSERT_TRUE(parser.yylex(cleanInterface) == yy::ParserShiftReduce::token::JSON_STRING);
+ ASSERT_THROW(ThorsAnvil::Json::getString(parser), ThorsAnvil::Json::ParsingError);
+
+ ASSERT_TRUE(parser.yylex(cleanInterface) == yy::ParserShiftReduce::token::JSON_STRING);
+ ASSERT_THROW(ThorsAnvil::Json::getString(parser), ThorsAnvil::Json::ParsingError);
+
+
+ ASSERT_TRUE(parser.yylex(cleanInterface) == yy::ParserShiftReduce::token::JSON_STRING);
+ ASSERT_THROW(ThorsAnvil::Json::getString(parser), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(LexerJson, ValidateError)
+{
+ std::stringstream jsonElements("");
+ ThorsAnvil::Json::LexerJson parser(jsonElements);
+
+ ASSERT_THROW(parser.LexerError("Test Failure"), ThorsAnvil::Json::ParsingError);
+}
+
248 Json/test/ParserRecursiveTest.cpp
@@ -0,0 +1,248 @@
+
+#include "gtest/gtest.h"
+#include "ParserRecursive.h"
+#include "ParserInterface.h"
+#include "LexerJson.h"
+#include <sstream>
+
+TEST(ParserRecursive, EmptyMap)
+{
+ std::stringstream json("{}");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, EmptyArray)
+{
+ std::stringstream json("[]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, ArrayWithNumber)
+{
+ std::stringstream json("[ 1 ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, ArrayWithString)
+{
+ std::stringstream json("[ \"String\" ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, ArrayWithBoolTrue)
+{
+ std::stringstream json("[ true ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, ArrayWithBoolFalse)
+{
+ std::stringstream json("[ false ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, ArrayWithNull)
+{
+ std::stringstream json("[ null ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, ArrayWithArray)
+{
+ std::stringstream json("[ [] ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, ArrayWithMap)
+{
+ std::stringstream json("[ {} ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, MapWithNumber)
+{
+ std::stringstream json("{ \"item\":1 }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, MapWithString)
+{
+ std::stringstream json("{ \"item\":\"String\" }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, MapWithBoolTrue)
+{
+ std::stringstream json("{ \"item\":true }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, MapWithBoolFalse)
+{
+ std::stringstream json("{ \"item\":false }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, MapWithNull)
+{
+ std::stringstream json("{ \"item\":null }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, MapWithArray)
+{
+ std::stringstream json("{ \"item\":[] }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, MapWithMap)
+{
+ std::stringstream json("{ \"item\":{} }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, MultiItemArray)
+{
+ std::stringstream json("[ 12, \"String\", true, false, null, { \"Item\": 1, \"Plop\": 2}, [ 1, 2] ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, MultiItemMap)
+{
+ std::stringstream json("{ \"I1\": 12, \"I2\": \"String\", \"I3\": true, \"I4\": false, \"I5\": null, \"I6\": { \"Item\": 1, \"Plop\": 2}, \"I7\": [ 1, 2] }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserRecursive, BadMapValue)
+{
+ std::stringstream json("{ \"I1\": ] }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(ParserRecursive, BadArrayValue)
+{
+ std::stringstream json("{ ] }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(ParserRecursive, BadMapMissingComma)
+{
+ std::stringstream json("{ \"I1\": 12 \"I2\": 13 }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(ParserRecursive, BadMapMissingColon)
+{
+ std::stringstream json("{ \"I1\" 12 }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(ParserRecursive, BadArrayMissingComma)
+{
+ std::stringstream json("[ 12 13 ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(ParserRecursive, NotHighLevelObject)
+{
+ std::stringstream json("12");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ ThorsAnvil::Json::ParserRecursive parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+
240 Json/test/ParserShiftReduceTest.cpp
@@ -0,0 +1,240 @@
+
+#include "gtest/gtest.h"
+#include "ParserShiftReduce.tab.hpp"
+#include "ParserInterface.h"
+#include "LexerJson.h"
+#include <sstream>
+
+TEST(ParserShiftReduce, EmptyMap)
+{
+ std::stringstream json("{}");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, EmptyArray)
+{
+ std::stringstream json("[]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, ArrayWithNumber)
+{
+ std::stringstream json("[ 1 ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, ArrayWithString)
+{
+ std::stringstream json("[ \"String\" ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, ArrayWithBoolTrue)
+{
+ std::stringstream json("[ true ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, ArrayWithBoolFalse)
+{
+ std::stringstream json("[ false ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, ArrayWithNull)
+{
+ std::stringstream json("[ null ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, ArrayWithArray)
+{
+ std::stringstream json("[ [] ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, ArrayWithMap)
+{
+ std::stringstream json("[ {} ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, MapWithNumber)
+{
+ std::stringstream json("{ \"item\":1 }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, MapWithString)
+{
+ std::stringstream json("{ \"item\":\"String\" }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, MapWithBoolTrue)
+{
+ std::stringstream json("{ \"item\":true }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, MapWithBoolFalse)
+{
+ std::stringstream json("{ \"item\":false }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, MapWithNull)
+{
+ std::stringstream json("{ \"item\":null }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, MapWithArray)
+{
+ std::stringstream json("{ \"item\":[] }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, MapWithMap)
+{
+ std::stringstream json("{ \"item\":{} }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, MultiItemArray)
+{
+ std::stringstream json("[ 12, \"String\", true, false, null, { \"Item\": 1, \"Plop\": 2}, [ 1, 2] ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, MultiItemMap)
+{
+ std::stringstream json("{ \"I1\": 12, \"I2\": \"String\", \"I3\": true, \"I4\": false, \"I5\": null, \"I6\": { \"Item\": 1, \"Plop\": 2}, \"I7\": [ 1, 2] }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_TRUE(parser.parse() == 0);
+}
+
+TEST(ParserShiftReduce, BadMapValue)
+{
+ std::stringstream json("{ \"I1\": ] }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(ParserShiftReduce, BadArrayValue)
+{
+ std::stringstream json("{ ] }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(ParserShiftReduce, BadMapMissingComma)
+{
+ std::stringstream json("{ \"I1\": 12 \"I2\": 13 }");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(ParserShiftReduce, BadArrayMissingComma)
+{
+ std::stringstream json("[ 12 13 ]");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+TEST(ParserShiftReduce, NotHighLevelObject)
+{
+ std::stringstream json("12");
+ ThorsAnvil::Json::LexerJson lexer(json);
+ ThorsAnvil::Json::ParserCleanInterface interface;
+ yy::ParserShiftReduce parser(lexer, interface);
+
+ ASSERT_THROW(parser.parse(), ThorsAnvil::Json::ParsingError);
+}
+
+
+
+
98 Json/test/ScannerDomTest.cpp
@@ -0,0 +1,98 @@
+
+
+#include "gtest/gtest.h"
+#include "ScannerDom.h"
+#include "ParserShiftReduce.tab.hpp"
+#include "ParserRecursive.h"
+#include <sstream>
+
+TEST(ScannerDom, ShiftReduceScanMapEmpty)
+{
+ ThorsAnvil::Json::ScannerDom scanner;
+ std::stringstream json("{}");
+
+ ASSERT_TRUE(scanner.parse<yy::ParserShiftReduce>(json) == ThorsAnvil::Json::JsonMapObject);
+
+ std::auto_ptr<ThorsAnvil::Json::JsonMap>& map = scanner.getMap();
+ ASSERT_TRUE(map.get() != NULL);
+}
+
+TEST(ScannerDom, ShiftReduceScanArrayEmpty)
+{
+ ThorsAnvil::Json::ScannerDom scanner;
+ std::stringstream json("[]");
+
+ ASSERT_TRUE(scanner.parse<yy::ParserShiftReduce>(json) == ThorsAnvil::Json::JsonArrayObject);
+
+ std::auto_ptr<ThorsAnvil::Json::JsonArray>& array = scanner.getArray();
+ ASSERT_TRUE(array.get() != NULL);
+}
+
+TEST(ScannerDom, RecursiveScanMapEmpty)
+{
+ ThorsAnvil::Json::ScannerDom scanner;
+ std::stringstream json("{}");
+
+ ASSERT_TRUE(scanner.parse<ThorsAnvil::Json::ParserRecursive>(json) == ThorsAnvil::Json::JsonMapObject);
+
+ std::auto_ptr<ThorsAnvil::Json::JsonMap>& map = scanner.getMap();
+ ASSERT_TRUE(map.get() != NULL);
+}
+
+TEST(ScannerDom, RecursiveScanArrayEmpty)
+{
+ ThorsAnvil::Json::ScannerDom scanner;
+ std::stringstream json("[]");
+
+ ASSERT_TRUE(scanner.parse<ThorsAnvil::Json::ParserRecursive>(json) == ThorsAnvil::Json::JsonArrayObject);
+
+ std::auto_ptr<ThorsAnvil::Json::JsonArray>& array = scanner.getArray();
+ ASSERT_TRUE(array.get() != NULL);
+}
+
+
+TEST(ScannerDom, ShiftReduceScanMap)
+{
+ ThorsAnvil::Json::ScannerDom scanner;
+ std::stringstream json("{ \"I1\": 1, \"I2\": \"S\", \"I3\": true, \"I4\": false, \"I6\": null, \"I7\": {}, \"I8\": [] }");
+
+ ASSERT_TRUE(scanner.parse<yy::ParserShiftReduce>(json) == ThorsAnvil::Json::JsonMapObject);
+
+ std::auto_ptr<ThorsAnvil::Json::JsonMap>& map = scanner.getMap();
+ ASSERT_TRUE(map.get() != NULL);
+}
+
+TEST(ScannerDom, ShiftReduceScanArray)
+{
+ ThorsAnvil::Json::ScannerDom scanner;
+ std::stringstream json("[ 1, \"S\", true, false, null, {}, [] ]");
+
+ ASSERT_TRUE(scanner.parse<yy::ParserShiftReduce>(json) == ThorsAnvil::Json::JsonArrayObject);
+
+ std::auto_ptr<ThorsAnvil::Json::JsonArray>& array = scanner.getArray();
+ ASSERT_TRUE(array.get() != NULL);
+}
+
+TEST(ScannerDom, RecursiveScanMap)
+{
+ ThorsAnvil::Json::ScannerDom scanner;
+ std::stringstream json("{ \"I1\": 1, \"I2\": \"S\", \"I3\": true, \"I4\": false, \"I6\": null, \"I7\": {}, \"I8\": [] }");
+
+ ASSERT_TRUE(scanner.parse<ThorsAnvil::Json::ParserRecursive>(json) == ThorsAnvil::Json::JsonMapObject);
+
+ std::auto_ptr<ThorsAnvil::Json::JsonMap>& map = scanner.getMap();
+ ASSERT_TRUE(map.get() != NULL);
+}
+
+TEST(ScannerDom, RecursiveScanArray)
+{
+ ThorsAnvil::Json::ScannerDom scanner;
+ std::stringstream json("[ 1, \"S\", true, false, null, {}, [] ]");
+
+ ASSERT_TRUE(scanner.parse<ThorsAnvil::Json::ParserRecursive>(json) == ThorsAnvil::Json::JsonArrayObject);
+
+ std::auto_ptr<ThorsAnvil::Json::JsonArray>& array = scanner.getArray();
+ ASSERT_TRUE(array.get() != NULL);
+}
+
+
353 Json/test/ScannerSaxTest.cpp
@@ -0,0 +1,353 @@
+
+#include "gtest/gtest.h"
+#include "ScannerSax.h"
+#include "ParserShiftReduce.tab.hpp"
+#include "ParserRecursive.h"
+#include <sstream>
+
+
+template<typename T>
+struct TestAction: ThorsAnvil::Json::SaxAction
+{
+ TestAction(int& c, bool& pa, bool& a, T& v) : count(c), preAction(pa), action(a), value(v)
+ {
+ count = 0;
+ preAction = false;
+ action = false;
+ }
+ int& count;
+ bool& preAction;
+ bool& action;
+ T& value;
+
+ virtual void doPreAction(ThorsAnvil::Json::ScannerSax&)
+ {
+ preAction = true;
+ ++count;
+ }
+ virtual void doAction(ThorsAnvil::Json::ScannerSax&, ThorsAnvil::Json::JsonValue const& input)
+ {
+ action = true;
+ value = input.getValue<T>();
+ }
+};
+
+
+TEST(ScannerSax, ShiftReduceScanMapEmpty)
+{
+ int count;
+ bool preAction;
+ bool action;
+ int value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<int>(count, preAction, action, value));
+
+ std::stringstream json("{}");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction("I1", saxAction);
+ scanner.parse<yy::ParserShiftReduce>(json);
+
+ ASSERT_TRUE(count == 0);
+ ASSERT_TRUE(preAction == false);
+ ASSERT_TRUE(action == false);
+}
+
+TEST(ScannerSax, ShiftReduceScanMapMiss)
+{
+ int count;
+ bool preAction;
+ bool action;
+ int value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<int>(count, preAction, action, value));
+
+ std::stringstream json("{ \"I2\" : 1}");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction("I1", saxAction);
+ scanner.parse<yy::ParserShiftReduce>(json);
+
+ ASSERT_TRUE(count == 0);
+ ASSERT_TRUE(preAction == false);
+ ASSERT_TRUE(action == false);
+}
+
+TEST(ScannerSax, ShiftReduceScanMapHit)
+{
+ int count;
+ bool preAction;
+ bool action;
+ int value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<int>(count, preAction, action, value));
+
+ std::stringstream json("{ \"I1\" : 123}");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction("I1", saxAction);
+ scanner.parse<yy::ParserShiftReduce>(json);
+
+ ASSERT_TRUE(count == 1);
+ ASSERT_TRUE(preAction == true);
+ ASSERT_TRUE(action == true);
+ ASSERT_TRUE(value == 123);
+}
+
+TEST(ScannerSax, ShiftReduceScanArrayEmpty)
+{
+ int count;
+ bool preAction;
+ bool action;
+ bool value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<bool>(count, preAction, action, value));
+
+ std::stringstream json("[]");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction("I1", saxAction);
+ scanner.parse<yy::ParserShiftReduce>(json);
+
+ ASSERT_TRUE(count == 0);
+ ASSERT_TRUE(preAction == false);
+ ASSERT_TRUE(action == false);
+}
+
+TEST(ScannerSax, ShiftReduceScanArrayMiss)
+{
+ int count;
+ bool preAction;
+ bool action;
+ bool value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<bool>(count, preAction, action, value));
+
+ std::stringstream json("[ true ]");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction(2, saxAction);
+ scanner.parse<yy::ParserShiftReduce>(json);
+
+ ASSERT_TRUE(preAction == false);
+ ASSERT_TRUE(action == false);
+}
+
+TEST(ScannerSax, ShiftReduceScanArrayHit)
+{
+ int count;
+ bool preAction;
+ bool action;
+ bool value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<bool>(count, preAction, action, value));
+
+ std::stringstream json("[ 512, true ]");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction(1, saxAction);
+ scanner.parse<yy::ParserShiftReduce>(json);
+
+ ASSERT_TRUE(count == 1);
+ ASSERT_TRUE(preAction == true);
+ ASSERT_TRUE(action == true);
+ ASSERT_TRUE(value == true);
+}
+
+
+TEST(ScannerSax, RecursiveScanMapEmpty)
+{
+ int count;
+ bool preAction;
+ bool action;
+ std::string value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<std::string>(count, preAction, action, value));
+
+ std::stringstream json("{}");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction("I1", saxAction);
+ scanner.parse<ThorsAnvil::Json::ParserRecursive>(json);
+
+ ASSERT_TRUE(count == 0);
+ ASSERT_TRUE(preAction == false);
+ ASSERT_TRUE(action == false);
+}
+
+TEST(ScannerSax, RecursiveScanMapMiss)
+{
+ int count;
+ bool preAction;
+ bool action;
+ std::string value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<std::string>(count, preAction, action, value));
+
+ std::stringstream json("{ \"I2\" : \"S1\"}");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction("I1", saxAction);
+ scanner.parse<ThorsAnvil::Json::ParserRecursive>(json);
+
+ ASSERT_TRUE(count == 0);
+ ASSERT_TRUE(preAction == false);
+ ASSERT_TRUE(action == false);
+}
+
+TEST(ScannerSax, RecursiveScanMapHit)
+{
+ int count;
+ bool preAction;
+ bool action;
+ std::string value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<std::string>(count, preAction, action, value));
+
+ std::stringstream json("{ \"I1\" : \"123SS\"}");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction("I1", saxAction);
+ scanner.parse<ThorsAnvil::Json::ParserRecursive>(json);
+
+ ASSERT_TRUE(count == 1);
+ ASSERT_TRUE(preAction == true);
+ ASSERT_TRUE(action == true);
+ ASSERT_TRUE(value == "123SS");
+}
+
+TEST(ScannerSax, RecursiveScanArrayEmpty)
+{
+ int count;
+ bool preAction;
+ bool action;
+ bool value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<bool>(count, preAction, action, value));
+
+ std::stringstream json("[]");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction("I1", saxAction);
+ scanner.parse<ThorsAnvil::Json::ParserRecursive>(json);
+
+ ASSERT_TRUE(count == 0);
+ ASSERT_TRUE(preAction == false);
+ ASSERT_TRUE(action == false);
+}
+
+TEST(ScannerSax, RecursiveScanArrayMiss)
+{
+ int count;
+ bool preAction;
+ bool action;
+ bool value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<bool>(count, preAction, action, value));
+
+ std::stringstream json("[ false ]");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction(2, saxAction);
+ scanner.parse<ThorsAnvil::Json::ParserRecursive>(json);
+
+ ASSERT_TRUE(count == 0);
+ ASSERT_TRUE(preAction == false);
+ ASSERT_TRUE(action == false);
+}
+
+TEST(ScannerSax, RecursiveScanArrayHit)
+{
+ int count;
+ bool preAction;
+ bool action;
+ bool value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<bool>(count, preAction, action, value));
+
+ std::stringstream json("[ 512, false ]");
+ ThorsAnvil::Json::ScannerSax scanner;
+ scanner.registerAction(1, saxAction);
+ scanner.parse<ThorsAnvil::Json::ParserRecursive>(json);
+
+ ASSERT_TRUE(count == 1);
+ ASSERT_TRUE(preAction == true);
+ ASSERT_TRUE(action == true);
+ ASSERT_TRUE(value == false);
+}
+
+TEST(ScannerSax, ReplaceAction)
+{
+ int count;
+ bool preAction;
+ bool action;
+ int value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<int>(count, preAction, action, value));
+
+ int count2;
+ bool preAction2;
+ bool action2;
+ int value2;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction2(new TestAction<int>(count2, preAction2, action2, value2));
+
+
+ ThorsAnvil::Json::ScannerSax scanner;
+
+ ThorsAnvil::Json::ActionRefNote actNote = scanner.registerAction(1, saxAction);
+ scanner.replaceAction(actNote, saxAction2);
+
+ std::stringstream json("[ 512, 567 ]");
+ scanner.parse<ThorsAnvil::Json::ParserRecursive>(json);
+
+ ASSERT_TRUE(count == 0);
+ ASSERT_TRUE(preAction == false);
+ ASSERT_TRUE(action == false);
+ ASSERT_TRUE(count2 == 1);
+ ASSERT_TRUE(preAction2 == true);
+ ASSERT_TRUE(action2 == true);
+ ASSERT_TRUE(value2 == 567);
+}
+
+TEST(ScannerSax, DefaultArrayAction)
+{
+ int count;
+ bool preAction;
+ bool action;
+ int value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<int>(count, preAction, action, value));
+
+
+ ThorsAnvil::Json::ScannerSax scanner;
+
+ ThorsAnvil::Json::ActionRefNote actNote = scanner.registerAction(-1, saxAction);
+
+ std::stringstream json("[ 512, 567 ]");
+ scanner.parse<ThorsAnvil::Json::ParserRecursive>(json);
+
+ ASSERT_EQ(2, count);
+ ASSERT_TRUE(preAction == true);
+ ASSERT_TRUE(action == true);
+ ASSERT_EQ(567, value);
+}
+
+TEST(ScannerSax, DefaultMapAction)
+{
+ int count;
+ bool preAction;
+ bool action;
+ int value;
+ std::auto_ptr<ThorsAnvil::Json::SaxAction> saxAction(new TestAction<int>(count, preAction, action, value));
+
+
+ ThorsAnvil::Json::ScannerSax scanner;
+
+ ThorsAnvil::Json::ActionRefNote actNote = scanner.registerAction("\xFF", saxAction);
+
+ std::stringstream json("{ \"I1\": 512, \"I2\": 567 }");
+ scanner.parse<ThorsAnvil::Json::ParserRecursive>(json);
+
+ ASSERT_EQ(2, count);
+ ASSERT_TRUE(preAction == true);
+ ASSERT_TRUE(action == true);
+ ASSERT_EQ(567, value);
+}
+
+TEST(ScannerSax, GetNullValue)
+{
+ int count;
+ bool preAction;
+ bool action;