Skip to content

Commit

Permalink
Work in progress.
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinH committed Feb 28, 2024
1 parent 3dacaef commit 0875d1f
Show file tree
Hide file tree
Showing 23 changed files with 357 additions and 89 deletions.
2 changes: 1 addition & 1 deletion include/tao/config/internal/array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#ifndef TAO_CONFIG_INTERNAL_ARRAY_HPP
#define TAO_CONFIG_INTERNAL_ARRAY_HPP

#include <iterator>
#include <cstddef>
#include <list>

#include "forward.hpp"
Expand Down
4 changes: 4 additions & 0 deletions include/tao/config/internal/concat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#ifndef TAO_CONFIG_INTERNAL_CONCAT_HPP
#define TAO_CONFIG_INTERNAL_CONCAT_HPP

#include <cstddef>
#include <cstdint>
#include <iterator>
#include <list>
#include <stdexcept>
Expand Down Expand Up @@ -64,6 +66,8 @@ namespace tao::config::internal
}
result = &e.get_value();
continue;
case entry_kind::function:
throw pegtl::parse_error( "function as referenced reference part", e.get_function().position );
case entry_kind::reference:
throw std::logic_error( "code should be unreachable" ); // LCOV_EXCL_LINE
case entry_kind::array:
Expand Down
23 changes: 12 additions & 11 deletions include/tao/config/internal/config_grammar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

namespace tao::config::internal::rules
{
struct reference_value
struct jaxn_value
{
using rule_t = reference_value;
using subs_t = pegtl::type_list< reference2_rest >;
using rule_t = jaxn_value;
using subs_t = pegtl::type_list< json::jaxn::internal::rules::sor_single_value >;

template< pegtl::apply_mode A,
pegtl::rewind_mode M,
Expand All @@ -33,17 +33,17 @@ namespace tao::config::internal::rules
typename State >
[[nodiscard]] static bool match( pegtl_input_t& in, State& st, const extension_maps& )
{
const auto r = parse_reference2( in );
const auto f = [ & ]( concat& c ) { c.concat.emplace_back( r ); };
const auto j = parse_jaxn( in );
const auto f = [ & ]( concat& c ) { c.concat.emplace_back( j ); };
phase1_append( st.root, st.prefix + st.suffix, f, phase1_mode::manifest );
return true;
}
};

struct jaxn_value
struct reference_value
{
using rule_t = jaxn_value;
using subs_t = pegtl::type_list< json::jaxn::internal::rules::sor_single_value >;
using rule_t = reference_value;
using subs_t = pegtl::type_list< reference2_rest >;

template< pegtl::apply_mode A,
pegtl::rewind_mode M,
Expand All @@ -54,8 +54,8 @@ namespace tao::config::internal::rules
typename State >
[[nodiscard]] static bool match( pegtl_input_t& in, State& st, const extension_maps& )
{
const auto j = parse_jaxn( in );
const auto f = [ & ]( concat& c ) { c.concat.emplace_back( j ); };
const auto r = parse_reference2( in );
const auto f = [ & ]( concat& c ) { c.concat.emplace_back( r ); };
phase1_append( st.root, st.prefix + st.suffix, f, phase1_mode::manifest );
return true;
}
Expand Down Expand Up @@ -107,8 +107,9 @@ namespace tao::config::internal::rules
struct opt_comma : pegtl::opt< pegtl::one< ',' >, wss > {};

template< typename U > struct member_list_impl : pegtl::until< U, member, wss, opt_comma > {};
template< typename U > struct element_list_impl : pegtl::until< U, value_list, wss, opt_comma > {};

struct element_list : pegtl::until< jaxn::end_array, value_list, wss, opt_comma > {};
struct element_list : element_list_impl< jaxn::end_array > {};
struct array : pegtl::if_must< jaxn::begin_array, element_list > {};
struct member_list : member_list_impl< jaxn::end_object > {};
struct object : pegtl::if_must< jaxn::begin_object, member_list > {};
Expand Down
5 changes: 4 additions & 1 deletion include/tao/config/internal/config_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "json_traits.hpp"
#include "member_functions.hpp"
#include "pegtl.hpp"
#include "phase2_call.hpp"
#include "phase2_combine.hpp"
#include "phase2_replace.hpp"
#include "phase2_resolve.hpp"
Expand Down Expand Up @@ -89,12 +90,14 @@ namespace tao::config::internal

[[nodiscard]] bool phase2_iteration()
{
return ( phase2_combine( st.root ) + phase2_resolve( st.root ) + phase2_replace( st.root ) ) > 0;
return ( phase2_call( st.root, em ) + phase2_combine( st.root ) + phase2_resolve( st.root ) + phase2_replace( st.root ) ) > 0;
}

void phase2_loop()
{
while( phase2_iteration() ) {
// This loop could do with some major optimisations, though they would only be worth it
// if somebody reads some really large config files or reads one 10^7 times per second.
}
}

Expand Down
14 changes: 14 additions & 0 deletions include/tao/config/internal/debug_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ namespace tao::config::internal
case entry_kind::value:
c.string( "value" );
return;
case entry_kind::function:
c.string( "function" );
return;
case entry_kind::reference:
c.string( "reference" );
return;
Expand Down Expand Up @@ -284,6 +287,10 @@ namespace tao::config::internal
c.key( "value" );
json::events::produce< Traits >( c, v.get_value() );
break;
case entry_kind::function:
c.key( "function" );
json::events::produce< Traits >( c, v.get_function() );
break;
case entry_kind::reference:
c.key( "reference" );
json::events::produce< Traits >( c, v.get_reference() );
Expand Down Expand Up @@ -327,6 +334,13 @@ namespace tao::config::internal
TAO_JSON_BIND_REQUIRED( "object_data", &object::object ) >
{};

template<>
struct debug_traits< function >
: json::binding::object< TAO_JSON_BIND_REQUIRED( "position", &function::position ),
TAO_JSON_BIND_REQUIRED( "function", &function::name ),
TAO_JSON_BIND_REQUIRED( "function_args", &function::array ) >
{};

template< typename T >
struct debug_traits< const T* >
{
Expand Down
33 changes: 30 additions & 3 deletions include/tao/config/internal/entry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "constants.hpp"
#include "entry_kind.hpp"
#include "forward.hpp"
#include "function.hpp"
#include "json.hpp"
#include "json_traits.hpp"
#include "object.hpp"
Expand All @@ -26,7 +27,7 @@ namespace tao::config::internal
{
struct entry
{
using data_t = std::variant< json_t, reference2, array, object, concat >;
using data_t = std::variant< json_t, function, reference2, array, object, concat >;

explicit entry( const json_t& j )
: m_data( j )
Expand All @@ -40,11 +41,16 @@ namespace tao::config::internal
assert( !r.empty() );
}

entry( const std::string& n, const pegtl::position& p )
: m_data( std::in_place_type_t< function >(), n, p )
{}

entry( const entry_kind k, const pegtl::position& p )
: m_data( std::in_place_type_t< object >(), p )
{
switch( k ) {
case entry_kind::value:
case entry_kind::function:
case entry_kind::reference:
throw std::string( "this should never happen" );
case entry_kind::array:
Expand All @@ -59,12 +65,12 @@ namespace tao::config::internal
throw std::logic_error( "code should be unreachable" ); // LCOV_EXCL_LINE
}

entry( entry&& ) = delete;
entry( entry&& ) = default;
entry( const entry& ) = default;

~entry() = default;

entry& operator=( entry&& ) = delete;
entry& operator=( entry&& ) = default;
entry& operator=( const entry& ) = default;

entry_kind kind() const noexcept
Expand All @@ -77,6 +83,11 @@ namespace tao::config::internal
return std::holds_alternative< json_t >( m_data );
}

[[nodiscard]] bool is_function() const noexcept
{
return std::holds_alternative< function >( m_data );
}

[[nodiscard]] bool is_reference() const noexcept
{
return std::holds_alternative< reference2 >( m_data );
Expand Down Expand Up @@ -119,6 +130,13 @@ namespace tao::config::internal
return *s;
}

[[nodiscard]] function& get_function() noexcept
{
auto* s = std::get_if< function >( &m_data );
assert( s );
return *s;
}

[[nodiscard]] reference2& get_reference() noexcept
{
auto* s = std::get_if< reference2 >( &m_data );
Expand Down Expand Up @@ -154,6 +172,13 @@ namespace tao::config::internal
return *s;
}

[[nodiscard]] const function& get_function() const noexcept
{
const auto* s = std::get_if< function >( &m_data );
assert( s );
return *s;
}

[[nodiscard]] const reference2& get_reference() const noexcept
{
const auto* s = std::get_if< reference2 >( &m_data );
Expand Down Expand Up @@ -187,6 +212,8 @@ namespace tao::config::internal
switch( kind() ) {
case entry_kind::value:
return 0;
case entry_kind::function:
return get_function().count_references_recursive();
case entry_kind::reference:
return 1;
case entry_kind::array:
Expand Down
9 changes: 5 additions & 4 deletions include/tao/config/internal/entry_kind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ namespace tao::config::internal
enum class entry_kind : char
{
value = 0,
reference = 1,
array = 2,
object = 3,
concat = 4
function = 1,
reference = 2,
array = 3,
object = 4,
concat = 5
};

} // namespace tao::config::internal
Expand Down
2 changes: 2 additions & 0 deletions include/tao/config/internal/extension_maps.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ namespace tao::config::internal
inner_extension_map inner;
outer_extension_map member;
outer_extension_map value;

inner_function_map functions;
};

} // namespace tao::config::internal
Expand Down
3 changes: 3 additions & 0 deletions include/tao/config/internal/extension_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

namespace tao::config::internal
{
using inner_function = std::function< bool( entry& ) >;
using inner_function_map = std::map< std::string, inner_function >;

using inner_extension = std::function< json_t( pegtl_input_t&, state&, const extension_maps& ) >;
using inner_extension_map = std::map< std::string, inner_extension >;

Expand Down
3 changes: 3 additions & 0 deletions include/tao/config/internal/forward.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ namespace tao::config::internal
struct basic_array;
template< typename C >
struct basic_object;
template< typename C >
struct basic_function;

using array = basic_array< concat >;
using object = basic_object< concat >;
using function = basic_function< concat >;

template< typename T >
struct argument_traits;
Expand Down
53 changes: 53 additions & 0 deletions include/tao/config/internal/function.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2019-2024 Dr. Colin Hirsch and Daniel Frey
// Please see LICENSE for license or visit https://github.com/taocpp/config/

#ifndef TAO_CONFIG_INTERNAL_FUNCTION_HPP
#define TAO_CONFIG_INTERNAL_FUNCTION_HPP

#include <cstddef>
#include <list>
#include <string>

#include "forward.hpp"
#include "pegtl.hpp"

namespace tao::config::internal
{
template< typename C >
struct basic_function
{
using data_t = std::list< C >;

basic_function() = delete;

basic_function( const std::string& n, const pegtl::position& p )
: name( n ),
position( p )
{}

basic_function( basic_function&& ) = default;
basic_function( const basic_function& ) = default;

~basic_function() = default;

basic_function& operator=( basic_function&& ) = default;
basic_function& operator=( const basic_function& ) = default;

[[nodiscard]] std::size_t count_references_recursive() const noexcept
{
std::size_t result = 0;

for( const auto& c : array ) {
result += c.count_references_recursive();
}
return result;
}

std::string name;
std::list< C > array;
pegtl::position position;
};

} // namespace tao::config::internal

#endif
39 changes: 39 additions & 0 deletions include/tao/config/internal/inner_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#ifndef TAO_CONFIG_INTERNAL_INNER_FUNCTIONS_HPP
#define TAO_CONFIG_INTERNAL_INNER_FUNCTIONS_HPP

#include <string>
#include <vector>

#include "jaxn_action.hpp"
#include "json.hpp"
#include "json_traits.hpp"
Expand All @@ -29,6 +32,42 @@ namespace tao::config::internal
return ( !l.is_null() ) ? l : r;
}

[[nodiscard]] inline bool new_default_function( entry& e, function& f )
{
if( f.array.size() < 2 ) {
throw pegtl::parse_error( "default function requires at least two arguments", f.position );
}
for( concat& c : f.array ) {
if( c.concat.size() != 1 ) {
return false;
}
entry& a = c.concat.front();

switch( a.kind() ) {
case entry_kind::value:
if( a.get_value().is_null() ) {
continue;
}
break;
case entry_kind::function:
return false;
case entry_kind::reference:
return false;
case entry_kind::array:
break;
case entry_kind::object:
break;
case entry_kind::concat:
return false;
}
// Both a and f are sub-objects of e.
entry t = std::move( a );
e = std::move( t );
return true;
}
throw pegtl::parse_error( "default function requires at least one non-null argument", f.position );
}

[[nodiscard]] inline std::string env_function( const pegtl::position& p, const std::string& s )
{
return get_env_throws( p, s );
Expand Down
Loading

0 comments on commit 0875d1f

Please sign in to comment.