From 8bf34e0c41e5801fabd34ff3a4510b730703f5f5 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 22 Dec 2019 16:21:29 +0000 Subject: Refactor to support extensible lexer --- libjsonpp/Jamfile.jam | 3 +- libjsonpp/json.ll | 3 +- libjsonpp/jsonFlexLexer.cpp | 71 +++++---------------------------------- libjsonpp/jsonFlexLexer.h | 40 ++++++++++++---------- libjsonpp/jsonValueFlexLexer.cpp | 72 ++++++++++++++++++++++++++++++++++++++++ libjsonpp/jsonValueFlexLexer.h | 34 +++++++++++++++++++ libjsonpp/jsonpp.cpp | 14 ++++++++ libjsonpp/jsonpp.h | 23 ++++--------- libjsonpp/parse.cpp | 9 ++--- libjsonpp/serialize.cpp | 3 -- 10 files changed, 162 insertions(+), 110 deletions(-) create mode 100644 libjsonpp/jsonValueFlexLexer.cpp create mode 100644 libjsonpp/jsonValueFlexLexer.h create mode 100644 libjsonpp/jsonpp.cpp diff --git a/libjsonpp/Jamfile.jam b/libjsonpp/Jamfile.jam index c956b7b..7f607bd 100644 --- a/libjsonpp/Jamfile.jam +++ b/libjsonpp/Jamfile.jam @@ -17,7 +17,6 @@ lib jsonpp : : . ..//glibmm - yyFlexLexer=jsonBaseFlexLexer : : . ; @@ -58,5 +57,5 @@ run testEncoding ; -package.install install : . : : jsonpp : [ glob *.h : jsonFlexLexer.h ] ; +package.install install : . : : jsonpp : [ glob *.h : jsonValueFlexLexer.h ] ; diff --git a/libjsonpp/json.ll b/libjsonpp/json.ll index 391556d..12e46a9 100644 --- a/libjsonpp/json.ll +++ b/libjsonpp/json.ll @@ -8,6 +8,7 @@ %option prefix="jsonBase" %{ +#include #include "jsonFlexLexer.h" #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" @@ -86,7 +87,7 @@ text [^\\\"]* yy_pop_state(); break; case OBJECT_ITEM: - name = encodeBuf(); + PushKey(encodeBuf()); BEGIN(COLON); break; } diff --git a/libjsonpp/jsonFlexLexer.cpp b/libjsonpp/jsonFlexLexer.cpp index 0964c1c..df29d8f 100644 --- a/libjsonpp/jsonFlexLexer.cpp +++ b/libjsonpp/jsonFlexLexer.cpp @@ -1,87 +1,32 @@ -#include "jsonFlexLexer.h" +#include "jsonValueFlexLexer.h" #include namespace json { - const std::string UTF8 { "utf-8" }; - - jsonFlexLexer::jsonFlexLexer(std::istream & in, std::string enc, Value & v) : + jsonFlexLexer::jsonFlexLexer(std::istream & in, std::string enc) : yyFlexLexer(&in, nullptr), - encoding(enc != UTF8 ? std::move(enc) : std::string()) + encoding(enc != utf8 ? std::move(enc) : std::string()) { yy_push_state(0); - acceptValues.push([&v](auto && value) { - v = std::forward(value); - return &v; - }); } std::string jsonFlexLexer::encodeBuf() const { if (!encoding.empty()) { - return Glib::convert(buf, UTF8, encoding); + return Glib::convert(buf, utf8, encoding); } return buf; } void - jsonFlexLexer::BeginObject() - { - auto object = std::get_if(acceptValues.top()(Object())); - acceptValues.push([object,this](auto && value) { - return &object->emplace(std::move(name), std::forward(value)).first->second; - }); - } - - void - jsonFlexLexer::BeginArray() - { - auto array = std::get_if(acceptValues.top()(Array())); - acceptValues.push([array](auto && value) { - return &array->emplace_back(std::forward(value)); - }); - } - - 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(std::string && value) - { - acceptValues.top()(std::move(value)); - } - - void - jsonFlexLexer::EndArray() - { - acceptValues.pop(); - } - - void - jsonFlexLexer::EndObject() + jsonFlexLexer::LexerError(const char * msg) { - acceptValues.pop(); + throw ParseError(msg, 0, 0); } - void - jsonFlexLexer::LexerError(const char * msg) + 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)) { - throw ParseError(msg, 0, 0); } } diff --git a/libjsonpp/jsonFlexLexer.h b/libjsonpp/jsonFlexLexer.h index 43770d5..bbd6b95 100644 --- a/libjsonpp/jsonFlexLexer.h +++ b/libjsonpp/jsonFlexLexer.h @@ -2,41 +2,45 @@ #define JSONFLEXLEXER_H #include -#include "jsonpp.h" -#include -#include +#include #ifndef FLEX_SCANNER +#define yyFlexLexer jsonBaseFlexLexer #include #endif namespace json { +#pragma GCC visibility push(default) + class ParseError : public std::invalid_argument { + public: + ParseError(const char *, int, int); + }; + class jsonFlexLexer : public yyFlexLexer { public: - jsonFlexLexer(std::istream &, std::string enc, Value & v); + jsonFlexLexer(std::istream &, std::string enc); int yylex() override; - void LexerError(const char * msg) override; - void BeginObject(); - void BeginArray(); + private: + virtual void BeginObject() = 0; + virtual void BeginArray() = 0; - void PushBoolean(bool); - void PushNumber(double); - void PushNull(); - void PushText(std::string &&); + virtual void PushBoolean(bool) = 0; + virtual void PushNumber(double) = 0; + virtual void PushNull() = 0; + virtual void PushText(std::string &&) = 0; + virtual void PushKey(std::string &&) = 0; - void EndArray(); - void EndObject(); + virtual void EndArray() = 0; + virtual void EndObject() = 0; - private: + void LexerError(const char * msg) override; std::string encodeBuf() const; - std::string buf, name; + std::string buf; const std::string encoding; - - using AcceptValue = std::function; - std::stack acceptValues; }; +#pragma GCC visibility pop } #endif diff --git a/libjsonpp/jsonValueFlexLexer.cpp b/libjsonpp/jsonValueFlexLexer.cpp new file mode 100644 index 0000000..5225c95 --- /dev/null +++ b/libjsonpp/jsonValueFlexLexer.cpp @@ -0,0 +1,72 @@ +#include "jsonValueFlexLexer.h" + +namespace json { + jsonValueFlexLexer::jsonValueFlexLexer(std::istream & in, std::string enc, Value & v) : + jsonFlexLexer(in, std::move(enc)) + { + acceptValues.push([&v](auto && value) { + return &(v = std::forward(value)); + }); + } + + void + jsonValueFlexLexer::BeginObject() + { + auto object = std::get_if(acceptValues.top()(Object())); + acceptValues.push([object,this](auto && value) { + return &object->emplace(std::move(name), std::forward(value)).first->second; + }); + } + + void + jsonValueFlexLexer::BeginArray() + { + auto array = std::get_if(acceptValues.top()(Array())); + acceptValues.push([array](auto && value) { + return &array->emplace_back(std::forward(value)); + }); + } + + void + jsonValueFlexLexer::PushNull() + { + acceptValues.top()(Null()); + } + + void + jsonValueFlexLexer::PushBoolean(bool value) + { + acceptValues.top()(value); + } + + void + jsonValueFlexLexer::PushNumber(double value) + { + acceptValues.top()(value); + } + + void + jsonValueFlexLexer::PushText(std::string && value) + { + acceptValues.top()(std::forward(value)); + } + + void + jsonValueFlexLexer::PushKey(std::string && value) + { + name = std::forward(value); + } + + void + jsonValueFlexLexer::EndArray() + { + acceptValues.pop(); + } + + void + jsonValueFlexLexer::EndObject() + { + acceptValues.pop(); + } +} + diff --git a/libjsonpp/jsonValueFlexLexer.h b/libjsonpp/jsonValueFlexLexer.h new file mode 100644 index 0000000..82f3d62 --- /dev/null +++ b/libjsonpp/jsonValueFlexLexer.h @@ -0,0 +1,34 @@ +#ifndef JSONVALUEFLEXLEXER_H +#define JSONVALUEFLEXLEXER_H + +#include "jsonFlexLexer.h" +#include "jsonpp.h" +#include +#include + +namespace json { + class jsonValueFlexLexer : public jsonFlexLexer { + public: + jsonValueFlexLexer(std::istream &, std::string enc, Value & v); + + void BeginObject() override; + void BeginArray() override; + + void PushBoolean(bool) override; + void PushNumber(double) override; + void PushNull() override; + void PushText(std::string &&) override; + void PushKey(std::string &&) override; + + void EndArray() override; + void EndObject() override; + + private: + using AcceptValue = std::function; + std::stack acceptValues; + std::string name; + }; +} + +#endif + diff --git a/libjsonpp/jsonpp.cpp b/libjsonpp/jsonpp.cpp new file mode 100644 index 0000000..db2ac63 --- /dev/null +++ b/libjsonpp/jsonpp.cpp @@ -0,0 +1,14 @@ +#include "jsonpp.h" + +namespace json { + const std::string null("null"); + const std::string utf8("utf-8"); + + static_assert(std::is_move_constructible::value); + static_assert(std::is_nothrow_move_constructible::value); + static_assert(std::is_nothrow_move_constructible::value); + static_assert(std::is_move_assignable::value); + static_assert(std::is_nothrow_move_assignable::value); + static_assert(std::is_nothrow_move_assignable::value); +} + diff --git a/libjsonpp/jsonpp.h b/libjsonpp/jsonpp.h index 67afb36..ac45acd 100644 --- a/libjsonpp/jsonpp.h +++ b/libjsonpp/jsonpp.h @@ -1,22 +1,20 @@ -#ifndef JSON_H -#define JSON_H +#ifndef JSONPP_H +#define JSONPP_H #include #include #include #include -#include +#include "jsonFlexLexer.h" -#pragma GCC visibility push(default) namespace json { - class ParseError : public std::invalid_argument { - public: - ParseError(const char *, int, int); - }; + extern const std::string utf8; + extern const std::string null; typedef Glib::ustring String; typedef double Number; typedef bool Boolean; +#pragma GCC visibility push(default) class Null { }; class Object; class Array; @@ -32,21 +30,14 @@ namespace json { using A::A; }; - static_assert(std::is_move_constructible::value); - static_assert(std::is_nothrow_move_constructible::value); - static_assert(std::is_nothrow_move_constructible::value); - static_assert(std::is_move_assignable::value); - static_assert(std::is_nothrow_move_assignable::value); - static_assert(std::is_nothrow_move_assignable::value); - 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); void serializeValue(const Value &, std::ostream & s, const std::string & encoding); -} #pragma GCC visibility pop +} #endif diff --git a/libjsonpp/parse.cpp b/libjsonpp/parse.cpp index 9c9a013..ec6448b 100644 --- a/libjsonpp/parse.cpp +++ b/libjsonpp/parse.cpp @@ -1,19 +1,14 @@ #include "jsonpp.h" -#include "jsonFlexLexer.h" +#include "jsonValueFlexLexer.h" namespace json { - 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)) - { - } - Value parseValue(std::istream & s) { return parseValue(s, std::string()); } Value parseValue(std::istream & s, const std::string & enc) { Value v; - jsonFlexLexer jfl(s, enc, v); + jsonValueFlexLexer jfl(s, enc, v); while (jfl.yylex()) {} return v; } diff --git a/libjsonpp/serialize.cpp b/libjsonpp/serialize.cpp index 055d36f..cb3d203 100644 --- a/libjsonpp/serialize.cpp +++ b/libjsonpp/serialize.cpp @@ -4,9 +4,6 @@ #include namespace json { - const std::string null("null"); - const std::string utf8("utf-8"); - class JsonSerialize { public: JsonSerialize(std::ostream & out, const std::string & encoding) : -- cgit v1.2.3