1 /*
2     This file is part of GNU APL, a free implementation of the
3     ISO/IEC Standard 13751, "Programming Language APL, Extended"
4 
5     Copyright (C) 2008-2019  Dr. Jürgen Sauermann
6 
7     This program is free software: you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #ifndef __ERROR_HH_DEFINED__
22 #define __ERROR_HH_DEFINED__
23 
24 #include "Backtrace.hh"
25 #include "Common.hh"
26 #include "ErrorCode.hh"
27 #include "UCS_string.hh"
28 #include <cstring>
29 #ifdef __GNUC__
30     #define GNUC__noreturn __attribute__ ((noreturn))
31 #else
32     #define GNUC__noreturn
33 #endif
34 
35 class StateIndicator;
36 
37 /**
38  ** The exception that is thrown when errors occur.
39  ** The primary item is the error_code; the other items are only valid if
40  ** error_code != NO_ERROR
41  **/
42 /// An APL error and information related to it
43 class Error
44 {
45 public:
46    /// constructor: error with error code ec
47    Error(ErrorCode ec, const char * loc);
48 
49    /// return true iff error_code is known (as opposed to an arbitrary
50    /// error code constructed by ⎕ES)
51    bool is_known() const;
52 
53    /// return true iff error_code is some SYNTAX ERROR or VALUE ERROR
54    bool is_syntax_or_value_error() const;
55 
56    /// return the error code of \b this error
get_error_code() const57    const ErrorCode get_error_code() const
58       { return error_code; }
59 
60    /// return ⎕EM[1;]. This is the first of 3 error lines. It contains the
61    /// error name (like SYNTAX ERROR, DOMAIN ERROR, etc) and is subject
62    /// to translation
get_error_line_1() const63    const char * get_error_line_1() const
64       { return error_message_1; }
65 
66    /// clear error line 1
clear_error_line_1()67    void clear_error_line_1()
68       { *error_message_1 = 0; }
69 
70    /// return error_message_2. This is the second of 3 error lines.
71    /// It contains the failed statement and is NOT subject to translation.
get_error_line_2() const72    const char * get_error_line_2() const
73       { return error_message_2; }
74 
75    /// return the major class (⎕ET) of the error
error_major(ErrorCode err)76    static int error_major(ErrorCode err)
77       { return err >> 16; }
78 
79    /// return the category (⎕ET) of the error
error_minor(ErrorCode err)80    static int error_minor(ErrorCode err)
81       { return err & 0xFFFF; }
82 
83    /// return source file location where this error was printed (0 if not)
get_print_loc() const84    const char * get_print_loc() const
85       { return print_loc; }
86 
87    /// compute the caret line. This is the third of the 3 error lines.
88    /// It contains the failure position the statement and is NOT subject
89    /// to translation.
90    UCS_string get_error_line_3() const;
91 
92    /// return the source code location where the error was thrown
get_throw_loc() const93    const char * get_throw_loc() const
94       { return throw_loc; }
95 
96    /// return the left caret (^) position in the third error line
get_left_caret() const97    int get_left_caret() const
98       { return left_caret; }
99 
100    /// return the right caret (^) position in the third error line
get_right_caret() const101    int get_right_caret() const
102       { return right_caret; }
103 
104    /// return the show_locked flag
get_show_locked() const105    bool get_show_locked() const
106       { return show_locked; }
107 
108    /// print the error and its related information
109    void print(ostream & out, const char * loc) const;
110 
111    /// set the first error line
set_error_line_1(const char * msg_1)112    void set_error_line_1(const char * msg_1)
113       { strncpy(error_message_1, msg_1, sizeof(error_message_1) - 1);
114         error_message_1[sizeof(error_message_1) - 1] = 0; }
115 
116    /// set the second error line
set_error_line_2(const char * msg_2)117    void set_error_line_2(const char * msg_2)
118       { strncpy(error_message_2, msg_2, sizeof(error_message_2) - 1);
119         error_message_2[sizeof(error_message_2) - 1] = 0; }
120 
121    /// set error line 2, left caret, and right caret
122    void set_error_line_2(const UCS_string & ucs, int lcaret, int rcaret);
123 
124    /// print the 3 error message lines as per ⎕EM
125    void print_em(ostream & out, const char * loc);
126 
127    /// set the error code
clear_error_code()128    void clear_error_code()
129       { error_code = E_NO_ERROR; }
130 
131    /// set the show_locked flag
set_show_locked(bool on)132    void set_show_locked(bool on)
133       { show_locked = on; }
134 
135    /// set the left caret (^) position in the third error line
set_left_caret(int col)136    void set_left_caret(int col)
137       { left_caret = col; }
138 
139    /// set the right caret (^) position in the third error line
set_right_caret(int col)140    void set_right_caret(int col)
141       { right_caret = col; }
142 
143    /// set the source code line where a parse error was thrown
set_parser_loc(const char * loc)144    void set_parser_loc(const char * loc)
145       { parser_loc = loc; }
146 
147    /// update error information in \b this and copy it to si
148    void update_error_info(StateIndicator * si);
149 
150    /// throw an Error related to \b Symbol \b symbol
151    static void throw_symbol_error(const UCS_string & symbol,
152                                   const char * loc) GNUC__noreturn;
153 
154    /// throw a error with a parser location
155    static void throw_parse_error(ErrorCode code, const char * par_loc,
156                                  const char * loc) GNUC__noreturn;
157 
158    /// throw a DEFN ERROR for function \b fun
159    static void throw_define_error(const UCS_string & fun,
160                                   const UCS_string & cmd,
161                                   const char * loc) GNUC__noreturn;
162 
163    /// return a string describing the error
164    static const char * error_name(ErrorCode err);
165 
166 protected:
167    /// the error code
168    ErrorCode error_code;
169 
170    /// the mandatory source file location where the error was thrown
171    const char * throw_loc;
172 
173    /// an optional symbol related to (i.e. triggering) the error
174    char symbol_name[60];
175 
176    /// an optional source file location (for parse errors)
177    const char * parser_loc;
178 
179    /// an optional error text. this text is provided for non-APL errors,
180    // for example in ⎕ES
181    char error_message_1[60];
182 
183    /// second line of error message (only valid if error_code != _NO_ERROR)
184    char error_message_2[60];
185 
186    /// display user function and line rather than ⎕ES instruction
187    bool show_locked;
188 
189    /// the left caret position (-1 if none) for the error display
190    int left_caret;
191 
192    /// the right caret position (-1 if none) for the error display
193    int right_caret;
194 
195    /// where this error was printed (0 if not)
196    const char * print_loc;
197 
198 private:
199    /// constructor (not implemented): prevent construction without error code
200    Error();
201 };
202 #endif // __ERROR_HH_DEFINED__
203