json: split json impl files into tree and flat
This commit is contained in:
parent
81a7ff5db5
commit
60787655b3
@ -71,8 +71,12 @@ UTIL_FILES = \
|
|||||||
ip.cpp \
|
ip.cpp \
|
||||||
ip.hpp \
|
ip.hpp \
|
||||||
iterator.hpp \
|
iterator.hpp \
|
||||||
json.cpp \
|
json/except.cpp \
|
||||||
json.hpp \
|
json/except.hpp \
|
||||||
|
json/flat.cpp \
|
||||||
|
json/flat.hpp \
|
||||||
|
json/tree.cpp \
|
||||||
|
json/tree.hpp \
|
||||||
lerp.cpp \
|
lerp.cpp \
|
||||||
lerp.hpp \
|
lerp.hpp \
|
||||||
log.cpp \
|
log.cpp \
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "detail/coord.hpp"
|
#include "detail/coord.hpp"
|
||||||
|
|
||||||
#include "json.hpp"
|
#include "json/tree.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
359
json.hpp
359
json.hpp
@ -1,359 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of libgim.
|
|
||||||
*
|
|
||||||
* libgim is free software: you can redistribute it and/or modify it under the
|
|
||||||
* terms of the GNU General Public License as published by the Free Software
|
|
||||||
* Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
* version.
|
|
||||||
*
|
|
||||||
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __UTIL_JSON_HPP
|
|
||||||
#define __UTIL_JSON_HPP
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
|
|
||||||
#include "iterator.hpp"
|
|
||||||
|
|
||||||
namespace json {
|
|
||||||
namespace tree {
|
|
||||||
class node;
|
|
||||||
class object;
|
|
||||||
class array;
|
|
||||||
class string;
|
|
||||||
class number;
|
|
||||||
class boolean;
|
|
||||||
class null;
|
|
||||||
|
|
||||||
/// Parse an encoded form of JSON into a tree structure
|
|
||||||
extern std::unique_ptr<node> parse (const boost::filesystem::path &path);
|
|
||||||
extern std::unique_ptr<node> parse (const char *start, const char *stop);
|
|
||||||
extern std::unique_ptr<node> parse (const char *start);
|
|
||||||
extern std::unique_ptr<node> parse (const std::string&);
|
|
||||||
|
|
||||||
extern void write (const json::tree::node&, std::ostream&);
|
|
||||||
|
|
||||||
/// Abstract base for all JSON values
|
|
||||||
class node {
|
|
||||||
public:
|
|
||||||
virtual ~node () { ; }
|
|
||||||
|
|
||||||
virtual const object& as_object (void) const;
|
|
||||||
virtual const array& as_array (void) const;
|
|
||||||
virtual const string& as_string (void) const;
|
|
||||||
virtual const number& as_number (void) const;
|
|
||||||
virtual const boolean& as_boolean (void) const;
|
|
||||||
virtual const null& as_null (void) const;
|
|
||||||
|
|
||||||
virtual bool is_object (void) const { return false; }
|
|
||||||
virtual bool is_array (void) const { return false; }
|
|
||||||
virtual bool is_string (void) const { return false; }
|
|
||||||
virtual bool is_number (void) const { return false; }
|
|
||||||
virtual bool is_boolean (void) const { return false; }
|
|
||||||
virtual bool is_null (void) const { return false; }
|
|
||||||
|
|
||||||
virtual bool operator==(const node &rhs) const = 0;
|
|
||||||
virtual bool operator!=(const node &rhs) const;
|
|
||||||
virtual bool operator==(const object &) const { return false; }
|
|
||||||
virtual bool operator==(const array &) const { return false; }
|
|
||||||
virtual bool operator==(const string &) const { return false; }
|
|
||||||
virtual bool operator==(const number &) const { return false; }
|
|
||||||
virtual bool operator==(const boolean &) const { return false; }
|
|
||||||
virtual bool operator==(const null &) const { return false; }
|
|
||||||
|
|
||||||
virtual bool operator==(const char *rhs) const;
|
|
||||||
virtual bool operator!=(const char *rhs) const { return !(*this == rhs); }
|
|
||||||
|
|
||||||
virtual const node& operator[] (const std::string&) const;
|
|
||||||
virtual const node& operator[] (unsigned int) const;
|
|
||||||
|
|
||||||
virtual std::ostream& write (std::ostream &os) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Represents a JSON object, and contains its children.
|
|
||||||
class object : public node {
|
|
||||||
protected:
|
|
||||||
typedef std::map<std::string, std::unique_ptr<node>> value_store;
|
|
||||||
public:
|
|
||||||
typedef value_store::iterator iterator;
|
|
||||||
typedef value_store::const_iterator const_iterator;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
value_store m_values;
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~object ();
|
|
||||||
|
|
||||||
virtual const object& as_object (void) const { return *this; }
|
|
||||||
virtual bool is_object (void) const { return true; }
|
|
||||||
virtual bool operator==(const object &rhs) const;
|
|
||||||
virtual bool operator==(const node &rhs) const
|
|
||||||
{ return rhs == *this; }
|
|
||||||
|
|
||||||
virtual void insert (const std::string &key, std::unique_ptr<node>&& value);
|
|
||||||
virtual const node& operator[](const std::string &key) const;
|
|
||||||
virtual bool has (const std::string&) const;
|
|
||||||
|
|
||||||
virtual void clear (void);
|
|
||||||
virtual void erase (const std::string &key);
|
|
||||||
|
|
||||||
virtual const_iterator begin (void) const;
|
|
||||||
virtual const_iterator end (void) const;
|
|
||||||
|
|
||||||
virtual std::ostream& write (std::ostream &os) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Represents a JSON array, and contains its children.
|
|
||||||
class array : public node {
|
|
||||||
protected:
|
|
||||||
typedef std::vector<std::unique_ptr<node>>::iterator pointer_array_iterator;
|
|
||||||
typedef std::vector<std::unique_ptr<node>>::const_iterator const_pointer_array_iterator;
|
|
||||||
|
|
||||||
public:
|
|
||||||
typedef referencing_iterator<pointer_array_iterator> iterator;
|
|
||||||
typedef referencing_iterator<const_pointer_array_iterator> const_iterator;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
std::vector<std::unique_ptr<node>> m_values;
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~array();
|
|
||||||
|
|
||||||
virtual const array& as_array (void) const { return *this; }
|
|
||||||
virtual bool is_array (void) const { return true; }
|
|
||||||
virtual bool operator==(const array &rhs) const;
|
|
||||||
virtual bool operator==(const node &rhs) const
|
|
||||||
{ return rhs == *this; }
|
|
||||||
|
|
||||||
virtual size_t size (void) const
|
|
||||||
{ return m_values.size (); }
|
|
||||||
virtual node& operator [](unsigned int idx)
|
|
||||||
{ return *m_values[idx]; }
|
|
||||||
virtual const node& operator [](unsigned int idx) const
|
|
||||||
{ return *m_values[idx]; }
|
|
||||||
|
|
||||||
virtual const_iterator begin (void) const { return const_iterator (m_values.begin ()); }
|
|
||||||
virtual const_iterator end (void) const { return const_iterator (m_values.end ()); }
|
|
||||||
|
|
||||||
virtual void insert (std::unique_ptr<json::tree::node> &&_value);
|
|
||||||
|
|
||||||
virtual std::ostream& write (std::ostream &os) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Represents a JSON string literal.
|
|
||||||
class string : public node {
|
|
||||||
protected:
|
|
||||||
std::string m_value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit string (const std::string &_value): m_value (_value) { ; }
|
|
||||||
explicit string (const char *_value): m_value (_value) { ; }
|
|
||||||
string (const char *_first, const char *_last): m_value (_first, _last) { ; }
|
|
||||||
|
|
||||||
virtual const string& as_string (void) const { return *this; }
|
|
||||||
virtual bool is_string (void) const { return true; }
|
|
||||||
virtual bool operator==(const char *rhs) const;
|
|
||||||
virtual bool operator==(const string &rhs) const;
|
|
||||||
virtual bool operator==(const node &rhs) const
|
|
||||||
{ return rhs == *this; }
|
|
||||||
|
|
||||||
virtual size_t size (void) const { return m_value.size (); }
|
|
||||||
|
|
||||||
operator const std::string&(void) const { return m_value; }
|
|
||||||
const std::string& native (void) const { return m_value; }
|
|
||||||
|
|
||||||
virtual std::ostream& write (std::ostream &os) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Represents a JSON integer/float literal.
|
|
||||||
class number : public node {
|
|
||||||
protected:
|
|
||||||
double m_value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit number (double _value): m_value (_value) { ; }
|
|
||||||
explicit number (int _value): m_value (_value) { ; }
|
|
||||||
explicit number (size_t _value): m_value (_value) { ; }
|
|
||||||
|
|
||||||
virtual const number& as_number (void) const { return *this; }
|
|
||||||
virtual bool is_number (void) const { return true; }
|
|
||||||
virtual bool operator==(const number &rhs) const;
|
|
||||||
virtual bool operator==(const node &rhs) const
|
|
||||||
{ return rhs == *this; }
|
|
||||||
|
|
||||||
operator double(void) const { return m_value; }
|
|
||||||
double native (void) const { return m_value; }
|
|
||||||
|
|
||||||
virtual std::ostream& write (std::ostream &os) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Represents a JSON boolean literal.
|
|
||||||
class boolean : public node {
|
|
||||||
protected:
|
|
||||||
bool m_value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit boolean (bool _value): m_value (_value) { ; }
|
|
||||||
|
|
||||||
virtual const boolean& as_boolean (void) const { return *this; }
|
|
||||||
virtual bool is_boolean (void) const { return true; }
|
|
||||||
virtual bool operator==(const boolean &rhs) const;
|
|
||||||
virtual bool operator==(const node &rhs) const
|
|
||||||
{ return rhs == *this; }
|
|
||||||
|
|
||||||
operator bool (void) const { return m_value; }
|
|
||||||
bool native (void) const { return m_value; }
|
|
||||||
|
|
||||||
virtual std::ostream& write (std::ostream &os) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// Represents a JSON null value.
|
|
||||||
class null : public node {
|
|
||||||
public:
|
|
||||||
virtual bool operator==(const null&) const { return true; }
|
|
||||||
virtual bool operator==(const node &rhs) const
|
|
||||||
{ return rhs == *this; }
|
|
||||||
|
|
||||||
virtual bool is_null (void) const { return true; }
|
|
||||||
virtual const null& as_null (void) const { return *this; }
|
|
||||||
|
|
||||||
virtual std::ostream& write (std::ostream &os) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// The base class for all exceptions throw directly by the json namespace.
|
|
||||||
class error : public std::runtime_error {
|
|
||||||
public:
|
|
||||||
error (const std::string &_what):
|
|
||||||
std::runtime_error (_what)
|
|
||||||
{ ; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Base class for all type conversion errors
|
|
||||||
class type_error : public error {
|
|
||||||
public:
|
|
||||||
type_error (const std::string &_what):
|
|
||||||
error (_what)
|
|
||||||
{ ; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Base class for errors thrown during parsing
|
|
||||||
class parse_error : public error {
|
|
||||||
public:
|
|
||||||
parse_error (const std::string &_what):
|
|
||||||
error (_what)
|
|
||||||
{ ; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Base class for errors thrown during schema validation
|
|
||||||
class schema_error : public error {
|
|
||||||
public:
|
|
||||||
schema_error (const std::string &_what):
|
|
||||||
error (_what)
|
|
||||||
{ ; }
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream&
|
|
||||||
operator <<(std::ostream &os, const json::tree::node &n);
|
|
||||||
|
|
||||||
|
|
||||||
// Instantiate this template for the type you wish to output. We use a
|
|
||||||
// helper class here to avoid partial template specialisation of a
|
|
||||||
// function (eg, for templated types).
|
|
||||||
template <typename T>
|
|
||||||
struct io {
|
|
||||||
static std::unique_ptr<json::tree::node> serialise (const T&);
|
|
||||||
static T deserialise (const json::tree::node&);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace flat {
|
|
||||||
enum class type {
|
|
||||||
UNKNOWN,
|
|
||||||
|
|
||||||
NUL,
|
|
||||||
BOOLEAN,
|
|
||||||
STRING,
|
|
||||||
INTEGER,
|
|
||||||
REAL,
|
|
||||||
|
|
||||||
OBJECT_BEGIN,
|
|
||||||
OBJECT_END,
|
|
||||||
|
|
||||||
ARRAY_BEGIN,
|
|
||||||
ARRAY_END
|
|
||||||
};
|
|
||||||
|
|
||||||
struct item {
|
|
||||||
type tag;
|
|
||||||
const char *first;
|
|
||||||
const char *last;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T as (void) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<item> parse (const char *first, const char *last);
|
|
||||||
std::vector<item> parse (const char *first);
|
|
||||||
std::vector<item> parse (const boost::filesystem::path&);
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
struct error : public std::runtime_error {
|
|
||||||
error (const std::string &&_what):
|
|
||||||
runtime_error (std::move (_what))
|
|
||||||
{ ; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct parse_error : public error {
|
|
||||||
parse_error (size_t _line, const std::string &&_what):
|
|
||||||
error (std::move (_what)),
|
|
||||||
line (_line)
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
size_t line;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct value_error : public error {
|
|
||||||
value_error (const std::string &&_what):
|
|
||||||
error (std::move (_what))
|
|
||||||
{ ; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, class ...Args>
|
|
||||||
std::unique_ptr<json::tree::node> to_json (const T &t, Args&&... args) {
|
|
||||||
return json::tree::io<T>::serialise (t, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, class ...Args>
|
|
||||||
T from_json (const json::tree::node &n, Args&&... args) {
|
|
||||||
return json::tree::io<T>::deserialise (n, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
28
json/except.cpp
Normal file
28
json/except.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of libgim.
|
||||||
|
*
|
||||||
|
* libgim is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "except.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
json::parse_error::parse_error (const std::string &_what, size_t _line):
|
||||||
|
error (_what),
|
||||||
|
line (_line)
|
||||||
|
{ ; }
|
54
json/except.hpp
Normal file
54
json/except.hpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libgim.
|
||||||
|
*
|
||||||
|
* libgim is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright 2015 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __UTIL_JSON_EXCEPT_HPP
|
||||||
|
#define __UTIL_JSON_EXCEPT_HPP
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace json {
|
||||||
|
/// The base class for all exceptions throw directly by the json namespace.
|
||||||
|
struct error : public std::runtime_error {
|
||||||
|
using runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Base class for all type conversion errors
|
||||||
|
struct type_error : public error {
|
||||||
|
using error::error;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Base class for errors thrown during parsing
|
||||||
|
struct parse_error : public error {
|
||||||
|
using error::error;
|
||||||
|
|
||||||
|
parse_error (const std::string &_what, size_t _line = 0);
|
||||||
|
|
||||||
|
size_t line;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Base class for errors thrown during schema validation
|
||||||
|
struct schema_error : public error {
|
||||||
|
using error::error;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
199
json/flat.cpp.rl
Normal file
199
json/flat.cpp.rl
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libgim.
|
||||||
|
*
|
||||||
|
* libgim is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "json/flat.hpp"
|
||||||
|
|
||||||
|
#include "json/except.hpp"
|
||||||
|
#include "io.hpp"
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
%%{
|
||||||
|
# JSON (rfc7159)
|
||||||
|
machine json;
|
||||||
|
|
||||||
|
action trace { if (false) std::cerr << *p; }
|
||||||
|
action success { __success = true; }
|
||||||
|
action failure { }
|
||||||
|
|
||||||
|
action new_line { ++line; }
|
||||||
|
|
||||||
|
action first { parsed.push_back ({ type::UNKNOWN, p, p}); }
|
||||||
|
action last { parsed.back ().last = p; }
|
||||||
|
|
||||||
|
action tag_nul { parsed.back ().tag = type::NUL; }
|
||||||
|
action tag_boolean { parsed.back ().tag = type::BOOLEAN; }
|
||||||
|
action tag_string { parsed.back ().tag = type::STRING; }
|
||||||
|
action tag_integer { parsed.back ().tag = type::INTEGER; }
|
||||||
|
action tag_real { parsed.back ().tag = type::REAL; }
|
||||||
|
|
||||||
|
action tag_object_begin { parsed.push_back ({ type::OBJECT_BEGIN, p, p + 1 }); }
|
||||||
|
action tag_object_end { parsed.push_back ({ type::OBJECT_END, p, p + 1 }); }
|
||||||
|
action tag_array_begin { parsed.push_back ({ type::ARRAY_BEGIN, p, p + 1 }); }
|
||||||
|
action tag_array_end { parsed.push_back ({ type::ARRAY_END, p, p + 1 }); }
|
||||||
|
|
||||||
|
# Line counter
|
||||||
|
lines = (
|
||||||
|
any | '\n' @new_line
|
||||||
|
)*;
|
||||||
|
|
||||||
|
# UTF-8 (rfc3629)
|
||||||
|
utf8_tail = 0x80..0xbf;
|
||||||
|
|
||||||
|
utf8_1 = 0x00..0x7f;
|
||||||
|
utf8_2 = 0xc2..0xdf utf8_tail;
|
||||||
|
utf8_3 = 0xe0 0xa0..0xbf utf8_tail |
|
||||||
|
0xe1..0xec utf8_tail{2} |
|
||||||
|
0xed 0x80..0x9f utf8_tail |
|
||||||
|
0xee..0xef utf8_tail{2};
|
||||||
|
utf8_4 = 0xf0 0x90..0xbf utf8_tail{2} |
|
||||||
|
0xf1..0xf3 utf8_tail{3} |
|
||||||
|
0xf4 0x80..0x8f utf8_tail{2};
|
||||||
|
|
||||||
|
|
||||||
|
utf8 = utf8_1 | utf8_2 | utf8_3 | utf8_4;
|
||||||
|
|
||||||
|
# Utility
|
||||||
|
ws = 0x20 | 0x09 | 0x0A | 0x0D;
|
||||||
|
array_start = '[';
|
||||||
|
array_end = ']';
|
||||||
|
object_start = '{';
|
||||||
|
object_end = '}';
|
||||||
|
|
||||||
|
# Strings
|
||||||
|
char =
|
||||||
|
(utf8 - ["\\])
|
||||||
|
| "\\" (
|
||||||
|
[\\"/bfnrt]
|
||||||
|
| "u" xdigit{4}
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
|
string = ('"' char* '"') >first >tag_string %*last;
|
||||||
|
|
||||||
|
# numbers
|
||||||
|
int = '0' | [1-9] digit*;
|
||||||
|
|
||||||
|
frac = '.' digit+;
|
||||||
|
e = 'e'i[+\-]?;
|
||||||
|
exp = e digit+;
|
||||||
|
|
||||||
|
number = (
|
||||||
|
'-'?
|
||||||
|
int
|
||||||
|
(frac >tag_real)?
|
||||||
|
exp?
|
||||||
|
) >tag_integer;
|
||||||
|
|
||||||
|
# wrapper types
|
||||||
|
array = array_start @{ fhold; fcall array_members; } array_end;
|
||||||
|
object = object_start @{ fhold; fcall object_members; } object_end;
|
||||||
|
|
||||||
|
# simple types; case sensitive literals
|
||||||
|
bool = ("true" | "false") >tag_boolean;
|
||||||
|
nul = "null" >tag_nul;
|
||||||
|
literal = bool | nul;
|
||||||
|
|
||||||
|
value = object | array | (number | string | literal) >first %last;
|
||||||
|
|
||||||
|
# Complex
|
||||||
|
member = string ws* ':' ws* value;
|
||||||
|
|
||||||
|
array_members := ((
|
||||||
|
array_start >tag_array_begin ws* (value ws* (',' ws* value ws*)*)? array_end >tag_array_end
|
||||||
|
) & lines)
|
||||||
|
@{ fhold; fret; } $trace $!failure;
|
||||||
|
|
||||||
|
object_members := ((
|
||||||
|
object_start >tag_object_begin ws* (member ws* (',' ws* member ws*)*)? object_end >tag_object_end
|
||||||
|
) & lines)
|
||||||
|
@{ fhold; fret; } $trace $!failure;
|
||||||
|
|
||||||
|
# meta types
|
||||||
|
document := ((ws* value ws*) & lines)
|
||||||
|
%success
|
||||||
|
$!failure
|
||||||
|
$trace;
|
||||||
|
|
||||||
|
variable stack ragelstack;
|
||||||
|
prepush { ragelstack.push_back (0); }
|
||||||
|
postpop { ragelstack.pop_back (); }
|
||||||
|
|
||||||
|
write data;
|
||||||
|
}%%
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
std::vector<json::flat::item>
|
||||||
|
json::flat::parse (const char *first, const char *last)
|
||||||
|
{
|
||||||
|
const char *p = first;
|
||||||
|
const char *pe = last;
|
||||||
|
const char *eof = pe;
|
||||||
|
|
||||||
|
std::deque<int> ragelstack;
|
||||||
|
std::vector<item> parsed;
|
||||||
|
|
||||||
|
size_t line = 0;
|
||||||
|
int cs, top;
|
||||||
|
bool __success = false;
|
||||||
|
|
||||||
|
%%write init;
|
||||||
|
%%write exec;
|
||||||
|
|
||||||
|
if (!__success)
|
||||||
|
throw json::parse_error ("parse error", line);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
std::vector<json::flat::item>
|
||||||
|
json::flat::parse (const boost::filesystem::path &path)
|
||||||
|
{
|
||||||
|
util::mapped_file f (path);
|
||||||
|
return parse ((const char *)f.cbegin (), (const char*)f.cend ());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
std::ostream&
|
||||||
|
json::flat::operator<< (std::ostream &os, json::flat::type t)
|
||||||
|
{
|
||||||
|
switch (t) {
|
||||||
|
case json::flat::type::STRING: os << "STRING"; break;
|
||||||
|
case json::flat::type::NUL: os << "NUL"; break;
|
||||||
|
case json::flat::type::BOOLEAN: os << "BOOLEAN"; break;
|
||||||
|
case json::flat::type::INTEGER: os << "INTEGER"; break;
|
||||||
|
case json::flat::type::REAL: os << "REAL"; break;
|
||||||
|
|
||||||
|
case json::flat::type::OBJECT_BEGIN: os << "OBJECT_BEGIN"; break;
|
||||||
|
case json::flat::type::OBJECT_END: os << "OBJECT_END"; break;
|
||||||
|
case json::flat::type::ARRAY_BEGIN: os << "ARRAY_BEGIN"; break;
|
||||||
|
case json::flat::type::ARRAY_END: os << "ARRAY_END"; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
unreachable ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
59
json/flat.hpp
Normal file
59
json/flat.hpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libgim.
|
||||||
|
*
|
||||||
|
* libgim is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UTIL_JSON_FLAT_HPP
|
||||||
|
#define __UTIL_JSON_FLAT_HPP
|
||||||
|
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace json { namespace flat {
|
||||||
|
enum class type {
|
||||||
|
UNKNOWN,
|
||||||
|
|
||||||
|
NUL,
|
||||||
|
BOOLEAN,
|
||||||
|
STRING,
|
||||||
|
INTEGER,
|
||||||
|
REAL,
|
||||||
|
|
||||||
|
OBJECT_BEGIN,
|
||||||
|
OBJECT_END,
|
||||||
|
|
||||||
|
ARRAY_BEGIN,
|
||||||
|
ARRAY_END
|
||||||
|
};
|
||||||
|
|
||||||
|
struct item {
|
||||||
|
type tag;
|
||||||
|
const char *first;
|
||||||
|
const char *last;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T as (void) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<item> parse (const char *first, const char *last);
|
||||||
|
std::vector<item> parse (const char *first);
|
||||||
|
std::vector<item> parse (const boost::filesystem::path&);
|
||||||
|
|
||||||
|
std::ostream& operator<< (std::ostream&, type);
|
||||||
|
} }
|
||||||
|
|
||||||
|
#endif
|
@ -18,7 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "json.hpp"
|
#include "json/tree.hpp"
|
||||||
|
|
||||||
|
#include "json/except.hpp"
|
||||||
|
#include "json/flat.hpp"
|
||||||
|
|
||||||
#include "debug.hpp"
|
#include "debug.hpp"
|
||||||
#include "io.hpp"
|
#include "io.hpp"
|
||||||
@ -40,157 +43,6 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace util;
|
using namespace util;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
%%{
|
|
||||||
# JSON (rfc7159)
|
|
||||||
machine json;
|
|
||||||
|
|
||||||
action trace { if (false) std::cerr << *p; }
|
|
||||||
action success { __success = true; }
|
|
||||||
action failure { }
|
|
||||||
|
|
||||||
action new_line { ++line; }
|
|
||||||
|
|
||||||
action first { parsed.push_back ({ type::UNKNOWN, p, p}); }
|
|
||||||
action last { parsed.back ().last = p; }
|
|
||||||
|
|
||||||
action tag_nul { parsed.back ().tag = type::NUL; }
|
|
||||||
action tag_boolean { parsed.back ().tag = type::BOOLEAN; }
|
|
||||||
action tag_string { parsed.back ().tag = type::STRING; }
|
|
||||||
action tag_integer { parsed.back ().tag = type::INTEGER; }
|
|
||||||
action tag_real { parsed.back ().tag = type::REAL; }
|
|
||||||
|
|
||||||
action tag_object_begin { parsed.push_back ({ type::OBJECT_BEGIN, p, p + 1 }); }
|
|
||||||
action tag_object_end { parsed.push_back ({ type::OBJECT_END, p, p + 1 }); }
|
|
||||||
action tag_array_begin { parsed.push_back ({ type::ARRAY_BEGIN, p, p + 1 }); }
|
|
||||||
action tag_array_end { parsed.push_back ({ type::ARRAY_END, p, p + 1 }); }
|
|
||||||
|
|
||||||
# Line counter
|
|
||||||
lines = (
|
|
||||||
any | '\n' @new_line
|
|
||||||
)*;
|
|
||||||
|
|
||||||
# UTF-8 (rfc3629)
|
|
||||||
utf8_tail = 0x80..0xbf;
|
|
||||||
|
|
||||||
utf8_1 = 0x00..0x7f;
|
|
||||||
utf8_2 = 0xc2..0xdf utf8_tail;
|
|
||||||
utf8_3 = 0xe0 0xa0..0xbf utf8_tail |
|
|
||||||
0xe1..0xec utf8_tail{2} |
|
|
||||||
0xed 0x80..0x9f utf8_tail |
|
|
||||||
0xee..0xef utf8_tail{2};
|
|
||||||
utf8_4 = 0xf0 0x90..0xbf utf8_tail{2} |
|
|
||||||
0xf1..0xf3 utf8_tail{3} |
|
|
||||||
0xf4 0x80..0x8f utf8_tail{2};
|
|
||||||
|
|
||||||
|
|
||||||
utf8 = utf8_1 | utf8_2 | utf8_3 | utf8_4;
|
|
||||||
|
|
||||||
# Utility
|
|
||||||
ws = 0x20 | 0x09 | 0x0A | 0x0D;
|
|
||||||
array_start = '[';
|
|
||||||
array_end = ']';
|
|
||||||
object_start = '{';
|
|
||||||
object_end = '}';
|
|
||||||
|
|
||||||
# Strings
|
|
||||||
char =
|
|
||||||
(utf8 - ["\\])
|
|
||||||
| "\\" (
|
|
||||||
[\\"/bfnrt]
|
|
||||||
| "u" xdigit{4}
|
|
||||||
)
|
|
||||||
;
|
|
||||||
|
|
||||||
string = ('"' char* '"') >first >tag_string %*last;
|
|
||||||
|
|
||||||
# numbers
|
|
||||||
int = '0' | [1-9] digit*;
|
|
||||||
|
|
||||||
frac = '.' digit+;
|
|
||||||
e = 'e'i[+\-]?;
|
|
||||||
exp = e digit+;
|
|
||||||
|
|
||||||
number = (
|
|
||||||
'-'?
|
|
||||||
int
|
|
||||||
(frac >tag_real)?
|
|
||||||
exp?
|
|
||||||
) >tag_integer;
|
|
||||||
|
|
||||||
# wrapper types
|
|
||||||
array = array_start @{ fhold; fcall array_members; } array_end;
|
|
||||||
object = object_start @{ fhold; fcall object_members; } object_end;
|
|
||||||
|
|
||||||
# simple types; case sensitive literals
|
|
||||||
bool = ("true" | "false") >tag_boolean;
|
|
||||||
nul = "null" >tag_nul;
|
|
||||||
literal = bool | nul;
|
|
||||||
|
|
||||||
value = object | array | (number | string | literal) >first %last;
|
|
||||||
|
|
||||||
# Complex
|
|
||||||
member = string ws* ':' ws* value;
|
|
||||||
|
|
||||||
array_members := ((
|
|
||||||
array_start >tag_array_begin ws* (value ws* (',' ws* value ws*)*)? array_end >tag_array_end
|
|
||||||
) & lines)
|
|
||||||
@{ fhold; fret; } $trace $!failure;
|
|
||||||
|
|
||||||
object_members := ((
|
|
||||||
object_start >tag_object_begin ws* (member ws* (',' ws* member ws*)*)? object_end >tag_object_end
|
|
||||||
) & lines)
|
|
||||||
@{ fhold; fret; } $trace $!failure;
|
|
||||||
|
|
||||||
# meta types
|
|
||||||
document := ((ws* value ws*) & lines)
|
|
||||||
%success
|
|
||||||
$!failure
|
|
||||||
$trace;
|
|
||||||
|
|
||||||
variable stack ragelstack;
|
|
||||||
prepush { ragelstack.push_back (0); }
|
|
||||||
postpop { ragelstack.pop_back (); }
|
|
||||||
|
|
||||||
write data;
|
|
||||||
}%%
|
|
||||||
|
|
||||||
|
|
||||||
std::ostream& operator<< (std::ostream &os, json::flat::type);
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
std::vector<json::flat::item>
|
|
||||||
json::flat::parse (const char *first, const char *last)
|
|
||||||
{
|
|
||||||
const char *p = first;
|
|
||||||
const char *pe = last;
|
|
||||||
const char *eof = pe;
|
|
||||||
|
|
||||||
std::deque<int> ragelstack;
|
|
||||||
std::vector<item> parsed;
|
|
||||||
|
|
||||||
size_t line = 0;
|
|
||||||
int cs, top;
|
|
||||||
bool __success = false;
|
|
||||||
|
|
||||||
%%write init;
|
|
||||||
%%write exec;
|
|
||||||
|
|
||||||
if (!__success)
|
|
||||||
throw parse_error (line, "parse error");
|
|
||||||
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<json::flat::item>
|
|
||||||
json::flat::parse (const boost::filesystem::path &path)
|
|
||||||
{
|
|
||||||
util::mapped_file f (path);
|
|
||||||
return parse ((const char *)f.cbegin (), (const char*)f.cend ());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// External support
|
// External support
|
||||||
@ -355,32 +207,32 @@ json::tree::parse (const char *first, const char *last)
|
|||||||
|
|
||||||
const json::tree::object&
|
const json::tree::object&
|
||||||
json::tree::node::as_object (void) const
|
json::tree::node::as_object (void) const
|
||||||
{ throw type_error ("node is not an object"); }
|
{ throw json::type_error ("node is not an object"); }
|
||||||
|
|
||||||
|
|
||||||
const json::tree::array&
|
const json::tree::array&
|
||||||
json::tree::node::as_array (void) const
|
json::tree::node::as_array (void) const
|
||||||
{ throw type_error ("node is not an array"); }
|
{ throw json::type_error ("node is not an array"); }
|
||||||
|
|
||||||
|
|
||||||
const json::tree::string&
|
const json::tree::string&
|
||||||
json::tree::node::as_string (void) const
|
json::tree::node::as_string (void) const
|
||||||
{ throw type_error ("node is not a string"); }
|
{ throw json::type_error ("node is not a string"); }
|
||||||
|
|
||||||
|
|
||||||
const json::tree::number&
|
const json::tree::number&
|
||||||
json::tree::node::as_number (void) const
|
json::tree::node::as_number (void) const
|
||||||
{ throw type_error ("node is not a number"); }
|
{ throw json::type_error ("node is not a number"); }
|
||||||
|
|
||||||
|
|
||||||
const json::tree::boolean&
|
const json::tree::boolean&
|
||||||
json::tree::node::as_boolean (void) const
|
json::tree::node::as_boolean (void) const
|
||||||
{ throw type_error ("node is not a boolean"); }
|
{ throw json::type_error ("node is not a boolean"); }
|
||||||
|
|
||||||
|
|
||||||
const json::tree::null&
|
const json::tree::null&
|
||||||
json::tree::node::as_null (void) const
|
json::tree::node::as_null (void) const
|
||||||
{ throw type_error ("node is not a null"); }
|
{ throw json::type_error ("node is not a null"); }
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -394,7 +246,7 @@ json::tree::node::operator!= (const node &rhs) const
|
|||||||
bool json::tree::node::operator==(const char *rhs) const {
|
bool json::tree::node::operator==(const char *rhs) const {
|
||||||
try {
|
try {
|
||||||
return as_string ().native () == rhs;
|
return as_string ().native () == rhs;
|
||||||
} catch (const json::tree::type_error&) {
|
} catch (const json::type_error&) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -444,7 +296,7 @@ json::tree::object::operator[](const std::string &key) const {
|
|||||||
if (value == m_values.end ()) {
|
if (value == m_values.end ()) {
|
||||||
ostringstream ss;
|
ostringstream ss;
|
||||||
ss << "no key: " << key;
|
ss << "no key: " << key;
|
||||||
throw json::tree::error (ss.str());
|
throw json::error (ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return *value->second;
|
return *value->second;
|
||||||
@ -466,7 +318,7 @@ void
|
|||||||
json::tree::object::erase (const std::string &key) {
|
json::tree::object::erase (const std::string &key) {
|
||||||
auto pos = m_values.find (key);
|
auto pos = m_values.find (key);
|
||||||
if (pos == m_values.end ())
|
if (pos == m_values.end ())
|
||||||
throw json::tree::error ("erasing invalid key");
|
throw json::error ("erasing invalid key");
|
||||||
|
|
||||||
m_values.erase (key);
|
m_values.erase (key);
|
||||||
}
|
}
|
||||||
@ -649,27 +501,3 @@ namespace json { namespace tree {
|
|||||||
return std::unique_ptr<node> (new number (f));
|
return std::unique_ptr<node> (new number (f));
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
std::ostream&
|
|
||||||
operator<< (std::ostream &os, json::flat::type t)
|
|
||||||
{
|
|
||||||
switch (t) {
|
|
||||||
case json::flat::type::STRING: os << "STRING"; break;
|
|
||||||
case json::flat::type::NUL: os << "NUL"; break;
|
|
||||||
case json::flat::type::BOOLEAN: os << "BOOLEAN"; break;
|
|
||||||
case json::flat::type::INTEGER: os << "INTEGER"; break;
|
|
||||||
case json::flat::type::REAL: os << "REAL"; break;
|
|
||||||
|
|
||||||
case json::flat::type::OBJECT_BEGIN: os << "OBJECT_BEGIN"; break;
|
|
||||||
case json::flat::type::OBJECT_END: os << "OBJECT_END"; break;
|
|
||||||
case json::flat::type::ARRAY_BEGIN: os << "ARRAY_BEGIN"; break;
|
|
||||||
case json::flat::type::ARRAY_END: os << "ARRAY_END"; break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
unreachable ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return os;
|
|
||||||
}
|
|
271
json/tree.hpp
Normal file
271
json/tree.hpp
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libgim.
|
||||||
|
*
|
||||||
|
* libgim is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with libgim. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UTIL_JSON_TREE_HPP
|
||||||
|
#define __UTIL_JSON_TREE_HPP
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#include "iterator.hpp"
|
||||||
|
#include "json/flat.hpp"
|
||||||
|
|
||||||
|
namespace json { namespace tree {
|
||||||
|
class node;
|
||||||
|
class object;
|
||||||
|
class array;
|
||||||
|
class string;
|
||||||
|
class number;
|
||||||
|
class boolean;
|
||||||
|
class null;
|
||||||
|
|
||||||
|
/// Parse an encoded form of JSON into a tree structure
|
||||||
|
extern std::unique_ptr<node> parse (const boost::filesystem::path &path);
|
||||||
|
extern std::unique_ptr<node> parse (const char *start, const char *stop);
|
||||||
|
extern std::unique_ptr<node> parse (const char *start);
|
||||||
|
extern std::unique_ptr<node> parse (const std::string&);
|
||||||
|
|
||||||
|
extern void write (const json::tree::node&, std::ostream&);
|
||||||
|
|
||||||
|
/// Abstract base for all JSON values
|
||||||
|
class node {
|
||||||
|
public:
|
||||||
|
virtual ~node () { ; }
|
||||||
|
|
||||||
|
virtual const object& as_object (void) const;
|
||||||
|
virtual const array& as_array (void) const;
|
||||||
|
virtual const string& as_string (void) const;
|
||||||
|
virtual const number& as_number (void) const;
|
||||||
|
virtual const boolean& as_boolean (void) const;
|
||||||
|
virtual const null& as_null (void) const;
|
||||||
|
|
||||||
|
virtual bool is_object (void) const { return false; }
|
||||||
|
virtual bool is_array (void) const { return false; }
|
||||||
|
virtual bool is_string (void) const { return false; }
|
||||||
|
virtual bool is_number (void) const { return false; }
|
||||||
|
virtual bool is_boolean (void) const { return false; }
|
||||||
|
virtual bool is_null (void) const { return false; }
|
||||||
|
|
||||||
|
virtual bool operator==(const node &rhs) const = 0;
|
||||||
|
virtual bool operator!=(const node &rhs) const;
|
||||||
|
virtual bool operator==(const object &) const { return false; }
|
||||||
|
virtual bool operator==(const array &) const { return false; }
|
||||||
|
virtual bool operator==(const string &) const { return false; }
|
||||||
|
virtual bool operator==(const number &) const { return false; }
|
||||||
|
virtual bool operator==(const boolean &) const { return false; }
|
||||||
|
virtual bool operator==(const null &) const { return false; }
|
||||||
|
|
||||||
|
virtual bool operator==(const char *rhs) const;
|
||||||
|
virtual bool operator!=(const char *rhs) const { return !(*this == rhs); }
|
||||||
|
|
||||||
|
virtual const node& operator[] (const std::string&) const;
|
||||||
|
virtual const node& operator[] (unsigned int) const;
|
||||||
|
|
||||||
|
virtual std::ostream& write (std::ostream &os) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Represents a JSON object, and contains its children.
|
||||||
|
class object : public node {
|
||||||
|
protected:
|
||||||
|
typedef std::map<std::string, std::unique_ptr<node>> value_store;
|
||||||
|
public:
|
||||||
|
typedef value_store::iterator iterator;
|
||||||
|
typedef value_store::const_iterator const_iterator;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
value_store m_values;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~object ();
|
||||||
|
|
||||||
|
virtual const object& as_object (void) const { return *this; }
|
||||||
|
virtual bool is_object (void) const { return true; }
|
||||||
|
virtual bool operator==(const object &rhs) const;
|
||||||
|
virtual bool operator==(const node &rhs) const
|
||||||
|
{ return rhs == *this; }
|
||||||
|
|
||||||
|
virtual void insert (const std::string &key, std::unique_ptr<node>&& value);
|
||||||
|
virtual const node& operator[](const std::string &key) const;
|
||||||
|
virtual bool has (const std::string&) const;
|
||||||
|
|
||||||
|
virtual void clear (void);
|
||||||
|
virtual void erase (const std::string &key);
|
||||||
|
|
||||||
|
virtual const_iterator begin (void) const;
|
||||||
|
virtual const_iterator end (void) const;
|
||||||
|
|
||||||
|
virtual std::ostream& write (std::ostream &os) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Represents a JSON array, and contains its children.
|
||||||
|
class array : public node {
|
||||||
|
protected:
|
||||||
|
typedef std::vector<std::unique_ptr<node>>::iterator pointer_array_iterator;
|
||||||
|
typedef std::vector<std::unique_ptr<node>>::const_iterator const_pointer_array_iterator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef referencing_iterator<pointer_array_iterator> iterator;
|
||||||
|
typedef referencing_iterator<const_pointer_array_iterator> const_iterator;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<std::unique_ptr<node>> m_values;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~array();
|
||||||
|
|
||||||
|
virtual const array& as_array (void) const { return *this; }
|
||||||
|
virtual bool is_array (void) const { return true; }
|
||||||
|
virtual bool operator==(const array &rhs) const;
|
||||||
|
virtual bool operator==(const node &rhs) const
|
||||||
|
{ return rhs == *this; }
|
||||||
|
|
||||||
|
virtual size_t size (void) const
|
||||||
|
{ return m_values.size (); }
|
||||||
|
virtual node& operator [](unsigned int idx)
|
||||||
|
{ return *m_values[idx]; }
|
||||||
|
virtual const node& operator [](unsigned int idx) const
|
||||||
|
{ return *m_values[idx]; }
|
||||||
|
|
||||||
|
virtual const_iterator begin (void) const { return const_iterator (m_values.begin ()); }
|
||||||
|
virtual const_iterator end (void) const { return const_iterator (m_values.end ()); }
|
||||||
|
|
||||||
|
virtual void insert (std::unique_ptr<json::tree::node> &&_value);
|
||||||
|
|
||||||
|
virtual std::ostream& write (std::ostream &os) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Represents a JSON string literal.
|
||||||
|
class string : public node {
|
||||||
|
protected:
|
||||||
|
std::string m_value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit string (const std::string &_value): m_value (_value) { ; }
|
||||||
|
explicit string (const char *_value): m_value (_value) { ; }
|
||||||
|
string (const char *_first, const char *_last): m_value (_first, _last) { ; }
|
||||||
|
|
||||||
|
virtual const string& as_string (void) const { return *this; }
|
||||||
|
virtual bool is_string (void) const { return true; }
|
||||||
|
virtual bool operator==(const char *rhs) const;
|
||||||
|
virtual bool operator==(const string &rhs) const;
|
||||||
|
virtual bool operator==(const node &rhs) const
|
||||||
|
{ return rhs == *this; }
|
||||||
|
|
||||||
|
virtual size_t size (void) const { return m_value.size (); }
|
||||||
|
|
||||||
|
operator const std::string&(void) const { return m_value; }
|
||||||
|
const std::string& native (void) const { return m_value; }
|
||||||
|
|
||||||
|
virtual std::ostream& write (std::ostream &os) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Represents a JSON integer/float literal.
|
||||||
|
class number : public node {
|
||||||
|
protected:
|
||||||
|
double m_value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit number (double _value): m_value (_value) { ; }
|
||||||
|
explicit number (int _value): m_value (_value) { ; }
|
||||||
|
explicit number (size_t _value): m_value (_value) { ; }
|
||||||
|
|
||||||
|
virtual const number& as_number (void) const { return *this; }
|
||||||
|
virtual bool is_number (void) const { return true; }
|
||||||
|
virtual bool operator==(const number &rhs) const;
|
||||||
|
virtual bool operator==(const node &rhs) const
|
||||||
|
{ return rhs == *this; }
|
||||||
|
|
||||||
|
operator double(void) const { return m_value; }
|
||||||
|
double native (void) const { return m_value; }
|
||||||
|
|
||||||
|
virtual std::ostream& write (std::ostream &os) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Represents a JSON boolean literal.
|
||||||
|
class boolean : public node {
|
||||||
|
protected:
|
||||||
|
bool m_value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit boolean (bool _value): m_value (_value) { ; }
|
||||||
|
|
||||||
|
virtual const boolean& as_boolean (void) const { return *this; }
|
||||||
|
virtual bool is_boolean (void) const { return true; }
|
||||||
|
virtual bool operator==(const boolean &rhs) const;
|
||||||
|
virtual bool operator==(const node &rhs) const
|
||||||
|
{ return rhs == *this; }
|
||||||
|
|
||||||
|
operator bool (void) const { return m_value; }
|
||||||
|
bool native (void) const { return m_value; }
|
||||||
|
|
||||||
|
virtual std::ostream& write (std::ostream &os) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Represents a JSON null value.
|
||||||
|
class null : public node {
|
||||||
|
public:
|
||||||
|
virtual bool operator==(const null&) const { return true; }
|
||||||
|
virtual bool operator==(const node &rhs) const
|
||||||
|
{ return rhs == *this; }
|
||||||
|
|
||||||
|
virtual bool is_null (void) const { return true; }
|
||||||
|
virtual const null& as_null (void) const { return *this; }
|
||||||
|
|
||||||
|
virtual std::ostream& write (std::ostream &os) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator <<(std::ostream &os, const json::tree::node &n);
|
||||||
|
|
||||||
|
|
||||||
|
// Instantiate this template for the type you wish to output. We use a
|
||||||
|
// helper class here to avoid partial template specialisation of a
|
||||||
|
// function (eg, for templated types).
|
||||||
|
template <typename T>
|
||||||
|
struct io {
|
||||||
|
static std::unique_ptr<json::tree::node> serialise (const T&);
|
||||||
|
static T deserialise (const json::tree::node&);
|
||||||
|
};
|
||||||
|
} }
|
||||||
|
|
||||||
|
template <typename T, class ...Args>
|
||||||
|
std::unique_ptr<json::tree::node> to_json (const T &t, Args&&... args) {
|
||||||
|
return json::tree::io<T>::serialise (t, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, class ...Args>
|
||||||
|
T from_json (const json::tree::node &n, Args&&... args) {
|
||||||
|
return json::tree::io<T>::deserialise (n, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
|||||||
#include "range.hpp"
|
#include "range.hpp"
|
||||||
|
|
||||||
#include "debug.hpp"
|
#include "debug.hpp"
|
||||||
#include "json.hpp"
|
#include "json/tree.hpp"
|
||||||
#include "maths.hpp"
|
#include "maths.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
#include "../debug.hpp"
|
#include "../debug.hpp"
|
||||||
#include "../json.hpp"
|
#include "../json/tree.hpp"
|
||||||
#include "../maths.hpp"
|
#include "../maths.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
* Copyright 2012 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2012 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../json.hpp"
|
#include "json/except.hpp"
|
||||||
|
#include "json/tree.hpp"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -49,7 +50,7 @@ main (int argc, char **argv) {
|
|||||||
try {
|
try {
|
||||||
boost::filesystem::path input (argv[ARG_INPUT]);
|
boost::filesystem::path input (argv[ARG_INPUT]);
|
||||||
std::cout << *json::tree::parse (input) << "\n";
|
std::cout << *json::tree::parse (input) << "\n";
|
||||||
} catch (const json::tree::error& err) {
|
} catch (const json::error& err) {
|
||||||
std::cerr << err.what () << "\n";
|
std::cerr << err.what () << "\n";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "../json.hpp"
|
#include "json/except.hpp"
|
||||||
|
#include "json/tree.hpp"
|
||||||
|
|
||||||
#include "../debug.hpp"
|
#include "debug.hpp"
|
||||||
#include "../maths.hpp"
|
#include "maths.hpp"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@ -82,7 +83,7 @@ is_type_valid (const json::tree::node &node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!type.is_string ())
|
if (!type.is_string ())
|
||||||
throw json::tree::schema_error ("schema type requires array, string, or object");
|
throw json::schema_error ("schema type requires array, string, or object");
|
||||||
|
|
||||||
static const auto ANY_VALIDATOR = [] (const json::tree::node &) { return true; };
|
static const auto ANY_VALIDATOR = [] (const json::tree::node &) { return true; };
|
||||||
static const auto INT_VALIDATOR = [] (const json::tree::node &n) {
|
static const auto INT_VALIDATOR = [] (const json::tree::node &n) {
|
||||||
@ -120,7 +121,7 @@ bool
|
|||||||
is_enum_valid (const json::tree::node &node,
|
is_enum_valid (const json::tree::node &node,
|
||||||
const json::tree::node &constraint) {
|
const json::tree::node &constraint) {
|
||||||
if (!constraint.is_array ())
|
if (!constraint.is_array ())
|
||||||
throw json::tree::schema_error ("enum validation requires an array");
|
throw json::schema_error ("enum validation requires an array");
|
||||||
|
|
||||||
const json::tree::array &valids = constraint.as_array ();
|
const json::tree::array &valids = constraint.as_array ();
|
||||||
return valids.end () != std::find (valids.begin (),
|
return valids.end () != std::find (valids.begin (),
|
||||||
@ -318,7 +319,7 @@ bool
|
|||||||
is_max_items_valid (const json::tree::array &node,
|
is_max_items_valid (const json::tree::array &node,
|
||||||
const json::tree::node &constraint) {
|
const json::tree::node &constraint) {
|
||||||
if (!constraint.is_number () && is_integer (constraint.as_number ()))
|
if (!constraint.is_number () && is_integer (constraint.as_number ()))
|
||||||
throw json::tree::schema_error ("max_items should be an integer");
|
throw json::schema_error ("max_items should be an integer");
|
||||||
|
|
||||||
return node.size () <= constraint.as_number ();
|
return node.size () <= constraint.as_number ();
|
||||||
}
|
}
|
||||||
@ -328,7 +329,7 @@ bool
|
|||||||
is_min_items_valid (const json::tree::array &node,
|
is_min_items_valid (const json::tree::array &node,
|
||||||
const json::tree::node &constraint) {
|
const json::tree::node &constraint) {
|
||||||
if (!constraint.is_number () && is_integer (constraint.as_number ()))
|
if (!constraint.is_number () && is_integer (constraint.as_number ()))
|
||||||
throw json::tree::schema_error ("min_items should be an integer");
|
throw json::schema_error ("min_items should be an integer");
|
||||||
|
|
||||||
return node.size () >= constraint.as_number ();
|
return node.size () >= constraint.as_number ();
|
||||||
}
|
}
|
||||||
@ -338,7 +339,7 @@ bool
|
|||||||
is_unique_items_valid (const json::tree::array &node,
|
is_unique_items_valid (const json::tree::array &node,
|
||||||
const json::tree::node &constraint) {
|
const json::tree::node &constraint) {
|
||||||
if (!constraint.is_boolean ())
|
if (!constraint.is_boolean ())
|
||||||
throw json::tree::schema_error ("uniqueItems must be a boolean");
|
throw json::schema_error ("uniqueItems must be a boolean");
|
||||||
|
|
||||||
if (node.size () < 2)
|
if (node.size () < 2)
|
||||||
return true;
|
return true;
|
||||||
@ -357,7 +358,7 @@ bool
|
|||||||
is_items_valid (const json::tree::array &node,
|
is_items_valid (const json::tree::array &node,
|
||||||
const json::tree::node &_schema) {
|
const json::tree::node &_schema) {
|
||||||
if (!_schema.is_object ())
|
if (!_schema.is_object ())
|
||||||
throw json::tree::schema_error ("array_items constraint must be an object");
|
throw json::schema_error ("array_items constraint must be an object");
|
||||||
const json::tree::object &schema = _schema.as_object ();
|
const json::tree::object &schema = _schema.as_object ();
|
||||||
|
|
||||||
for (const json::tree::node &i: node)
|
for (const json::tree::node &i: node)
|
||||||
@ -445,7 +446,7 @@ is_properties_valid (const json::tree::object &node,
|
|||||||
CHECK (node.is_object ());
|
CHECK (node.is_object ());
|
||||||
|
|
||||||
if (!constraint.is_object ())
|
if (!constraint.is_object ())
|
||||||
throw json::tree::schema_error ("properties needs an object");
|
throw json::schema_error ("properties needs an object");
|
||||||
|
|
||||||
return is_properties_valid (node, constraint.as_object ());
|
return is_properties_valid (node, constraint.as_object ());
|
||||||
}
|
}
|
||||||
@ -583,7 +584,7 @@ main (int argc, char **argv) {
|
|||||||
try {
|
try {
|
||||||
schema = json::tree::parse (boost::filesystem::path (argv[ARG_SCHEMA]));
|
schema = json::tree::parse (boost::filesystem::path (argv[ARG_SCHEMA]));
|
||||||
input = json::tree::parse (boost::filesystem::path (argv[ARG_INPUT]));
|
input = json::tree::parse (boost::filesystem::path (argv[ARG_INPUT]));
|
||||||
} catch (const json::tree::parse_error &err) {
|
} catch (const json::parse_error &err) {
|
||||||
std::cerr << "malformed json for schema or input. " << err.what () << "\n";
|
std::cerr << "malformed json for schema or input. " << err.what () << "\n";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "../json.hpp"
|
#include "json/flat.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#ifndef __UTIL_VECTOR_HPP
|
#ifndef __UTIL_VECTOR_HPP
|
||||||
#define __UTIL_VECTOR_HPP
|
#define __UTIL_VECTOR_HPP
|
||||||
|
|
||||||
#include "json.hpp"
|
#include "json/tree.hpp"
|
||||||
#include "detail/coord.hpp"
|
#include "detail/coord.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
Loading…
Reference in New Issue
Block a user