[muparser] Add a muParser ValueOrError type

First steps towards removing exceptions from muParser.
This commit is contained in:
ridiculousfish 2017-11-18 14:36:14 -08:00
parent c0af4ba70a
commit 5655f255ef
10 changed files with 324 additions and 226 deletions

View file

@ -57,49 +57,49 @@ namespace mu {
virtual void InitOprt();
virtual void OnDetectVar(string_type *pExpr, int &nStart, int &nEnd);
value_type Diff(value_type *a_Var, value_type a_fPos, value_type a_fEpsilon = 0) const;
ValueOrError Diff(value_type *a_Var, value_type a_fPos, value_type a_fEpsilon = 0) const;
protected:
// Trigonometric functions
static value_type Sin(value_type);
static value_type Cos(value_type);
static value_type Tan(value_type);
static value_type Tan2(value_type, value_type);
static ValueOrError Sin(value_type);
static ValueOrError Cos(value_type);
static ValueOrError Tan(value_type);
static ValueOrError Tan2(value_type, value_type);
// arcus functions
static value_type ASin(value_type);
static value_type ACos(value_type);
static value_type ATan(value_type);
static value_type ATan2(value_type, value_type);
static ValueOrError ASin(value_type);
static ValueOrError ACos(value_type);
static ValueOrError ATan(value_type);
static ValueOrError ATan2(value_type, value_type);
// hyperbolic functions
static value_type Sinh(value_type);
static value_type Cosh(value_type);
static value_type Tanh(value_type);
static ValueOrError Sinh(value_type);
static ValueOrError Cosh(value_type);
static ValueOrError Tanh(value_type);
// arcus hyperbolic functions
static value_type ASinh(value_type);
static value_type ACosh(value_type);
static value_type ATanh(value_type);
static ValueOrError ASinh(value_type);
static ValueOrError ACosh(value_type);
static ValueOrError ATanh(value_type);
// Logarithm functions
static value_type Log2(value_type); // Logarithm Base 2
static value_type Log10(value_type); // Logarithm Base 10
static value_type Ln(value_type); // Logarithm Base e (natural logarithm)
static ValueOrError Log2(value_type); // Logarithm Base 2
static ValueOrError Log10(value_type); // Logarithm Base 10
static ValueOrError Ln(value_type); // Logarithm Base e (natural logarithm)
// misc
static value_type Exp(value_type);
static value_type Abs(value_type);
static value_type Sqrt(value_type);
static value_type Rint(value_type);
static value_type Sign(value_type);
static ValueOrError Exp(value_type);
static ValueOrError Abs(value_type);
static ValueOrError Sqrt(value_type);
static ValueOrError Rint(value_type);
static ValueOrError Sign(value_type);
// Prefix operators
// !!! Unary Minus is a MUST if you want to use negative signs !!!
static value_type UnaryMinus(value_type);
static value_type UnaryPlus(value_type);
static ValueOrError UnaryMinus(value_type);
static ValueOrError UnaryPlus(value_type);
// Functions with variable number of arguments
static value_type Sum(const value_type *, int); // sum
static value_type Avg(const value_type *, int); // mean value
static value_type Min(const value_type *, int); // minimum
static value_type Max(const value_type *, int); // maximum
static ValueOrError Sum(const value_type *, int); // sum
static ValueOrError Avg(const value_type *, int); // mean value
static ValueOrError Min(const value_type *, int); // minimum
static ValueOrError Max(const value_type *, int); // maximum
static int IsVal(const char_type *a_szExpr, int *a_iPos, value_type *a_fVal);
};

View file

@ -55,28 +55,29 @@ typedef wchar_t muChar_t; // character type
typedef int muBool_t; // boolean type
typedef int muInt_t; // integer type
typedef double muFloat_t; // floating point type
using mu::ValueOrError;
// function types for calculation
typedef muFloat_t (*muFun0_t)();
typedef muFloat_t (*muFun1_t)(muFloat_t);
typedef muFloat_t (*muFun2_t)(muFloat_t, muFloat_t);
typedef muFloat_t (*muFun3_t)(muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun4_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun5_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun6_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun7_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t,
muFloat_t);
typedef muFloat_t (*muFun8_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t,
muFloat_t, muFloat_t);
typedef muFloat_t (*muFun9_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t,
muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muFun10_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t,
muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef ValueOrError (*muFun0_t)();
typedef ValueOrError (*muFun1_t)(muFloat_t);
typedef ValueOrError (*muFun2_t)(muFloat_t, muFloat_t);
typedef ValueOrError (*muFun3_t)(muFloat_t, muFloat_t, muFloat_t);
typedef ValueOrError (*muFun4_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef ValueOrError (*muFun5_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef ValueOrError (*muFun6_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef ValueOrError (*muFun7_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t,
muFloat_t);
typedef ValueOrError (*muFun8_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t,
muFloat_t, muFloat_t);
typedef ValueOrError (*muFun9_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t,
muFloat_t, muFloat_t, muFloat_t);
typedef ValueOrError (*muFun10_t)(muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t, muFloat_t,
muFloat_t, muFloat_t, muFloat_t, muFloat_t);
typedef muFloat_t (*muMultFun_t)(const muFloat_t *, muInt_t);
typedef muFloat_t (*muStrFun1_t)(const muChar_t *);
typedef muFloat_t (*muStrFun2_t)(const muChar_t *, muFloat_t);
typedef muFloat_t (*muStrFun3_t)(const muChar_t *, muFloat_t, muFloat_t);
typedef ValueOrError (*muMultFun_t)(const muFloat_t *, muInt_t);
typedef ValueOrError (*muStrFun1_t)(const muChar_t *);
typedef ValueOrError (*muStrFun2_t)(const muChar_t *, muFloat_t);
typedef ValueOrError (*muStrFun3_t)(const muChar_t *, muFloat_t, muFloat_t);
// Functions for parser management
typedef void (*muErrorHandler_t)(

View file

@ -25,8 +25,10 @@
#ifndef MUP_DEF_H
#define MUP_DEF_H
#include <cassert>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
@ -352,60 +354,137 @@ class ParserError {
EErrorCodes m_iErrc; ///< Error code
};
// Compatibility with non-clang compilers.
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
// Define a type-level attribute declaring that this type, when used as the return value
// of a function, should produce warnings.
#if __has_attribute(warn_unused_result)
#define MUPARSER_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define MUPARSER_ATTR_WARN_UNUSED_RESULT
#endif
// OptionalError is used to optionally encapsulate an error.
class OptionalError {
std::unique_ptr<ParserError> error_{};
public:
/// Create an OptionalError that represents no error.
OptionalError() {}
/// Create an OptionalError for the given error.
/* implicit */ OptionalError(ParserError err) : error_(new ParserError(std::move(err))) {}
/// \return whether an error is present.
bool has_error() const { return bool(error_); }
/// \return the error. asserts if this is not an error.
const ParserError &error() const {
assert(error_ && "Value did not error");
return *error_;
}
} MUPARSER_ATTR_WARN_UNUSED_RESULT;
// ValueOrError is used to propagate failures to callers.
class ValueOrError {
value_type value_{0};
OptionalError error_{};
public:
/// \return true if this has a value, false if it is an error.
bool has_value() const { return !error_.has_error(); }
/// \return false if this has a value,true if it is an error.
bool has_error() const { return error_.has_error(); }
/// Construct from a value.
/* implicit */ ValueOrError(value_type value) : value_(value) {}
/// Construct from an error.
/* implicit */ ValueOrError(ParserError err) : error_(std::move(err)) {}
/// \return the error. asserts if this is not an error.
const ParserError &error() const { return error_.error(); }
/// \return the value. asserts if this is an error.
value_type value() const {
assert(has_value() && "Value is an error");
return value_;
}
/// \return the value or throw the error
value_type getOrThrow() const {
if (has_error()) throw error();
return value();
}
/// \return whether this has a value.
explicit operator bool() const { return has_value(); }
value_type operator*() const {
assert(has_value() && "Cannot access value with error");
return value_;
}
} MUPARSER_ATTR_WARN_UNUSED_RESULT;
// Parser callbacks
/** \brief Callback type used for functions without arguments. */
typedef value_type (*generic_fun_type)();
typedef ValueOrError (*generic_fun_type)();
/** \brief Callback type used for functions without arguments. */
typedef value_type (*fun_type0)();
typedef ValueOrError (*fun_type0)();
/** \brief Callback type used for functions with a single arguments. */
typedef value_type (*fun_type1)(value_type);
typedef ValueOrError (*fun_type1)(value_type);
/** \brief Callback type used for functions with two arguments. */
typedef value_type (*fun_type2)(value_type, value_type);
typedef ValueOrError (*fun_type2)(value_type, value_type);
/** \brief Callback type used for functions with three arguments. */
typedef value_type (*fun_type3)(value_type, value_type, value_type);
typedef ValueOrError (*fun_type3)(value_type, value_type, value_type);
/** \brief Callback type used for functions with four arguments. */
typedef value_type (*fun_type4)(value_type, value_type, value_type, value_type);
typedef ValueOrError (*fun_type4)(value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type5)(value_type, value_type, value_type, value_type, value_type);
typedef ValueOrError (*fun_type5)(value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type6)(value_type, value_type, value_type, value_type, value_type,
value_type);
typedef ValueOrError (*fun_type6)(value_type, value_type, value_type, value_type, value_type,
value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type7)(value_type, value_type, value_type, value_type, value_type,
value_type, value_type);
typedef ValueOrError (*fun_type7)(value_type, value_type, value_type, value_type, value_type,
value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type8)(value_type, value_type, value_type, value_type, value_type,
value_type, value_type, value_type);
typedef ValueOrError (*fun_type8)(value_type, value_type, value_type, value_type, value_type,
value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type9)(value_type, value_type, value_type, value_type, value_type,
value_type, value_type, value_type, value_type);
typedef ValueOrError (*fun_type9)(value_type, value_type, value_type, value_type, value_type,
value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with five arguments. */
typedef value_type (*fun_type10)(value_type, value_type, value_type, value_type, value_type,
value_type, value_type, value_type, value_type, value_type);
typedef ValueOrError (*fun_type10)(value_type, value_type, value_type, value_type, value_type,
value_type, value_type, value_type, value_type, value_type);
/** \brief Callback type used for functions with a variable argument list. */
typedef value_type (*multfun_type)(const value_type *, int);
typedef ValueOrError (*multfun_type)(const value_type *, int);
/** \brief Callback type used for functions taking a string as an argument. */
typedef value_type (*strfun_type1)(const char_type *);
typedef ValueOrError (*strfun_type1)(const char_type *);
/** \brief Callback type used for functions taking a string and a value as arguments. */
typedef value_type (*strfun_type2)(const char_type *, value_type);
typedef ValueOrError (*strfun_type2)(const char_type *, value_type);
/** \brief Callback type used for functions taking a string and two values as arguments. */
typedef value_type (*strfun_type3)(const char_type *, value_type, value_type);
typedef ValueOrError (*strfun_type3)(const char_type *, value_type, value_type);
/** \brief Callback used for functions that identify values in a string. */
typedef int (*identfun_type)(const char_type *sExpr, int *nPos, value_type *fVal);

View file

@ -45,36 +45,36 @@ class ParserInt : public ParserBase {
private:
static int Round(value_type v) { return (int)(v + ((v >= 0) ? 0.5 : -0.5)); };
static value_type Abs(value_type);
static value_type Sign(value_type);
static value_type Ite(value_type, value_type, value_type);
static ValueOrError Abs(value_type);
static ValueOrError Sign(value_type);
static ValueOrError Ite(value_type, value_type, value_type);
// !! The unary Minus is a MUST, otherwise you cant use negative signs !!
static value_type UnaryMinus(value_type);
static ValueOrError UnaryMinus(value_type);
// Functions with variable number of arguments
static value_type Sum(const value_type* a_afArg, int a_iArgc); // sum
static value_type Min(const value_type* a_afArg, int a_iArgc); // minimum
static value_type Max(const value_type* a_afArg, int a_iArgc); // maximum
static ValueOrError Sum(const value_type* a_afArg, int a_iArgc); // sum
static ValueOrError Min(const value_type* a_afArg, int a_iArgc); // minimum
static ValueOrError Max(const value_type* a_afArg, int a_iArgc); // maximum
// binary operator callbacks
static value_type Add(value_type v1, value_type v2);
static value_type Sub(value_type v1, value_type v2);
static value_type Mul(value_type v1, value_type v2);
static value_type Div(value_type v1, value_type v2);
static value_type Mod(value_type v1, value_type v2);
static value_type Pow(value_type v1, value_type v2);
static value_type Shr(value_type v1, value_type v2);
static value_type Shl(value_type v1, value_type v2);
static value_type LogAnd(value_type v1, value_type v2);
static value_type LogOr(value_type v1, value_type v2);
static value_type And(value_type v1, value_type v2);
static value_type Or(value_type v1, value_type v2);
static value_type Xor(value_type v1, value_type v2);
static value_type Less(value_type v1, value_type v2);
static value_type Greater(value_type v1, value_type v2);
static value_type LessEq(value_type v1, value_type v2);
static value_type GreaterEq(value_type v1, value_type v2);
static value_type Equal(value_type v1, value_type v2);
static value_type NotEqual(value_type v1, value_type v2);
static value_type Not(value_type v1);
static ValueOrError Add(value_type v1, value_type v2);
static ValueOrError Sub(value_type v1, value_type v2);
static ValueOrError Mul(value_type v1, value_type v2);
static ValueOrError Div(value_type v1, value_type v2);
static ValueOrError Mod(value_type v1, value_type v2);
static ValueOrError Pow(value_type v1, value_type v2);
static ValueOrError Shr(value_type v1, value_type v2);
static ValueOrError Shl(value_type v1, value_type v2);
static ValueOrError LogAnd(value_type v1, value_type v2);
static ValueOrError LogOr(value_type v1, value_type v2);
static ValueOrError And(value_type v1, value_type v2);
static ValueOrError Or(value_type v1, value_type v2);
static ValueOrError Xor(value_type v1, value_type v2);
static ValueOrError Less(value_type v1, value_type v2);
static ValueOrError Greater(value_type v1, value_type v2);
static ValueOrError LessEq(value_type v1, value_type v2);
static ValueOrError GreaterEq(value_type v1, value_type v2);
static ValueOrError Equal(value_type v1, value_type v2);
static ValueOrError NotEqual(value_type v1, value_type v2);
static ValueOrError Not(value_type v1);
static int IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_iVal);
static int IsBinVal(const char_type* a_szExpr, int* a_iPos, value_type* a_iVal);

View file

@ -50,65 +50,65 @@ class ParserTester // final
static int c_iCount;
// Multiarg callbacks
static value_type f1of1(value_type v) { return v; };
static ValueOrError f1of1(value_type v) { return v; };
static value_type f1of2(value_type v, value_type) { return v; };
static value_type f2of2(value_type, value_type v) { return v; };
static ValueOrError f1of2(value_type v, value_type) { return v; };
static ValueOrError f2of2(value_type, value_type v) { return v; };
static value_type f1of3(value_type v, value_type, value_type) { return v; };
static value_type f2of3(value_type, value_type v, value_type) { return v; };
static value_type f3of3(value_type, value_type, value_type v) { return v; };
static ValueOrError f1of3(value_type v, value_type, value_type) { return v; };
static ValueOrError f2of3(value_type, value_type v, value_type) { return v; };
static ValueOrError f3of3(value_type, value_type, value_type v) { return v; };
static value_type f1of4(value_type v, value_type, value_type, value_type) { return v; }
static value_type f2of4(value_type, value_type v, value_type, value_type) { return v; }
static value_type f3of4(value_type, value_type, value_type v, value_type) { return v; }
static value_type f4of4(value_type, value_type, value_type, value_type v) { return v; }
static ValueOrError f1of4(value_type v, value_type, value_type, value_type) { return v; }
static ValueOrError f2of4(value_type, value_type v, value_type, value_type) { return v; }
static ValueOrError f3of4(value_type, value_type, value_type v, value_type) { return v; }
static ValueOrError f4of4(value_type, value_type, value_type, value_type v) { return v; }
static value_type f1of5(value_type v, value_type, value_type, value_type, value_type) {
static ValueOrError f1of5(value_type v, value_type, value_type, value_type, value_type) {
return v;
}
static value_type f2of5(value_type, value_type v, value_type, value_type, value_type) {
static ValueOrError f2of5(value_type, value_type v, value_type, value_type, value_type) {
return v;
}
static value_type f3of5(value_type, value_type, value_type v, value_type, value_type) {
static ValueOrError f3of5(value_type, value_type, value_type v, value_type, value_type) {
return v;
}
static value_type f4of5(value_type, value_type, value_type, value_type v, value_type) {
static ValueOrError f4of5(value_type, value_type, value_type, value_type v, value_type) {
return v;
}
static value_type f5of5(value_type, value_type, value_type, value_type, value_type v) {
static ValueOrError f5of5(value_type, value_type, value_type, value_type, value_type v) {
return v;
}
static value_type Min(value_type a_fVal1, value_type a_fVal2) {
static ValueOrError Min(value_type a_fVal1, value_type a_fVal2) {
return (a_fVal1 < a_fVal2) ? a_fVal1 : a_fVal2;
}
static value_type Max(value_type a_fVal1, value_type a_fVal2) {
static ValueOrError Max(value_type a_fVal1, value_type a_fVal2) {
return (a_fVal1 > a_fVal2) ? a_fVal1 : a_fVal2;
}
static value_type plus2(value_type v1) { return v1 + 2; }
static value_type times3(value_type v1) { return v1 * 3; }
static value_type sqr(value_type v1) { return v1 * v1; }
static value_type sign(value_type v) { return -v; }
static value_type add(value_type v1, value_type v2) { return v1 + v2; }
static value_type land(value_type v1, value_type v2) { return (int)v1 & (int)v2; }
static ValueOrError plus2(value_type v1) { return v1 + 2; }
static ValueOrError times3(value_type v1) { return v1 * 3; }
static ValueOrError sqr(value_type v1) { return v1 * v1; }
static ValueOrError sign(value_type v) { return -v; }
static ValueOrError add(value_type v1, value_type v2) { return v1 + v2; }
static ValueOrError land(value_type v1, value_type v2) { return (int)v1 & (int)v2; }
static value_type FirstArg(const value_type* a_afArg, int a_iArgc) {
static ValueOrError FirstArg(const value_type* a_afArg, int a_iArgc) {
if (!a_iArgc)
throw mu::Parser::exception_type(_T("too few arguments for function FirstArg."));
return a_afArg[0];
}
static value_type LastArg(const value_type* a_afArg, int a_iArgc) {
static ValueOrError LastArg(const value_type* a_afArg, int a_iArgc) {
if (!a_iArgc)
throw mu::Parser::exception_type(_T("too few arguments for function LastArg."));
return a_afArg[a_iArgc - 1];
}
static value_type Sum(const value_type* a_afArg, int a_iArgc) {
static ValueOrError Sum(const value_type* a_afArg, int a_iArgc) {
if (!a_iArgc) throw mu::Parser::exception_type(_T("too few arguments for function sum."));
value_type fRes = 0;
@ -116,46 +116,46 @@ class ParserTester // final
return fRes;
}
static value_type Rnd(value_type v) {
static ValueOrError Rnd(value_type v) {
return (value_type)(1 + (v * std::rand() / (RAND_MAX + 1.0)));
}
static value_type RndWithString(const char_type*) {
static ValueOrError RndWithString(const char_type*) {
return (value_type)(1 + (1000.0f * std::rand() / (RAND_MAX + 1.0)));
}
static value_type Ping() { return 10; }
static ValueOrError Ping() { return 10; }
static value_type ValueOf(const char_type*) { return 123; }
static ValueOrError ValueOf(const char_type*) { return 123; }
static value_type StrFun1(const char_type* v1) {
static ValueOrError StrFun1(const char_type* v1) {
int val(0);
stringstream_type(v1) >> val;
return (value_type)val;
}
static value_type StrFun2(const char_type* v1, value_type v2) {
static ValueOrError StrFun2(const char_type* v1, value_type v2) {
int val(0);
stringstream_type(v1) >> val;
return (value_type)(val + v2);
}
static value_type StrFun3(const char_type* v1, value_type v2, value_type v3) {
static ValueOrError StrFun3(const char_type* v1, value_type v2, value_type v3) {
int val(0);
stringstream_type(v1) >> val;
return val + v2 + v3;
}
static value_type StrToFloat(const char_type* a_szMsg) {
static ValueOrError StrToFloat(const char_type* a_szMsg) {
value_type val(0);
stringstream_type(a_szMsg) >> val;
return val;
}
// postfix operator callback
static value_type Mega(value_type a_fVal) { return a_fVal * (value_type)1e6; }
static value_type Micro(value_type a_fVal) { return a_fVal * (value_type)1e-6; }
static value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
static ValueOrError Mega(value_type a_fVal) { return a_fVal * (value_type)1e6; }
static ValueOrError Micro(value_type a_fVal) { return a_fVal * (value_type)1e-6; }
static ValueOrError Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
// Custom value recognition
static int IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal);

View file

@ -56,39 +56,40 @@ struct DumpLeaks {
#endif
// Operator callback functions
value_type Mega(value_type a_fVal) { return a_fVal * 1e6; }
value_type Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
value_type Rnd(value_type v) { return v * std::rand() / (value_type)(RAND_MAX + 1.0); }
value_type Not(value_type v) { return v == 0; }
value_type Add(value_type v1, value_type v2) { return v1 + v2; }
value_type Mul(value_type v1, value_type v2) { return v1 * v2; }
ValueOrError Mega(value_type a_fVal) { return a_fVal * 1e6; }
ValueOrError Milli(value_type a_fVal) { return a_fVal / (value_type)1e3; }
ValueOrError Rnd(value_type v) { return v * std::rand() / (value_type)(RAND_MAX + 1.0); }
ValueOrError Not(value_type v) { return v == 0; }
ValueOrError Add(value_type v1, value_type v2) { return v1 + v2; }
ValueOrError Mul(value_type v1, value_type v2) { return v1 * v2; }
//---------------------------------------------------------------------------
value_type ThrowAnException(value_type) {
ValueOrError ThrowAnException(value_type) {
throw std::runtime_error("This function does throw an exception.");
}
//---------------------------------------------------------------------------
value_type Ping() {
//---------------------------------------------------------------------------
ValueOrError Ping() {
mu::console() << "ping\n";
return 0;
}
//---------------------------------------------------------------------------
value_type StrFun0(const char_type *szMsg) {
ValueOrError StrFun0(const char_type *szMsg) {
if (szMsg) mu::console() << szMsg << std::endl;
return 999;
}
//---------------------------------------------------------------------------
value_type StrFun2(const char_type *v1, value_type v2, value_type v3) {
ValueOrError StrFun2(const char_type *v1, value_type v2, value_type v3) {
mu::console() << v1 << std::endl;
return v2 + v3;
}
//---------------------------------------------------------------------------
value_type Debug(mu::value_type v1, mu::value_type v2) {
ValueOrError Debug(mu::value_type v1, mu::value_type v2) {
ParserBase::EnableDebugDump(v1 != 0, v2 != 0);
mu::console() << _T("Bytecode dumping ") << ((v1 != 0) ? _T("active") : _T("inactive"))
<< _T("\n");
@ -153,7 +154,7 @@ void Splash() {
}
//---------------------------------------------------------------------------
value_type SelfTest() {
ValueOrError SelfTest() {
mu::console() << _T( "-----------------------------------------------------------\n");
mu::console() << _T( "Running test suite:\n\n");
@ -170,7 +171,7 @@ value_type SelfTest() {
}
//---------------------------------------------------------------------------
value_type Help() {
ValueOrError Help() {
mu::console() << _T( "-----------------------------------------------------------\n");
mu::console() << _T( "Commands:\n\n");
mu::console() << _T( " list var - list parser variables\n");

View file

@ -48,27 +48,27 @@ namespace mu {
//---------------------------------------------------------------------------
// Trigonometric function
value_type Parser::Sin(value_type v) { return MathImpl<value_type>::Sin(v); }
value_type Parser::Cos(value_type v) { return MathImpl<value_type>::Cos(v); }
value_type Parser::Tan(value_type v) { return MathImpl<value_type>::Tan(v); }
value_type Parser::ASin(value_type v) { return MathImpl<value_type>::ASin(v); }
value_type Parser::ACos(value_type v) { return MathImpl<value_type>::ACos(v); }
value_type Parser::ATan(value_type v) { return MathImpl<value_type>::ATan(v); }
value_type Parser::ATan2(value_type v1, value_type v2) {
ValueOrError Parser::Sin(value_type v) { return MathImpl<value_type>::Sin(v); }
ValueOrError Parser::Cos(value_type v) { return MathImpl<value_type>::Cos(v); }
ValueOrError Parser::Tan(value_type v) { return MathImpl<value_type>::Tan(v); }
ValueOrError Parser::ASin(value_type v) { return MathImpl<value_type>::ASin(v); }
ValueOrError Parser::ACos(value_type v) { return MathImpl<value_type>::ACos(v); }
ValueOrError Parser::ATan(value_type v) { return MathImpl<value_type>::ATan(v); }
ValueOrError Parser::ATan2(value_type v1, value_type v2) {
return MathImpl<value_type>::ATan2(v1, v2);
}
value_type Parser::Sinh(value_type v) { return MathImpl<value_type>::Sinh(v); }
value_type Parser::Cosh(value_type v) { return MathImpl<value_type>::Cosh(v); }
value_type Parser::Tanh(value_type v) { return MathImpl<value_type>::Tanh(v); }
value_type Parser::ASinh(value_type v) { return MathImpl<value_type>::ASinh(v); }
value_type Parser::ACosh(value_type v) { return MathImpl<value_type>::ACosh(v); }
value_type Parser::ATanh(value_type v) { return MathImpl<value_type>::ATanh(v); }
ValueOrError Parser::Sinh(value_type v) { return MathImpl<value_type>::Sinh(v); }
ValueOrError Parser::Cosh(value_type v) { return MathImpl<value_type>::Cosh(v); }
ValueOrError Parser::Tanh(value_type v) { return MathImpl<value_type>::Tanh(v); }
ValueOrError Parser::ASinh(value_type v) { return MathImpl<value_type>::ASinh(v); }
ValueOrError Parser::ACosh(value_type v) { return MathImpl<value_type>::ACosh(v); }
ValueOrError Parser::ATanh(value_type v) { return MathImpl<value_type>::ATanh(v); }
//---------------------------------------------------------------------------
// Logarithm functions
// Logarithm base 2
value_type Parser::Log2(value_type v) {
ValueOrError Parser::Log2(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v <= 0) throw ParserError(ecDOMAIN_ERROR, _T("Log2"));
#endif
@ -77,7 +77,7 @@ value_type Parser::Log2(value_type v) {
}
// Logarithm base 10
value_type Parser::Log10(value_type v) {
ValueOrError Parser::Log10(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v <= 0) throw ParserError(ecDOMAIN_ERROR, _T("Log10"));
#endif
@ -86,7 +86,7 @@ value_type Parser::Log10(value_type v) {
}
// Logarithm base e (natural logarithm)
value_type Parser::Ln(value_type v) {
ValueOrError Parser::Ln(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v <= 0) throw ParserError(ecDOMAIN_ERROR, _T("Ln"));
#endif
@ -96,38 +96,38 @@ value_type Parser::Ln(value_type v) {
//---------------------------------------------------------------------------
// misc
value_type Parser::Exp(value_type v) { return MathImpl<value_type>::Exp(v); }
value_type Parser::Abs(value_type v) { return MathImpl<value_type>::Abs(v); }
value_type Parser::Sqrt(value_type v) {
ValueOrError Parser::Exp(value_type v) { return MathImpl<value_type>::Exp(v); }
ValueOrError Parser::Abs(value_type v) { return MathImpl<value_type>::Abs(v); }
ValueOrError Parser::Sqrt(value_type v) {
#ifdef MUP_MATH_EXCEPTIONS
if (v < 0) throw ParserError(ecDOMAIN_ERROR, _T("sqrt"));
#endif
return MathImpl<value_type>::Sqrt(v);
}
value_type Parser::Rint(value_type v) { return MathImpl<value_type>::Rint(v); }
value_type Parser::Sign(value_type v) { return MathImpl<value_type>::Sign(v); }
ValueOrError Parser::Rint(value_type v) { return MathImpl<value_type>::Rint(v); }
ValueOrError Parser::Sign(value_type v) { return MathImpl<value_type>::Sign(v); }
//---------------------------------------------------------------------------
/** \brief Callback for the unary minus operator.
\param v The value to negate
\return -v
*/
value_type Parser::UnaryMinus(value_type v) { return -v; }
ValueOrError Parser::UnaryMinus(value_type v) { return -v; }
//---------------------------------------------------------------------------
/** \brief Callback for the unary minus operator.
\param v The value to negate
\return -v
*/
value_type Parser::UnaryPlus(value_type v) { return v; }
ValueOrError Parser::UnaryPlus(value_type v) { return v; }
//---------------------------------------------------------------------------
/** \brief Callback for adding multiple values.
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
value_type Parser::Sum(const value_type *a_afArg, int a_iArgc) {
ValueOrError Parser::Sum(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw exception_type(_T("too few arguments for function sum."));
value_type fRes = 0;
@ -140,7 +140,7 @@ value_type Parser::Sum(const value_type *a_afArg, int a_iArgc) {
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
value_type Parser::Avg(const value_type *a_afArg, int a_iArgc) {
ValueOrError Parser::Avg(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw exception_type(_T("too few arguments for function sum."));
value_type fRes = 0;
@ -153,7 +153,7 @@ value_type Parser::Avg(const value_type *a_afArg, int a_iArgc) {
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
value_type Parser::Min(const value_type *a_afArg, int a_iArgc) {
ValueOrError Parser::Min(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw exception_type(_T("too few arguments for function min."));
value_type fRes = a_afArg[0];
@ -167,7 +167,7 @@ value_type Parser::Min(const value_type *a_afArg, int a_iArgc) {
\param [in] a_afArg Vector with the function arguments
\param [in] a_iArgc The size of a_afArg
*/
value_type Parser::Max(const value_type *a_afArg, int a_iArgc) {
ValueOrError Parser::Max(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw exception_type(_T("too few arguments for function min."));
value_type fRes = a_afArg[0];
@ -330,7 +330,7 @@ void Parser::OnDetectVar(string_type * /*pExpr*/, int & /*nStart*/, int & /*nEnd
http://sourceforge.net/forum/forum.php?thread_id=1994611&forum_id=462843
*/
value_type Parser::Diff(value_type *a_Var, value_type a_fPos, value_type a_fEpsilon) const {
ValueOrError Parser::Diff(value_type *a_Var, value_type a_fPos, value_type a_fEpsilon) const {
value_type fRes(0), fBuf(*a_Var), f[4] = {0, 0, 0, 0}, fEpsilon(a_fEpsilon);
// Backwards compatible calculation of epsilon inc case the user doesn't provide

View file

@ -1025,62 +1025,74 @@ value_type ParserBase::ParseCmdCode() const {
switch (iArgCount) {
case 0:
sidx += 1;
Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)();
Stack[sidx] = (*(fun_type0)pTok->Fun.ptr)().getOrThrow();
continue;
case 1:
Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]);
Stack[sidx] = (*(fun_type1)pTok->Fun.ptr)(Stack[sidx]).getOrThrow();
continue;
case 2:
sidx -= 1;
Stack[sidx] = (*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1]);
Stack[sidx] =
(*(fun_type2)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1]).getOrThrow();
continue;
case 3:
sidx -= 2;
Stack[sidx] = (*(fun_type3)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1],
Stack[sidx + 2]);
Stack[sidx + 2])
.getOrThrow();
continue;
case 4:
sidx -= 3;
Stack[sidx] = (*(fun_type4)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1],
Stack[sidx + 2], Stack[sidx + 3]);
Stack[sidx + 2], Stack[sidx + 3])
.getOrThrow();
continue;
case 5:
sidx -= 4;
Stack[sidx] = (*(fun_type5)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1],
Stack[sidx + 2], Stack[sidx + 3],
Stack[sidx + 4]);
Stack[sidx + 4])
.getOrThrow();
continue;
case 6:
sidx -= 5;
Stack[sidx] = (*(fun_type6)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1],
Stack[sidx + 2], Stack[sidx + 3],
Stack[sidx + 4], Stack[sidx + 5]);
Stack[sidx + 4], Stack[sidx + 5])
.getOrThrow();
continue;
case 7:
sidx -= 6;
Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(
Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3],
Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6]);
Stack[sidx] = (*(fun_type7)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1],
Stack[sidx + 2], Stack[sidx + 3],
Stack[sidx + 4], Stack[sidx + 5],
Stack[sidx + 6])
.getOrThrow();
continue;
case 8:
sidx -= 7;
Stack[sidx] = (*(fun_type8)pTok->Fun.ptr)(
Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3],
Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6], Stack[sidx + 7]);
Stack[sidx] = (*(fun_type8)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1],
Stack[sidx + 2], Stack[sidx + 3],
Stack[sidx + 4], Stack[sidx + 5],
Stack[sidx + 6], Stack[sidx + 7])
.getOrThrow();
continue;
case 9:
sidx -= 8;
Stack[sidx] = (*(fun_type9)pTok->Fun.ptr)(
Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3],
Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6], Stack[sidx + 7],
Stack[sidx + 8]);
Stack[sidx], Stack[sidx + 1], Stack[sidx + 2],
Stack[sidx + 3], Stack[sidx + 4], Stack[sidx + 5],
Stack[sidx + 6], Stack[sidx + 7], Stack[sidx + 8])
.getOrThrow();
continue;
case 10:
sidx -= 9;
Stack[sidx] = (*(fun_type10)pTok->Fun.ptr)(
Stack[sidx], Stack[sidx + 1], Stack[sidx + 2], Stack[sidx + 3],
Stack[sidx + 4], Stack[sidx + 5], Stack[sidx + 6], Stack[sidx + 7],
Stack[sidx + 8], Stack[sidx + 9]);
Stack[sidx] = (*(fun_type10)pTok->Fun.ptr)(Stack[sidx], Stack[sidx + 1],
Stack[sidx + 2], Stack[sidx + 3],
Stack[sidx + 4], Stack[sidx + 5],
Stack[sidx + 6], Stack[sidx + 7],
Stack[sidx + 8], Stack[sidx + 9])
.getOrThrow();
continue;
default:
if (iArgCount > 0) // function with variable arguments store the number as
@ -1088,7 +1100,8 @@ value_type ParserBase::ParseCmdCode() const {
assert(0 && "muParser internal error");
sidx -= -iArgCount - 1;
Stack[sidx] = (*(multfun_type)pTok->Fun.ptr)(&Stack[sidx], -iArgCount);
Stack[sidx] =
(*(multfun_type)pTok->Fun.ptr)(&Stack[sidx], -iArgCount).getOrThrow();
continue;
}
}
@ -1105,15 +1118,19 @@ value_type ParserBase::ParseCmdCode() const {
{
case 0:
Stack[sidx] =
(*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str());
(*(strfun_type1)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str())
.getOrThrow();
continue;
case 1:
Stack[sidx] = (*(strfun_type2)pTok->Fun.ptr)(
m_vStringBuf[iIdxStack].c_str(), Stack[sidx]);
m_vStringBuf[iIdxStack].c_str(), Stack[sidx])
.getOrThrow();
continue;
case 2:
Stack[sidx] = (*(strfun_type3)pTok->Fun.ptr)(
m_vStringBuf[iIdxStack].c_str(), Stack[sidx], Stack[sidx + 1]);
Stack[sidx] =
(*(strfun_type3)pTok->Fun.ptr)(m_vStringBuf[iIdxStack].c_str(),
Stack[sidx], Stack[sidx + 1])
.getOrThrow();
continue;
}

View file

@ -37,40 +37,40 @@ using namespace std;
/** \brief Namespace for mathematical applications. */
namespace mu {
value_type ParserInt::Abs(value_type v) { return (value_type)Round(fabs((double)v)); }
value_type ParserInt::Sign(value_type v) { return (Round(v) < 0) ? -1 : (Round(v) > 0) ? 1 : 0; }
value_type ParserInt::Ite(value_type v1, value_type v2, value_type v3) {
ValueOrError ParserInt::Abs(value_type v) { return (value_type)Round(fabs((double)v)); }
ValueOrError ParserInt::Sign(value_type v) { return (Round(v) < 0) ? -1 : (Round(v) > 0) ? 1 : 0; }
ValueOrError ParserInt::Ite(value_type v1, value_type v2, value_type v3) {
return (Round(v1) == 1) ? Round(v2) : Round(v3);
}
value_type ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); }
value_type ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); }
value_type ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); }
value_type ParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); }
value_type ParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); }
value_type ParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); }
value_type ParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); }
value_type ParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); }
value_type ParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); }
value_type ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); }
value_type ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); }
value_type ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); }
value_type ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); }
value_type ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); }
value_type ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); }
value_type ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); }
value_type ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); }
value_type ParserInt::Not(value_type v) { return !Round(v); }
ValueOrError ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); }
ValueOrError ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); }
ValueOrError ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); }
ValueOrError ParserInt::Div(value_type v1, value_type v2) { return Round(v1) / Round(v2); }
ValueOrError ParserInt::Mod(value_type v1, value_type v2) { return Round(v1) % Round(v2); }
ValueOrError ParserInt::Shr(value_type v1, value_type v2) { return Round(v1) >> Round(v2); }
ValueOrError ParserInt::Shl(value_type v1, value_type v2) { return Round(v1) << Round(v2); }
ValueOrError ParserInt::LogAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); }
ValueOrError ParserInt::LogOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); }
ValueOrError ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); }
ValueOrError ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); }
ValueOrError ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); }
ValueOrError ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); }
ValueOrError ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); }
ValueOrError ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); }
ValueOrError ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); }
ValueOrError ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); }
ValueOrError ParserInt::Not(value_type v) { return !Round(v); }
value_type ParserInt::Pow(value_type v1, value_type v2) {
ValueOrError ParserInt::Pow(value_type v1, value_type v2) {
return std::pow((double)Round(v1), (double)Round(v2));
}
//---------------------------------------------------------------------------
// Unary operator Callbacks: Infix operators
value_type ParserInt::UnaryMinus(value_type v) { return -Round(v); }
ValueOrError ParserInt::UnaryMinus(value_type v) { return -Round(v); }
//---------------------------------------------------------------------------
value_type ParserInt::Sum(const value_type *a_afArg, int a_iArgc) {
ValueOrError ParserInt::Sum(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw ParserError(_T("too few arguments for function sum."));
value_type fRes = 0;
@ -80,7 +80,7 @@ value_type ParserInt::Sum(const value_type *a_afArg, int a_iArgc) {
}
//---------------------------------------------------------------------------
value_type ParserInt::Min(const value_type *a_afArg, int a_iArgc) {
ValueOrError ParserInt::Min(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw ParserError(_T("too few arguments for function min."));
value_type fRes = a_afArg[0];
@ -90,7 +90,7 @@ value_type ParserInt::Min(const value_type *a_afArg, int a_iArgc) {
}
//---------------------------------------------------------------------------
value_type ParserInt::Max(const value_type *a_afArg, int a_iArgc) {
ValueOrError ParserInt::Max(const value_type *a_afArg, int a_iArgc) {
if (!a_iArgc) throw ParserError(_T("too few arguments for function min."));
value_type fRes = a_afArg[0];

View file

@ -116,7 +116,7 @@ static const wchar_t *math_get_arg(int *argidx, wchar_t **argv, wcstring *storag
}
/// Implement integer modulo math operator.
static double moduloOperator(double v, double w) { return (int)v % std::max(1, (int)w); };
static mu::ValueOrError moduloOperator(double v, double w) { return (int)v % std::max(1, (int)w); };
/// Evaluate math expressions.
static int evaluate_expression(wchar_t *cmd, parser_t &parser, io_streams_t &streams,