PEGTL
PEGTL copied to clipboard
Error propagation
would it be possible to modify parse_error to support error probogation?
i have a basic version working
parse_error.hpp
namespace TAO_PEGTL_NAMESPACE
{
namespace internal
{
class parse_error
{
private:
std::string m_src;
// ...
explicit parse_error( const char* where, const char* msg )
: m_src(where), m_msg( msg )
{}
explicit parse_error( const std::string& where, const char* msg )
: m_src(where), m_msg( msg )
{}
[[nodiscard]] const char* where() const noexcept
{
return m_src.c_str();
}
// ...
};
} // namespace internal
class parse_error
: public std::runtime_error
{
// ...
parse_error( const char* where, const char* msg, position p )
: std::runtime_error( msg ),
m_impl( std::make_shared< internal::parse_error >(where, msg ) )
{
m_impl->add_position( std::move( p ) );
}
parse_error( const std::string& where, const char* msg, position p )
: std::runtime_error( msg ),
m_impl( std::make_shared< internal::parse_error >(where.c_str(), msg ) )
{
m_impl->add_position( std::move( p ) );
}
parse_error( const std::string_view& where, const char* msg, position p )
: std::runtime_error( msg ),
m_impl( std::make_shared< internal::parse_error >(std::string(where.data(), where.size()), msg ) )
{
m_impl->add_position( std::move( p ) );
}
parse_error( const char* where, const std::string& msg, position p )
: parse_error( where, msg.c_str(), std::move( p ) )
{}
parse_error( const std::string& where, const std::string& msg, position p )
: parse_error( where.c_str(), msg.c_str(), std::move( p ) )
{}
parse_error( const std::string_view& where, const std::string& msg, position p )
: parse_error( std::string(where.data(), where.size()), msg.c_str(), std::move( p ) )
{}
template< typename ParseInput >
parse_error( const char* msg, const ParseInput& in )
: parse_error( in.line_at(in.position()), msg, in.position() )
{}
template< typename ParseInput >
parse_error( const std::string& msg, const ParseInput& in )
: parse_error( in.line_at(in.position()), msg, in.position() )
{}
// ...
[[nodiscard]] const char* where() const noexcept
{
return m_impl->where();
}
// ...
};
} // namespace TAO_PEGTL_NAMESPACE
action_input.hpp
// ...
[[nodiscard]] std::string_view line_at( const TAO_PEGTL_NAMESPACE::position& p ) const noexcept
{
return input().line_at(p);
}
// ...
the source line is obtainable via e.where()
and should replace in.line_at(p)
or in.line_at(e.positions().front())
the source line is automatically set when given a ParseInput
and can be set manually via where
prefix as where, msg, pos
instead of msg, pos
such enables correct source line probogation when sub-parsing inside of actions
#61 GLSL_PREPROCESSOR::spaces
success
position GLSL preprocessor macro expansion:1:10
source bar A (4 + (2 * x))()
^
// ...
#97 tao::pegtl::raise_message<'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ', 'c', 'h', 'a', 'r', 'a', 'c', 't', 'e', 'r', ' ', 'f', 'o', 'u', 'n', 'd'>
raise tao::pegtl::raise_message<'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ', 'c', 'h', 'a', 'r', 'a', 'c', 't', 'e', 'r', ' ', 'f', 'o', 'u', 'n', 'd'>
unwind
unwind #83 GLSL_PREPROCESSOR::function_call_arg
unwind #82 GLSL_PREPROCESSOR::function_call_arg_and_optional_comma
unwind #78 tao::pegtl::sor<tao::pegtl::seq<tao::pegtl::at<tao::pegtl::eof>, tao::pegtl::raise_message<'U', 'n', 't', 'e', 'r', 'm', 'i', 'n', 'a', 't', 'e', 'd', ' ', 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', ' ', 'p', 'a', 'r', 'e', 'n', 't', 'h', 'e', 's', 'i', 's', ',', ' ', 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd', ' ', '\'', ')', '\'', ' ', 't', 'o', ' ', 'm', 'a', 't', 'c', 'h', ' ', '\'', '(', '\''> >, GLSL_PREPROCESSOR::function_call_arg_and_optional_comma>
unwind #75 tao::pegtl::until<tao::pegtl::at<GLSL_PREPROCESSOR::function_end>, tao::pegtl::sor<tao::pegtl::seq<tao::pegtl::at<tao::pegtl::eof>, tao::pegtl::raise_message<'U', 'n', 't', 'e', 'r', 'm', 'i', 'n', 'a', 't', 'e', 'd', ' ', 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', ' ', 'p', 'a', 'r', 'e', 'n', 't', 'h', 'e', 's', 'i', 's', ',', ' ', 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd', ' ', '\'', ')', '\'', ' ', 't', 'o', ' ', 'm', 'a', 't', 'c', 'h', ' ', '\'', '(', '\''> >, GLSL_PREPROCESSOR::function_call_arg_and_optional_comma> >
unwind #46 GLSL_PREPROCESSOR::function_call_parens
unwind #35 GLSL_PREPROCESSOR::function_call_actual
unwind #34 GLSL_PREPROCESSOR::function_call
unwind #30 tao::pegtl::sor<GLSL_PREPROCESSOR::whitespaces, GLSL_PREPROCESSOR::function_call, GLSL_PREPROCESSOR::identifier, tao::pegtl::ascii::any>
position GLSL preprocessor macro expansion:1:5
source bar A (4 + (2 * x))()
^
unwind #2 tao::pegtl::plus<tao::pegtl::sor<GLSL_PREPROCESSOR::whitespaces, GLSL_PREPROCESSOR::function_call, GLSL_PREPROCESSOR::identifier, tao::pegtl::ascii::any>>
unwind #1 GLSL_PREPROCESSOR::grammar___
position GLSL preprocessor macro expansion:1:1
source bar A (4 + (2 * x))()
^
unwind
unwind #11 GLSL_PREPROCESSOR::function_call_actual
position GLSL preprocessor function expansion:1:1
source foo(bar)
^
GLSL preprocessor macro expansion:1:10: Invalid character found
bar A (4 + (2 * x))()
^
} catch (const pegtl::parse_error &e) {
const auto p = e.positions().front();
std:cerr << e.what() << '\n'
<< e.where() << '\n'
<< std::setw(p.column) << '^' << std::endl;
}
This violates the zero-overhead-principle, as everybody would pay the price for this whether they need to information or not.
hmm what can be another way to achieve this without violating the zero overhead?
Does the new approach with nested exceptions help (currently on the "work" branch, will be soon merged into "main")? If you look at the anatomy of parse_error
you'll see that we are preparing for different position
types which gives much greater flexibility regarding what information is put into a parse error. Otherwise you can of course use your own parse_error
in your projects with a custom control class whose raise()
throws your exceptions rather than the "standard" PEGTL ones.