/src/muparser/src/muParserError.cpp
Line | Count | Source |
1 | | /* |
2 | | |
3 | | _____ __ _____________ _______ ______ ___________ |
4 | | / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ |
5 | | | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |
6 | | |__|_| /____/| __(____ /__| /____ >\___ >__| |
7 | | \/ |__| \/ \/ \/ |
8 | | Copyright (C) 2026 Ingo Berg |
9 | | |
10 | | Redistribution and use in source and binary forms, with or without modification, are permitted |
11 | | provided that the following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above copyright notice, this list of |
14 | | conditions and the following disclaimer. |
15 | | * Redistributions in binary form must reproduce the above copyright notice, this list of |
16 | | conditions and the following disclaimer in the documentation and/or other materials provided |
17 | | with the distribution. |
18 | | |
19 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR |
20 | | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
22 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
25 | | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
26 | | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | | */ |
28 | | |
29 | | #include "muParserError.h" |
30 | | #include <exception> |
31 | | |
32 | | #if defined(_MSC_VER) |
33 | | #pragma warning(push) |
34 | | #pragma warning(disable : 26812) // MSVC wants to force me te use enum classes or bother me with pointless warnings |
35 | | #endif |
36 | | |
37 | | namespace mu |
38 | | { |
39 | | //------------------------------------------------------------------------------ |
40 | | const ParserErrorMsg& ParserErrorMsg::Instance() |
41 | 20.4k | { |
42 | 20.4k | static const ParserErrorMsg instance; |
43 | 20.4k | return instance; |
44 | 20.4k | } |
45 | | |
46 | | //------------------------------------------------------------------------------ |
47 | | string_type ParserErrorMsg::operator[](unsigned a_iIdx) const |
48 | 13.9k | { |
49 | 13.9k | return (a_iIdx < m_vErrMsg.size()) ? m_vErrMsg[a_iIdx] : string_type(); |
50 | 13.9k | } |
51 | | |
52 | | //--------------------------------------------------------------------------- |
53 | | ParserErrorMsg::ParserErrorMsg() |
54 | 2 | :m_vErrMsg(0) |
55 | 2 | { |
56 | 2 | m_vErrMsg.resize(ecCOUNT); |
57 | | |
58 | 2 | m_vErrMsg[ecUNASSIGNABLE_TOKEN] = _T("Unexpected token \"$TOK$\" found at position $POS$."); |
59 | 2 | m_vErrMsg[ecINTERNAL_ERROR] = _T("Internal error"); |
60 | 2 | m_vErrMsg[ecINVALID_NAME] = _T("Invalid function-, variable- or constant name: \"$TOK$\"."); |
61 | 2 | m_vErrMsg[ecINVALID_BINOP_IDENT] = _T("Invalid binary operator identifier: \"$TOK$\"."); |
62 | 2 | m_vErrMsg[ecINVALID_INFIX_IDENT] = _T("Invalid infix operator identifier: \"$TOK$\"."); |
63 | 2 | m_vErrMsg[ecINVALID_POSTFIX_IDENT] = _T("Invalid postfix operator identifier: \"$TOK$\"."); |
64 | 2 | m_vErrMsg[ecINVALID_FUN_PTR] = _T("Invalid pointer to callback function."); |
65 | 2 | m_vErrMsg[ecEMPTY_EXPRESSION] = _T("Expression is empty."); |
66 | 2 | m_vErrMsg[ecINVALID_VAR_PTR] = _T("Invalid pointer to variable."); |
67 | 2 | m_vErrMsg[ecUNEXPECTED_OPERATOR] = _T("Unexpected operator \"$TOK$\" found at position $POS$"); |
68 | 2 | m_vErrMsg[ecUNEXPECTED_EOF] = _T("Unexpected end of expression at position $POS$"); |
69 | 2 | m_vErrMsg[ecUNEXPECTED_ARG_SEP] = _T("Unexpected argument separator at position $POS$"); |
70 | 2 | m_vErrMsg[ecUNEXPECTED_PARENS] = _T("Unexpected parenthesis \"$TOK$\" at position $POS$"); |
71 | 2 | m_vErrMsg[ecUNEXPECTED_FUN] = _T("Unexpected function \"$TOK$\" at position $POS$"); |
72 | 2 | m_vErrMsg[ecUNEXPECTED_VAL] = _T("Unexpected value \"$TOK$\" found at position $POS$"); |
73 | 2 | m_vErrMsg[ecUNEXPECTED_VAR] = _T("Unexpected variable \"$TOK$\" found at position $POS$"); |
74 | 2 | m_vErrMsg[ecUNEXPECTED_ARG] = _T("Function arguments used without a function (position: $POS$)"); |
75 | 2 | m_vErrMsg[ecMISSING_PARENS] = _T("Missing parenthesis"); |
76 | 2 | m_vErrMsg[ecTOO_MANY_PARAMS] = _T("Too many parameters for function \"$TOK$\" at expression position $POS$"); |
77 | 2 | m_vErrMsg[ecTOO_FEW_PARAMS] = _T("Too few parameters for function \"$TOK$\" at expression position $POS$"); |
78 | 2 | m_vErrMsg[ecDIV_BY_ZERO] = _T("Divide by zero"); |
79 | 2 | m_vErrMsg[ecDOMAIN_ERROR] = _T("Domain error"); |
80 | 2 | m_vErrMsg[ecNAME_CONFLICT] = _T("Name conflict"); |
81 | 2 | m_vErrMsg[ecOPT_PRI] = _T("Invalid value for operator priority (must be greater or equal to zero)."); |
82 | 2 | m_vErrMsg[ecBUILTIN_OVERLOAD] = _T("user defined binary operator \"$TOK$\" conflicts with a built in operator."); |
83 | 2 | m_vErrMsg[ecUNEXPECTED_STR] = _T("Unexpected string token found at position $POS$."); |
84 | 2 | m_vErrMsg[ecUNTERMINATED_STRING] = _T("Unterminated string starting at position $POS$."); |
85 | 2 | m_vErrMsg[ecSTRING_EXPECTED] = _T("String function called with a non string type of argument."); |
86 | 2 | m_vErrMsg[ecVAL_EXPECTED] = _T("String value used where a numerical argument is expected."); |
87 | 2 | m_vErrMsg[ecOPRT_TYPE_CONFLICT] = _T("No suitable overload for operator \"$TOK$\" at position $POS$."); |
88 | 2 | m_vErrMsg[ecSTR_RESULT] = _T("Strings must only be used as function arguments!"); |
89 | 2 | m_vErrMsg[ecGENERIC] = _T("Parser error."); |
90 | 2 | m_vErrMsg[ecLOCALE] = _T("Decimal separator is identic to function argument separator."); |
91 | 2 | m_vErrMsg[ecUNEXPECTED_CONDITIONAL] = _T("The \"$TOK$\" operator must be preceded by a closing bracket."); |
92 | 2 | m_vErrMsg[ecMISSING_ELSE_CLAUSE] = _T("If-then-else operator is missing an else clause"); |
93 | 2 | m_vErrMsg[ecMISPLACED_COLON] = _T("Misplaced colon at position $POS$"); |
94 | 2 | m_vErrMsg[ecUNREASONABLE_NUMBER_OF_COMPUTATIONS] = _T("Number of computations to small for bulk mode. (Vectorisation overhead too costly)"); |
95 | 2 | m_vErrMsg[ecIDENTIFIER_TOO_LONG] = _T("Identifier too long."); |
96 | 2 | m_vErrMsg[ecEXPRESSION_TOO_LONG] = _T("Expression too long."); |
97 | 2 | m_vErrMsg[ecINVALID_CHARACTERS_FOUND] = _T("Invalid non printable characters found in expression/identifer!"); |
98 | 2 | m_vErrMsg[ecBYTECODE_IMPORT_EXPORT_DISABLED] = _T("Bytecode cannot be imported or exported when parser is using a variable factory!"); |
99 | 2 | m_vErrMsg[ecUNARY_PLUS_IN_FRONT_OF_FUNCTION] = _T("Unary plus operator is not allowed in front of functions!"); |
100 | 2 | m_vErrMsg[ecNESTING_LIMIT] = _T("Expression too complex. Nesting limit reached!"); |
101 | | |
102 | 88 | for (int i = 0; i < ecCOUNT; ++i) |
103 | 86 | { |
104 | 86 | if (!m_vErrMsg[i].length()) |
105 | 0 | throw std::runtime_error("Error definitions are incomplete!"); |
106 | 86 | } |
107 | 2 | } |
108 | | |
109 | | //--------------------------------------------------------------------------- |
110 | | // |
111 | | // ParserError class |
112 | | // |
113 | | //--------------------------------------------------------------------------- |
114 | | |
115 | | /** \brief Default constructor. */ |
116 | | ParserError::ParserError() |
117 | 6.56k | :m_strMsg() |
118 | 6.56k | , m_strFormula() |
119 | 6.56k | , m_strTok() |
120 | 6.56k | , m_iPos(-1) |
121 | 6.56k | , m_iErrc(ecUNDEFINED) |
122 | 6.56k | , m_ErrMsg(ParserErrorMsg::Instance()) |
123 | 6.56k | { |
124 | 6.56k | } |
125 | | |
126 | | //------------------------------------------------------------------------------ |
127 | | /** \brief This Constructor is used for internal exceptions only. |
128 | | |
129 | | It does not contain any information but the error code. |
130 | | */ |
131 | | ParserError::ParserError(EErrorCodes a_iErrc) |
132 | 226 | :m_strMsg() |
133 | 226 | , m_strFormula() |
134 | 226 | , m_strTok() |
135 | 226 | , m_iPos(-1) |
136 | 226 | , m_iErrc(a_iErrc) |
137 | 226 | , m_ErrMsg(ParserErrorMsg::Instance()) |
138 | 226 | { |
139 | 226 | m_strMsg = m_ErrMsg[m_iErrc]; |
140 | 226 | stringstream_type stream; |
141 | 226 | stream << (int)m_iPos; |
142 | 226 | ReplaceSubString(m_strMsg, _T("$POS$"), stream.str()); |
143 | 226 | ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok); |
144 | 226 | } |
145 | | |
146 | | //------------------------------------------------------------------------------ |
147 | | /** \brief Construct an error from a message text. */ |
148 | | ParserError::ParserError(const string_type& sMsg) |
149 | 0 | :m_ErrMsg(ParserErrorMsg::Instance()) |
150 | 0 | { |
151 | 0 | Reset(); |
152 | 0 | m_strMsg = sMsg; |
153 | 0 | } |
154 | | |
155 | | //------------------------------------------------------------------------------ |
156 | | /** \brief Construct an error object. |
157 | | \param [in] a_iErrc the error code. |
158 | | \param [in] sTok The token string related to this error. |
159 | | \param [in] sExpr The expression related to the error. |
160 | | \param [in] a_iPos the position in the expression where the error occurred. |
161 | | */ |
162 | | ParserError::ParserError(EErrorCodes iErrc, |
163 | | const string_type& sTok, |
164 | | const string_type& sExpr, |
165 | | int iPos) |
166 | 13.5k | :m_strMsg() |
167 | 13.5k | , m_strFormula(sExpr) |
168 | 13.5k | , m_strTok(sTok) |
169 | 13.5k | , m_iPos(iPos) |
170 | 13.5k | , m_iErrc(iErrc) |
171 | 13.5k | , m_ErrMsg(ParserErrorMsg::Instance()) |
172 | 13.5k | { |
173 | 13.5k | m_strMsg = m_ErrMsg[m_iErrc]; |
174 | 13.5k | stringstream_type stream; |
175 | 13.5k | stream << (int)m_iPos; |
176 | 13.5k | ReplaceSubString(m_strMsg, _T("$POS$"), stream.str()); |
177 | 13.5k | ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok); |
178 | 13.5k | } |
179 | | |
180 | | //------------------------------------------------------------------------------ |
181 | | /** \brief Construct an error object. |
182 | | \param [in] iErrc the error code. |
183 | | \param [in] iPos the position in the expression where the error occurred. |
184 | | \param [in] sTok The token string related to this error. |
185 | | */ |
186 | | ParserError::ParserError(EErrorCodes iErrc, int iPos, const string_type& sTok) |
187 | 92 | :m_strMsg() |
188 | 92 | , m_strFormula() |
189 | 92 | , m_strTok(sTok) |
190 | 92 | , m_iPos(iPos) |
191 | 92 | , m_iErrc(iErrc) |
192 | 92 | , m_ErrMsg(ParserErrorMsg::Instance()) |
193 | 92 | { |
194 | 92 | m_strMsg = m_ErrMsg[m_iErrc]; |
195 | 92 | stringstream_type stream; |
196 | 92 | stream << (int)m_iPos; |
197 | 92 | ReplaceSubString(m_strMsg, _T("$POS$"), stream.str()); |
198 | 92 | ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok); |
199 | 92 | } |
200 | | |
201 | | //------------------------------------------------------------------------------ |
202 | | /** \brief Construct an error object. |
203 | | \param [in] szMsg The error message text. |
204 | | \param [in] iPos the position related to the error. |
205 | | \param [in] sTok The token string related to this error. |
206 | | */ |
207 | | ParserError::ParserError(const char_type* szMsg, int iPos, const string_type& sTok) |
208 | 5 | :m_strMsg(szMsg) |
209 | 5 | , m_strFormula() |
210 | 5 | , m_strTok(sTok) |
211 | 5 | , m_iPos(iPos) |
212 | 5 | , m_iErrc(ecGENERIC) |
213 | 5 | , m_ErrMsg(ParserErrorMsg::Instance()) |
214 | 5 | { |
215 | 5 | stringstream_type stream; |
216 | 5 | stream << (int)m_iPos; |
217 | 5 | ReplaceSubString(m_strMsg, _T("$POS$"), stream.str()); |
218 | 5 | ReplaceSubString(m_strMsg, _T("$TOK$"), m_strTok); |
219 | 5 | } |
220 | | |
221 | | //------------------------------------------------------------------------------ |
222 | | /** \brief Copy constructor. */ |
223 | | ParserError::ParserError(const ParserError& a_Obj) |
224 | 0 | :m_strMsg(a_Obj.m_strMsg) |
225 | 0 | , m_strFormula(a_Obj.m_strFormula) |
226 | 0 | , m_strTok(a_Obj.m_strTok) |
227 | 0 | , m_iPos(a_Obj.m_iPos) |
228 | 0 | , m_iErrc(a_Obj.m_iErrc) |
229 | 0 | , m_ErrMsg(ParserErrorMsg::Instance()) |
230 | 0 | { |
231 | 0 | } |
232 | | |
233 | | //------------------------------------------------------------------------------ |
234 | | /** \brief Assignment operator. */ |
235 | | ParserError& ParserError::operator=(const ParserError& a_Obj) |
236 | 11.7k | { |
237 | 11.7k | if (this == &a_Obj) |
238 | 0 | return *this; |
239 | | |
240 | 11.7k | m_strMsg = a_Obj.m_strMsg; |
241 | 11.7k | m_strFormula = a_Obj.m_strFormula; |
242 | 11.7k | m_strTok = a_Obj.m_strTok; |
243 | 11.7k | m_iPos = a_Obj.m_iPos; |
244 | 11.7k | m_iErrc = a_Obj.m_iErrc; |
245 | 11.7k | return *this; |
246 | 11.7k | } |
247 | | |
248 | | //------------------------------------------------------------------------------ |
249 | | ParserError::~ParserError() |
250 | 20.4k | {} |
251 | | |
252 | | //------------------------------------------------------------------------------ |
253 | | /** \brief Replace all occurrences of a substring with another string. |
254 | | \param strFind The string that shall be replaced. |
255 | | \param strReplaceWith The string that should be inserted instead of strFind |
256 | | */ |
257 | | void ParserError::ReplaceSubString(string_type& strSource, |
258 | | const string_type& strFind, |
259 | | const string_type& strReplaceWith) |
260 | 27.8k | { |
261 | 27.8k | string_type strResult; |
262 | 27.8k | string_type::size_type iPos(0), iNext(0); |
263 | | |
264 | 27.8k | for (;;) |
265 | 42.0k | { |
266 | 42.0k | iNext = strSource.find(strFind, iPos); |
267 | 42.0k | strResult.append(strSource, iPos, iNext - iPos); |
268 | | |
269 | 42.0k | if (iNext == string_type::npos) |
270 | 27.8k | break; |
271 | | |
272 | 14.2k | strResult.append(strReplaceWith); |
273 | 14.2k | iPos = iNext + strFind.length(); |
274 | 14.2k | } |
275 | | |
276 | 27.8k | strSource.swap(strResult); |
277 | 27.8k | } |
278 | | |
279 | | //------------------------------------------------------------------------------ |
280 | | /** \brief Reset the error object. */ |
281 | | void ParserError::Reset() |
282 | 0 | { |
283 | 0 | m_strMsg = _T(""); |
284 | 0 | m_strFormula = _T(""); |
285 | 0 | m_strTok = _T(""); |
286 | 0 | m_iPos = -1; |
287 | 0 | m_iErrc = ecUNDEFINED; |
288 | 0 | } |
289 | | |
290 | | //------------------------------------------------------------------------------ |
291 | | /** \brief Set the expression related to this error. */ |
292 | | void ParserError::SetFormula(const string_type& a_strFormula) |
293 | 3.58k | { |
294 | 3.58k | m_strFormula = a_strFormula; |
295 | 3.58k | } |
296 | | |
297 | | //------------------------------------------------------------------------------ |
298 | | /** \brief gets the expression related tp this error.*/ |
299 | | const string_type& ParserError::GetExpr() const |
300 | 0 | { |
301 | 0 | return m_strFormula; |
302 | 0 | } |
303 | | |
304 | | //------------------------------------------------------------------------------ |
305 | | /** \brief Returns the message string for this error. */ |
306 | | const string_type& ParserError::GetMsg() const |
307 | 1.88k | { |
308 | 1.88k | return m_strMsg; |
309 | 1.88k | } |
310 | | |
311 | | //------------------------------------------------------------------------------ |
312 | | /** \brief Return the formula position related to the error. |
313 | | |
314 | | If the error is not related to a distinct position this will return -1 |
315 | | */ |
316 | | int ParserError::GetPos() const |
317 | 1.88k | { |
318 | 1.88k | return m_iPos; |
319 | 1.88k | } |
320 | | |
321 | | //------------------------------------------------------------------------------ |
322 | | /** \brief Return string related with this token (if available). */ |
323 | | const string_type& ParserError::GetToken() const |
324 | 1.88k | { |
325 | 1.88k | return m_strTok; |
326 | 1.88k | } |
327 | | |
328 | | //------------------------------------------------------------------------------ |
329 | | /** \brief Return the error code. */ |
330 | | EErrorCodes ParserError::GetCode() const |
331 | 1.88k | { |
332 | 1.88k | return m_iErrc; |
333 | 1.88k | } |
334 | | } // namespace mu |
335 | | |
336 | | #if defined(_MSC_VER) |
337 | | #pragma warning(pop) |
338 | | #endif |