diff --git a/include/tao/config/internal/change_action_and_states.hpp b/include/tao/config/internal/change_action_and_states.hpp new file mode 100644 index 0000000..e452078 --- /dev/null +++ b/include/tao/config/internal/change_action_and_states.hpp @@ -0,0 +1,60 @@ +// Copyright (c) 2019-2023 Dr. Colin Hirsch and Daniel Frey +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) + +#ifndef TAO_CONFIG_INTERNAL_CHANGE_ACTION_AND_STATES_HPP +#define TAO_CONFIG_INTERNAL_CHANGE_ACTION_AND_STATES_HPP + +#include +#include + +#include "pegtl.hpp" + +namespace tao::config::internal +{ + template< template< typename... > class NewAction, typename... NewStates > + struct change_action_and_states + : pegtl::maybe_nothing + { + template< typename Rule, + pegtl::apply_mode A, + pegtl::rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + std::size_t... Ns, + typename ParseInput, + typename... States > + [[nodiscard]] static bool match( std::index_sequence< Ns... > /*unused*/, ParseInput& in, States&&... st ) + { + auto t = std::tie( st... ); + const auto pos = in.position(); + if( Control< Rule >::template match< A, M, NewAction, Control >( in, std::get< Ns >( t )... ) ) { + if constexpr( A == pegtl::apply_mode::action ) { + Action< Rule >::success( pos, st... ); + } + return true; + } + return false; + } + + template< typename Rule, + pegtl::apply_mode A, + pegtl::rewind_mode M, + template< typename... > + class Action, + template< typename... > + class Control, + typename ParseInput, + typename... States > + [[nodiscard]] static bool match( ParseInput& in, States&&... st ) + { + static_assert( !std::is_same_v< Action< void >, NewAction< void > >, "old and new action class templates are identical" ); + return match< Rule, A, M, Action, Control >( std::index_sequence_for< NewStates... >(), in, NewStates()..., st... ); + } + }; + +} // tao::config::internal + +#endif diff --git a/include/tao/config/internal/jaxn_action.hpp b/include/tao/config/internal/jaxn_action.hpp index 784be51..093b804 100644 --- a/include/tao/config/internal/jaxn_action.hpp +++ b/include/tao/config/internal/jaxn_action.hpp @@ -9,6 +9,7 @@ #include #include +#include "change_action_and_states.hpp" #include "json.hpp" #include "pegtl.hpp" @@ -313,56 +314,56 @@ namespace tao::config::internal template<> struct jaxn_action< json::jaxn::internal::rules::single_string > - : pegtl::change_action_and_states< json::jaxn::internal::unescape_action, std::string > + : change_action_and_states< json::jaxn::internal::unescape_action, std::string > { - template< typename Input, typename Consumer > - static void success( const Input& in, std::string& unescaped, Consumer& consumer ) + template< typename Consumer > + static void success( const pegtl::position& pos, std::string& unescaped, Consumer& consumer ) { - consumer.string( std::move( unescaped ), in.position() ); // TODO: Position from start of string! + consumer.string( std::move( unescaped ), pos ); } }; template<> struct jaxn_action< json::jaxn::internal::rules::string > - : pegtl::change_action_and_states< json::jaxn::internal::unescape_action, std::string > + : change_action_and_states< json::jaxn::internal::unescape_action, std::string > { - template< typename Input, typename Consumer > - static void success( const Input& in, std::string& unescaped, Consumer& consumer ) + template< typename Consumer > + static void success( const pegtl::position& pos, std::string& unescaped, Consumer& consumer ) { - consumer.string( std::move( unescaped ), in.position() ); // TODO: Position from start of string! + consumer.string( std::move( unescaped ), pos ); } }; template<> struct jaxn_action< json::jaxn::internal::rules::key > - : pegtl::change_action_and_states< json::jaxn::internal::unescape_action, std::string > + : change_action_and_states< json::jaxn::internal::unescape_action, std::string > { - template< typename Input, typename Consumer > - static void success( const Input& in, std::string& unescaped, Consumer& consumer ) + template< typename Consumer > + static void success( const pegtl::position& pos, std::string& unescaped, Consumer& consumer ) { - consumer.key( std::move( unescaped ), in.position() ); // TODO: Position from start of string! + consumer.key( std::move( unescaped ), pos ); } }; template<> struct jaxn_action< json::jaxn::internal::rules::single_binary > - : pegtl::change_action_and_states< json::jaxn::internal::bunescape_action, std::vector< std::byte > > + : change_action_and_states< json::jaxn::internal::bunescape_action, std::vector< std::byte > > { - template< typename Input, typename Consumer > - static void success( const Input& in, std::vector< std::byte >& value, Consumer& consumer ) + template< typename Consumer > + static void success( const pegtl::position& pos, std::vector< std::byte >& value, Consumer& consumer ) { - consumer.binary( std::move( value ), in.position() ); // TODO: Position from start of binary! + consumer.binary( std::move( value ), pos ); } }; template<> struct jaxn_action< json::jaxn::internal::rules::binary > - : pegtl::change_action_and_states< json::jaxn::internal::bunescape_action, std::vector< std::byte > > + : change_action_and_states< json::jaxn::internal::bunescape_action, std::vector< std::byte > > { - template< typename Input, typename Consumer > - static void success( const Input& in, std::vector< std::byte >& value, Consumer& consumer ) + template< typename Consumer > + static void success( const pegtl::position& pos, std::vector< std::byte >& value, Consumer& consumer ) { - consumer.binary( std::move( value ), in.position() ); // TODO: Position from start of binary! + consumer.binary( std::move( value ), pos ); } }; diff --git a/src/test/config/CMakeLists.txt b/src/test/config/CMakeLists.txt index a80bfe1..be7c3b8 100644 --- a/src/test/config/CMakeLists.txt +++ b/src/test/config/CMakeLists.txt @@ -6,6 +6,7 @@ set(testsources custom.cpp enumerations.cpp failure.cpp + multi_line_string_position.cpp parse_key1.cpp parse_key.cpp parse_reference2.cpp diff --git a/src/test/config/multi_line_string_position.cpp b/src/test/config/multi_line_string_position.cpp new file mode 100644 index 0000000..9433c47 --- /dev/null +++ b/src/test/config/multi_line_string_position.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2023 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/config/ + +#include + +#include + +namespace tao +{ + void test1() + { + const std::string input = "foo = '''a\nb\nc\n'''"; + const auto config = config::from_string( input, __FUNCTION__ ); + const auto string = config.get_object().at( "foo" ); + assert( string.position.line() == 1 ); + assert( string.get_string() == "a\nb\nc\n" ); + } + + void test2() + { + const std::string input = "foo = '''\na\nb\nc\n'''"; + const auto config = config::from_string( input, __FUNCTION__ ); + const auto string = config.get_object().at( "foo" ); + assert( string.position.line() == 1 ); // Should this be 2? + assert( string.get_string() == "a\nb\nc\n" ); + } + + void test3() + { + const std::string input = "\n\n\nfoo = '''a\nb\nc\n'''"; + const auto config = config::from_string( input, __FUNCTION__ ); + const auto string = config.get_object().at( "foo" ); + assert( string.position.line() == 4 ); + assert( string.get_string() == "a\nb\nc\n" ); + } + + void test4() + { + const std::string input = "\n\n\nfoo = '''\na\nb\nc\n'''"; + const auto config = config::from_string( input, __FUNCTION__ ); + const auto string = config.get_object().at( "foo" ); + assert( string.position.line() == 4 ); // Should this be 5? + assert( string.get_string() == "a\nb\nc\n" ); + } + +} // namespace tao + +int main() +{ + tao::test1(); + tao::test2(); + tao::test3(); + tao::test4(); + return 0; +}