1/*=============================================================================
2 Copyright (c) 2014 Joel de Guzman
3
4 Distributed under the Boost Software License, Version 1.0. (See accompanying
5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6==============================================================================*/
7#if !defined(BOOST_SPIRIT_X3_ERROR_REPORTING_MAY_19_2014_00405PM)
8#define BOOST_SPIRIT_X3_ERROR_REPORTING_MAY_19_2014_00405PM
9
10#include <boost/spirit/home/x3/support/ast/position_tagged.hpp>
11#include <boost/spirit/home/x3/support/utility/utf8.hpp>
12#include <ostream>
13
14// Clang-style error handling utilities
15
16namespace boost { namespace spirit { namespace x3
17{
18 // tag used to get our error handler from the context
19 struct error_handler_tag;
20
21 template <typename Iterator>
22 class error_handler
23 {
24 public:
25
26 typedef Iterator iterator_type;
27
28 error_handler(
29 Iterator first, Iterator last, std::ostream& err_out
30 , std::string file = "", int tabs = 4)
31 : err_out(err_out)
32 , file(file)
33 , tabs(tabs)
34 , pos_cache(first, last) {}
35
36 typedef void result_type;
37
38 void operator()(Iterator err_pos, std::string const& error_message) const;
39 void operator()(Iterator err_first, Iterator err_last, std::string const& error_message) const;
40 void operator()(position_tagged pos, std::string const& message) const
41 {
42 auto where = pos_cache.position_of(pos);
43 (*this)(where.begin(), where.end(), message);
44 }
45
46 template <typename AST>
47 void tag(AST& ast, Iterator first, Iterator last)
48 {
49 return pos_cache.annotate(ast, first, last);
50 }
51
52 boost::iterator_range<Iterator> position_of(position_tagged pos) const
53 {
54 return pos_cache.position_of(pos);
55 }
56
57 position_cache<std::vector<Iterator>> const& get_position_cache() const
58 {
59 return pos_cache;
60 }
61
62 private:
63
64 void print_file_line(std::size_t line) const;
65 void print_line(Iterator line_start, Iterator last) const;
66 void print_indicator(Iterator& line_start, Iterator last, char ind) const;
67 Iterator get_line_start(Iterator first, Iterator pos) const;
68 std::size_t position(Iterator i) const;
69
70 std::ostream& err_out;
71 std::string file;
72 int tabs;
73 position_cache<std::vector<Iterator>> pos_cache;
74 };
75
76 template <typename Iterator>
77 void error_handler<Iterator>::print_file_line(std::size_t line) const
78 {
79 if (file != "")
80 {
81 err_out << "In file " << file << ", ";
82 }
83 else
84 {
85 err_out << "In ";
86 }
87
88 err_out << "line " << line << ':' << std::endl;
89 }
90
91 template <typename Iterator>
92 void error_handler<Iterator>::print_line(Iterator start, Iterator last) const
93 {
94 auto end = start;
95 while (end != last)
96 {
97 auto c = *end;
98 if (c == '\r' || c == '\n')
99 break;
100 else
101 ++end;
102 }
103 typedef typename std::iterator_traits<Iterator>::value_type char_type;
104 std::basic_string<char_type> line{start, end};
105 err_out << x3::to_utf8(line) << std::endl;
106 }
107
108 template <typename Iterator>
109 void error_handler<Iterator>::print_indicator(Iterator& start, Iterator last, char ind) const
110 {
111 for (; start != last; ++start)
112 {
113 auto c = *start;
114 if (c == '\r' || c == '\n')
115 break;
116 else if (c == '\t')
117 for (int i = 0; i < tabs; ++i)
118 err_out << ind;
119 else
120 err_out << ind;
121 }
122 }
123
124 template <class Iterator>
125 inline Iterator error_handler<Iterator>::get_line_start(Iterator first, Iterator pos) const
126 {
127 Iterator latest = first;
128 for (Iterator i = first; i != pos;)
129 if (*i == '\r' || *i == '\n')
130 latest = ++i;
131 else
132 ++i;
133 return latest;
134 }
135
136 template <typename Iterator>
137 std::size_t error_handler<Iterator>::position(Iterator i) const
138 {
139 std::size_t line { 1 };
140 typename std::iterator_traits<Iterator>::value_type prev { 0 };
141
142 for (Iterator pos = pos_cache.first(); pos != i; ++pos) {
143 auto c = *pos;
144 switch (c) {
145 case '\n':
146 if (prev != '\r') ++line;
147 break;
148 case '\r':
149 ++line;
150 break;
151 default:
152 break;
153 }
154 prev = c;
155 }
156
157 return line;
158 }
159
160 template <typename Iterator>
161 void error_handler<Iterator>::operator()(
162 Iterator err_pos, std::string const& error_message) const
163 {
164 Iterator first = pos_cache.first();
165 Iterator last = pos_cache.last();
166
167 print_file_line(line: position(i: err_pos));
168 err_out << error_message << std::endl;
169
170 Iterator start = get_line_start(first, pos: err_pos);
171 print_line(start, last);
172 print_indicator(start, last: err_pos, ind: '_');
173 err_out << "^_" << std::endl;
174 }
175
176 template <typename Iterator>
177 void error_handler<Iterator>::operator()(
178 Iterator err_first, Iterator err_last, std::string const& error_message) const
179 {
180 Iterator first = pos_cache.first();
181 Iterator last = pos_cache.last();
182
183 print_file_line(line: position(i: err_first));
184 err_out << error_message << std::endl;
185
186 Iterator start = get_line_start(first, pos: err_first);
187 print_line(start, last);
188 print_indicator(start, last: err_first, ind: ' ');
189 print_indicator(start, last: err_last, ind: '~');
190 err_out << " <<-- Here" << std::endl;
191 }
192
193}}}
194
195#endif
196

source code of boost/libs/spirit/include/boost/spirit/home/x3/support/utility/error_reporting.hpp