Skip to content

Commit

Permalink
Fix multi-line string etc. positions.
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinH committed Nov 8, 2023
1 parent d243d30 commit df77d55
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 20 deletions.
60 changes: 60 additions & 0 deletions include/tao/config/internal/change_action_and_states.hpp
Original file line number Diff line number Diff line change
@@ -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 <tuple>
#include <utility>

#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
41 changes: 21 additions & 20 deletions include/tao/config/internal/jaxn_action.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <utility>
#include <vector>

#include "change_action_and_states.hpp"
#include "json.hpp"
#include "pegtl.hpp"

Expand Down Expand Up @@ -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 );
}
};

Expand Down
1 change: 1 addition & 0 deletions src/test/config/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 55 additions & 0 deletions src/test/config/multi_line_string_position.cpp
Original file line number Diff line number Diff line change
@@ -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 <cassert>

#include <tao/config.hpp>

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;
}

0 comments on commit df77d55

Please sign in to comment.