Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief an error listener reacting to mismatches of the grammar defined in `YAML.g4`
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : // -- Imports ------------------------------------------------------------------
10 :
11 : #include <iostream>
12 :
13 : #include <kdbmacros.h>
14 :
15 : #include "error_listener.hpp"
16 :
17 : using std::to_string;
18 :
19 : using antlr4::CommonTokenStream;
20 :
21 : // -- Functions ----------------------------------------------------------------
22 :
23 : namespace
24 : {
25 :
26 : using std::string;
27 :
28 : using antlr4::Recognizer;
29 : using antlr4::Token;
30 :
31 : /**
32 : * @brief This function returns a Clang-like error message for a given error.
33 : *
34 : * @param recognizer This parameter stores the current recognizer used to
35 : * parse the input.
36 : * @param offendingSymbol This token caused the failure of the parsing
37 : * process.
38 : * @param line This number specifies the line where the parsing process
39 : * failed.
40 : * @param charPositionInLine This number specifies the character position in
41 : * `line`, where the parsing process failed.
42 : * @param prefix This variable stores as prefix that this function prepends
43 : * to every line of the visualized error message.
44 : *
45 : * @return A string representation of the error
46 : */
47 6 : string visualizeError (Recognizer * recognizer, Token * offendingSymbol, size_t const line, size_t const charPositionInLine,
48 : string const & prefix)
49 : {
50 6 : CommonTokenStream * tokens = dynamic_cast<CommonTokenStream *> (recognizer->getInputStream ());
51 12 : string input = tokens->getTokenSource ()->getInputStream ()->toString ();
52 :
53 : string::size_type start = 0;
54 : string::size_type end = 0;
55 30 : for (size_t currentLine = 1; currentLine <= line; currentLine++)
56 : {
57 12 : size_t offset = (end == 0 ? 0 : 1);
58 12 : start = end + offset;
59 24 : end = input.find ("\n", end + offset);
60 : }
61 :
62 6 : string errorLine = input.substr (start, end - start);
63 :
64 54 : errorLine = prefix + errorLine + "\n" + prefix + string (charPositionInLine - 1, ' ');
65 6 : start = offendingSymbol->getStartIndex ();
66 6 : end = offendingSymbol->getStopIndex ();
67 24 : for (size_t current = start; current <= end; current++)
68 : {
69 9 : errorLine += "^";
70 : }
71 :
72 6 : return errorLine;
73 : }
74 : }
75 :
76 : // -- Class --------------------------------------------------------------------
77 :
78 : namespace yanlr
79 : {
80 :
81 : using antlr4::Recognizer;
82 :
83 : /**
84 : * @brief This constructor creates a new error listener using the given arguments.
85 : *
86 : * @param errorSource This text stores an identifier, usually the filename, that identifies the source of an error.
87 : */
88 124 : ErrorListener::ErrorListener (string const & errorSource)
89 : {
90 62 : source = errorSource;
91 31 : }
92 :
93 : /**
94 : * @brief This method will be called if the parsing process fails.
95 : *
96 : * @param recognizer This parameter stores the current recognizer used to
97 : * parse the input.
98 : * @param offendingSymbol This token caused the failure of the parsing
99 : * process.
100 : * @param line This number specifies the line where the parsing process
101 : * failed.
102 : * @param charPositionInLine This number specifies the character position in
103 : * `line`, where the parsing process failed.
104 : * @param message This text describes the parsing failure.
105 : * @param error This parameter stores the exception caused by the parsing
106 : * failure.
107 : */
108 6 : void ErrorListener::syntaxError (Recognizer * recognizer, Token * offendingSymbol, size_t line, size_t charPositionInLine,
109 : const std::string & message, std::exception_ptr error ELEKTRA_UNUSED)
110 : {
111 54 : auto location = source + ":" + to_string (line) + ":" + to_string (charPositionInLine) + ": ";
112 30 : auto indent = string (location.length (), ' ');
113 30 : errorMessage += "\n" + location + message + "\n";
114 18 : errorMessage += visualizeError (recognizer, offendingSymbol, line, charPositionInLine, indent);
115 6 : }
116 :
117 : /**
118 : * @brief This method returns the last error message saved by the error listener.
119 : *
120 : * @return A string containing an error message produced by the parser
121 : */
122 3 : char const * ErrorListener::message ()
123 : {
124 6 : return errorMessage.c_str ();
125 : }
126 140 : }
|