1 // Copyright (c) 2014-2020 Dr. Colin Hirsch and Daniel Frey
2 // Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/
3 
4 #ifndef TAO_PEGTL_PARSE_ERROR_HPP
5 #define TAO_PEGTL_PARSE_ERROR_HPP
6 
7 #include <cstddef>
8 #include <memory>
9 #include <stdexcept>
10 #include <string>
11 #include <string_view>
12 #include <utility>
13 #include <vector>
14 
15 #include "config.hpp"
16 #include "position.hpp"
17 
18 namespace TAO_PEGTL_NAMESPACE
19 {
20    namespace internal
21    {
22       class parse_error
23       {
24       private:
25          std::string m_msg;
26          std::size_t m_prefix = 0;
27          std::vector< position > m_positions;
28 
29       public:
parse_error(const char * msg)30          explicit parse_error( const char* msg )
31             : m_msg( msg )
32          {}
33 
what() const34          [[nodiscard]] const char* what() const noexcept
35          {
36             return m_msg.c_str();
37          }
38 
message() const39          [[nodiscard]] std::string_view message() const noexcept
40          {
41             return { m_msg.data() + m_prefix, m_msg.size() - m_prefix };
42          }
43 
positions() const44          [[nodiscard]] const std::vector< position >& positions() const noexcept
45          {
46             return m_positions;
47          }
48 
add_position(position && p)49          void add_position( position&& p )
50          {
51             const auto prefix = to_string( p );
52             m_msg = prefix + ": " + m_msg;
53             m_prefix += prefix.size() + 2;
54             m_positions.emplace_back( std::move( p ) );
55          }
56       };
57 
58    }  // namespace internal
59 
60    class parse_error
61       : public std::runtime_error
62    {
63    private:
64       std::shared_ptr< internal::parse_error > m_impl;
65 
66    public:
parse_error(const char * msg,position p)67       parse_error( const char* msg, position p )
68          : std::runtime_error( msg ),
69            m_impl( std::make_shared< internal::parse_error >( msg ) )
70       {
71          m_impl->add_position( std::move( p ) );
72       }
73 
parse_error(const std::string & msg,position p)74       parse_error( const std::string& msg, position p )
75          : parse_error( msg.c_str(), std::move( p ) )
76       {}
77 
78       template< typename ParseInput >
parse_error(const char * msg,const ParseInput & in)79       parse_error( const char* msg, const ParseInput& in )
80          : parse_error( msg, in.position() )
81       {}
82 
83       template< typename ParseInput >
parse_error(const std::string & msg,const ParseInput & in)84       parse_error( const std::string& msg, const ParseInput& in )
85          : parse_error( msg.c_str(), in.position() )
86       {}
87 
what() const88       [[nodiscard]] const char* what() const noexcept override
89       {
90          return m_impl->what();
91       }
92 
message() const93       [[nodiscard]] std::string_view message() const noexcept
94       {
95          return m_impl->message();
96       }
97 
positions() const98       [[nodiscard]] const std::vector< position >& positions() const noexcept
99       {
100          return m_impl->positions();
101       }
102 
add_position(position && p)103       void add_position( position&& p )
104       {
105          if( m_impl.use_count() > 1 ) {
106             m_impl = std::make_shared< internal::parse_error >( *m_impl );
107          }
108          m_impl->add_position( std::move( p ) );
109       }
110    };
111 
112 }  // namespace TAO_PEGTL_NAMESPACE
113 
114 #endif
115