// Copyright (c) 2014-2018 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
#include <cassert>
#include <sstream>
#include <tao/pegtl.hpp>
#include <tao/pegtl/contrib/changes.hpp>
#include <tao/pegtl/contrib/json.hpp>
#include "json_classes.hpp"
#include "json_errors.hpp"
#include "json_unescape.hpp"
namespace examples
{
// Basic state class that stores the result of a JSON parsing run -- a single JSON object.
struct result_state
{
result_state() = default;
result_state( const result_state& ) = delete;
result_state( result_state&& ) = delete;
~result_state() = default;
void operator=( const result_state& ) = delete;
void operator=( result_state&& ) = delete;
std::shared_ptr< json_base > result;
};
// Action class for the simple cases...
template< typename Rule >
struct value_action
: unescape_action< Rule >
{
};
struct string_state
: public unescape_state_base
{
void success( result_state& result )
{
result.result = std::make_shared< string_json >( std::move( unescaped ) );
}
};
template<>
struct value_action< tao::TAO_PEGTL_NAMESPACE::json::null >
{
static void apply0( result_state& result )
{
result.result = std::make_shared< null_json >();
}
};
template<>
struct value_action< tao::TAO_PEGTL_NAMESPACE::json::true_ >
{
static void apply0( result_state& result )
{
result.result = std::make_shared< boolean_json >( true );
}
};
template<>
struct value_action< tao::TAO_PEGTL_NAMESPACE::json::false_ >
{
static void apply0( result_state& result )
{
result.result = std::make_shared< boolean_json >( false );
}
};
template<>
struct value_action< tao::TAO_PEGTL_NAMESPACE::json::number >
{
template< typename Input >
static void apply( const Input& in, result_state& result )
{
std::stringstream ss;
ss << in.string();
long double v;
ss >> v; // NOTE: not quite correct for JSON but we'll use it for this simple example.
result.result = std::make_shared< number_json >( v );
}
};
// State and action classes to accumulate the data for a JSON array.
struct array_state
: public result_state
{
std::shared_ptr< array_json > array = std::make_shared< array_json >();
void push_back()
{
array->data.push_back( std::move( result ) );
result.reset();
}
void success( result_state& in_result )
{
if( this->result ) {
push_back();
}
in_result.result = array;
}
};
template< typename Rule >
struct array_action
: tao::TAO_PEGTL_NAMESPACE::nothing< Rule >
{
};
template<>
struct array_action< tao::TAO_PEGTL_NAMESPACE::json::value_separator >
{
static void apply0( array_state& result )
{
result.push_back();
}
};
// State and action classes to accumulate the data for a JSON object.
struct object_state
: public result_state
{
std::string unescaped;
std::shared_ptr< object_json > object = std::make_shared< object_json >();
void insert()
{
object->data.insert( std::make_pair( std::move( unescaped ), std::move( result ) ) );
unescaped.clear();
result.reset();
}
void success( result_state& in_result )
{
if( this->result ) {
insert();
}
in_result.result = object;
}
};
template< typename Rule >
struct object_action
: unescape_action< Rule >
{
};
template<>
struct object_action< tao::TAO_PEGTL_NAMESPACE::json::value_separator >
{
static void apply0( object_state& result )
{
result.insert();
}
};
// Put together a control class that changes the actions and states as required.
// clang-format off
template< typename Rule > struct control : errors< Rule > {}; // Inherit from json_errors.hpp.
template<> struct control< tao::TAO_PEGTL_NAMESPACE::json::value > : tao::TAO_PEGTL_NAMESPACE::change_action< tao::TAO_PEGTL_NAMESPACE::json::value, value_action, errors > {};
template<> struct control< tao::TAO_PEGTL_NAMESPACE::json::string::content > : tao::TAO_PEGTL_NAMESPACE::change_state< tao::TAO_PEGTL_NAMESPACE::json::string::content, string_state, errors > {};
template<> struct control< tao::TAO_PEGTL_NAMESPACE::json::array::content > : tao::TAO_PEGTL_NAMESPACE::change_state_and_action< tao::TAO_PEGTL_NAMESPACE::json::array::content, array_state, array_action, errors > {};
template<> struct control< tao::TAO_PEGTL_NAMESPACE::json::object::content > : tao::TAO_PEGTL_NAMESPACE::change_state_and_action< tao::TAO_PEGTL_NAMESPACE::json::object::content, object_state, object_action, errors > {};
struct grammar : tao::TAO_PEGTL_NAMESPACE::must< tao::TAO_PEGTL_NAMESPACE::json::text, tao::TAO_PEGTL_NAMESPACE::eof > {};
// clang-format on
} // namespace examples
int main( int argc, char** argv )
{
for( int i = 1; i < argc; ++i ) {
examples::result_state result;
tao::TAO_PEGTL_NAMESPACE::file_input<> in( argv[ i ] );
tao::TAO_PEGTL_NAMESPACE::parse< examples::grammar, tao::TAO_PEGTL_NAMESPACE::nothing, examples::control >( in, result );
assert( result.result );
std::cout << result.result << std::endl;
}
return 0;
}