Coverage Report

Created: 2026-08-13 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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