diff --git a/core/src/main/cpp/parser/equationsParser.cpp b/core/src/main/cpp/parser/equationsParser.cpp new file mode 100644 index 0000000..4913c35 --- /dev/null +++ b/core/src/main/cpp/parser/equationsParser.cpp @@ -0,0 +1,140 @@ +#include "equationsParser.h" + +#include +#include +#include +#include + +using namespace std; +using namespace mup; + +EQUATIONS_PARSER_START + +/** + * @brief Evaluates an input string as a mathematical expression and returns the result + * @param input The string to be evaluated as a mathematical expression + */ +string Calc(string input) { + ParserX parser(pckALL_NON_COMPLEX); + + Value ans; + parser.DefineVar(_T("ans"), Variable(&ans)); + + try + { + parser.SetExpr(input); + ans = parser.Eval(); + + return ans.AsString(); + } + catch(ParserError &e) + { + if (e.GetPos() != -1) { + string_type error = "Error: "; + error.append(e.GetMsg()); + return error; + } + } + catch(std::runtime_error & ex) + { + string_type error = "Error: Runtime error - "; + error.append(ex.what()); + return error; + } + return ans.AsString(); +} + +/** + * @brief Replaces all occurrences of the substring @from in the source string with another the + * substring @to + * @param source A reference to the string to perform the replacement on + * @param from The substring to be replaced + * @param to The substring that will replace 'from' + */ +void ReplaceAll(std::string& source, const std::string& from, const std::string& to) { + std::string newString; + newString.reserve(source.length()); // avoids a few memory allocations + + std::string::size_type lastPos = 0; + std::string::size_type findPos; + + while(std::string::npos != (findPos = source.find(from, lastPos))) + { + newString.append(source, lastPos, findPos - lastPos); + newString += to; + lastPos = findPos + from.length(); + } + + // Care for the rest after last occurrence + newString += source.substr(lastPos); + + source.swap(newString); +} + +/** + * @brief Evaluates an input string as a mathematical expression and returns the result as a JSON + * @param input The string to be evaluated as a mathematical expression + * @return The result of the evaluation as a JSON string in the following format: + * { + * "val": "result_value", + * "type": "result_type" + * } + * or in case of error: + * { + * "error": "error_message" + * } + */ +string CalcJson(string input) { + ParserX parser(pckALL_NON_COMPLEX); + + Value ans; + parser.DefineVar(_T("ans"), Variable(&ans)); + + stringstream_type ss; + + ss << _T("{"); + + try + { + parser.SetExpr(input); + ans = parser.Eval(); + + std::string ansString = ans.AsString(); + + ReplaceAll(ansString, "\"", "\\\""); + + ss << _T("\"val\": \"") << ansString << _T("\""); + ss << _T(",\"type\": \"") << ans.GetType() << _T("\""); + } + catch(ParserError &e) + { + if (e.GetPos() != -1) { + string_type error = e.GetMsg(); + ss << _T("\"error\": \"") << error << _T("\""); + } + } + catch(std::runtime_error & ex) + { + string_type error = "Error: Runtime error - "; + error.append(ex.what()); + ss << _T("\"error\": \"") << error << _T("\""); + } + + ss << _T("}"); + + return ss.str(); +} + +/** + * Calculates the result of a list of equations and stores them in the 'out' vector. + * + * @param equations a vector of strings representing mathematical equations + * @param out a vector of strings where the results of the calculations will be stored + */ +void CalcArray(vector equations, vector &out) { + for(string equation : equations) { + out.push_back(CalcJson(equation)); + } +} + +EQUATIONS_PARSER_END diff --git a/core/src/main/cpp/parser/equationsParser.h b/core/src/main/cpp/parser/equationsParser.h new file mode 100644 index 0000000..05a4a02 --- /dev/null +++ b/core/src/main/cpp/parser/equationsParser.h @@ -0,0 +1,21 @@ +#ifndef EQUATIONS_PARSER_H +#define EQUATIONS_PARSER_H + +#include +//--- Parser framework ----------------------------------------------------- +#include "mpParser.h" +#include "mpDefines.h" + +#define EQUATIONS_PARSER_START namespace EquationsParser { +#define EQUATIONS_PARSER_END } + +EQUATIONS_PARSER_START + +void ReplaceAll(std::string& source, const std::string& from, const std::string& to); +std::string Calc(std::string input); +std::string CalcJson(std::string input); +void CalcArray(std::vector in, std::vector &out); + +EQUATIONS_PARSER_END + +#endif diff --git a/core/src/main/cpp/parser/mpFuncCommon.cpp b/core/src/main/cpp/parser/mpFuncCommon.cpp index ce41c63..2f28f58 100755 --- a/core/src/main/cpp/parser/mpFuncCommon.cpp +++ b/core/src/main/cpp/parser/mpFuncCommon.cpp @@ -458,6 +458,34 @@ MUP_NAMESPACE_START throw ParserError(err); } + string_type localized_weekday(int week_day, const ptr_val_type *a_pArg) { + string_type locale = a_pArg[1]->GetString(); + string_type ret = ""; + string_type localized_weekdays[8][7] = { + {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}, + {"Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag"}, + {"Domingo", "Segunda-Feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sábado"}, + {"Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sabado"}, + {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"}, + {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"}, + {"星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}, + {"วันอาทิตย์", "วันจันทร์", "วันอังคาร", "วันพุธ", "วันพฤหัสบดี", "วันศุกร์", "วันเสาร์"} + }; + string_type locales[8] = {"en", "nb", "pt-BR", "es-ES", "fr-FR", "de-DE", "zh-CN", "th-TH"}; + + for (int i = 0; i < 8; i++) { + if(locale == locales[i]) { + ret = localized_weekdays[i][week_day]; + } + } + + if(ret == ""){ + raise_error(ecUKNOWN_LOCALE, 2, a_pArg); + } + + return ret; + } + //------------------------------------------------------------------------------ // // class FunDaysDiff @@ -675,11 +703,6 @@ MUP_NAMESPACE_START return new FunAddDays(*this); } - //------------------------------------------------------------------------------ - // - // class FunTimeDiff - // - //------------------------------------------------------------------------------ //FunTimeDiff::FunTimeDiff() // :ICallback(cmFUNC, _T("timediff"), -1) @@ -780,6 +803,30 @@ MUP_NAMESPACE_START // | //------------------------------------------------------------------------------ + //------------------------------------------------------------------------------ + // | + // Time auxiliar functions! | + // | + //------------------------------------------------------------------------------ + + int calculate_hour_offset(int original_hour, int gmt_offset) { + return ((original_hour + gmt_offset) % 24 + 24) % 24; + } + + string_type format_time (struct tm time, int gmt_offset) { + char buffer[9]; + int hours = calculate_hour_offset(time.tm_hour, gmt_offset); + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d", hours, time.tm_min, time.tm_sec); + + return std::string(buffer); + } + + //------------------------------------------------------------------------------ + // + // class FunTimeDiff + // + //------------------------------------------------------------------------------ + FunTimeDiff::FunTimeDiff() :ICallback(cmFUNC, _T("timediff"), -1) {} @@ -828,4 +875,238 @@ MUP_NAMESPACE_START return new FunTimeDiff(*this); } + //------------------------------------------------------------------------------ + // | + // class FunCurrentTime | + // Usage: current_time() | + // Optional offset: current_time(-2) | + // | + //------------------------------------------------------------------------------ + + FunCurrentTime::FunCurrentTime() + :ICallback(cmFUNC, _T("current_time"), -1) + {} + + void FunCurrentTime::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) + { + int gmt_offset = 0; + if (a_iArgc > 1) { + throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, GetExprPos(), GetIdent())); + } else if (a_iArgc == 1) { + switch(a_pArg[0]->GetType()) + { + case 'i': gmt_offset = a_pArg[0]->GetInteger(); break; + default: + { + ErrorContext err; + err.Errc = ecTYPE_CONFLICT_FUN; + err.Arg = 1; + err.Type1 = a_pArg[0]->GetType(); + err.Type2 = 'i'; + err.Ident = GetIdent(); + throw ParserError(err); + } + } + } + + std::time_t t = std::time(0); + std::tm now = *std::gmtime(&t); + + *ret = format_time(now, gmt_offset); + } + + ////--------------------------------------------------------------------------------------------------------- + const char_type* FunCurrentTime::GetDesc() const + { + return _T("current_time(offset) - Returns the current time in the HH:MM:SS format, applying the offset."); + } + + ////--------------------------------------------------------------------------------------------------------- + IToken* FunCurrentTime::Clone() const + { + return new FunCurrentTime(*this); + } + + //------------------------------------------------------------------------------ + // | + // Functions for regex matching | + // Usage: regex("string", "regex") | + // | + //------------------------------------------------------------------------------ + + FunRegex::FunRegex() + :ICallback(cmFUNC, _T("regex"), -1) + {} + + std::vector> capture_regex_groups(const std::string& input, const std::string& pattern) { + std::vector> captured_groups; + std::smatch match; + std::regex re(pattern); + std::string::const_iterator search_start(input.cbegin()); + + while (std::regex_search(search_start, input.cend(), match, re)) { + std::vector groups; + for (size_t i = 1; i < match.size(); ++i) { + groups.push_back(match[i].str()); + } + captured_groups.push_back(groups); + search_start = match.suffix().first; + } + + return captured_groups; + } + + void FunRegex::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) + { + if (a_iArgc < 2) { + throw ParserError(ErrorContext(ecTOO_FEW_PARAMS, GetExprPos(), GetIdent())); + } else if (a_iArgc > 2) { + throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, GetExprPos(), GetIdent())); + } + + string_type input = a_pArg[0]->GetString(); + string_type pattern = a_pArg[1]->GetString(); + + auto captured_groups = capture_regex_groups(input, pattern); + + if (captured_groups.size() == 0 || captured_groups[0].size() == 0) { + *ret = (string_type) ""; + } else { + *ret = (string_type) captured_groups[0][0]; + } + } + + ////------------------------------------------------------------------------------ + const char_type* FunRegex::GetDesc() const + { + return _T("regex(a,b) - Returns the first match of a regex pattern."); + } + + ////------------------------------------------------------------------------------ + IToken* FunRegex::Clone() const + { + return new FunRegex(*this); + } + + //------------------------------------------------------------------------------ + // | + // Function return the week of year of a date | + // Usage: weekyear("2022-04-20") | + // | + //------------------------------------------------------------------------------ + + FunWeekYear::FunWeekYear() + :ICallback(cmFUNC, _T("weekyear"), -1) + {} + + void FunWeekYear::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) + { + if (a_iArgc < 1) { + throw ParserError(ErrorContext(ecTOO_FEW_PARAMS, GetExprPos(), GetIdent())); + } else if (a_iArgc > 1) { + throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, GetExprPos(), GetIdent())); + } + + string_type date_time = a_pArg[0]->GetString(); + + struct tm date; + if (!strptime(date_time.c_str(), "%Y-%m-%d", &date)) { + raise_error(ecINVALID_DATE_FORMAT, 1, a_pArg); + } + + int year = date.tm_year + 1900; // tm_year is the number of years since 1900 + + // Get ordinal day of the year + int day_of_year = date.tm_yday + 1; // tm_yday is the number of days since January 1st + + // Get weekday number (0 is Sunday) + int weekday = date.tm_wday; + + // Calculate week number + int week_number = (day_of_year - weekday + 10) / 7; + + // Check if week belongs to previous year + if (week_number == 0) { + year--; + week_number = 52; + if (std::tm{0,0,0,1,0,year-1900}.tm_wday < 4) { // January 1st of the previous year is before Thursday + week_number = 53; + } + } + + // Check if week belongs to following year + if (week_number == 53) { + if (std::tm{0,0,0,1,0,year+1-1900}.tm_wday >= 4) { // January 1st of the following year is on or after Thursday + week_number = 1; + } + } + + *ret = week_number; + } + + ////------------------------------------------------------------------------------ + const char_type* FunWeekYear::GetDesc() const + { + return _T("weekyear(date) - Returns the week number of the year."); + } + + ////------------------------------------------------------------------------------ + IToken* FunWeekYear::Clone() const + { + return new FunWeekYear(*this); + } + + //------------------------------------------------------------------------------ + // | + // Function return the week day of a date | + // Usage: weekday("2022-04-20") | + // Optional locale: weekday("2022-04-20", "en") | + // | + //------------------------------------------------------------------------------ + + FunWeekDay::FunWeekDay() + :ICallback(cmFUNC, _T("weekday"), -1) + {} + + void FunWeekDay::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) + { + if (a_iArgc < 1) { + throw ParserError(ErrorContext(ecTOO_FEW_PARAMS, GetExprPos(), GetIdent())); + } else if (a_iArgc > 2) { + throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, GetExprPos(), GetIdent())); + } + + string_type date_time = a_pArg[0]->GetString(); + + struct tm date; + if (!strptime(date_time.c_str(), "%Y-%m-%d", &date)) { + raise_error(ecINVALID_DATETIME_FORMAT, 1, a_pArg); + } + + bool has_locale = false; + if (a_iArgc == 2) { + has_locale = true; + } + + int week_day = date.tm_wday; + + if(has_locale) { + *ret = localized_weekday(week_day, a_pArg); + } else { + *ret = week_day; + } + } + + ////------------------------------------------------------------------------------ + const char_type* FunWeekDay::GetDesc() const + { + return _T("weekday(date) - Returns the week day of the date."); + } + + ////------------------------------------------------------------------------------ + IToken* FunWeekDay::Clone() const + { + return new FunWeekDay(*this); + } + MUP_NAMESPACE_END diff --git a/core/src/main/cpp/parser/mpFuncCommon.h b/core/src/main/cpp/parser/mpFuncCommon.h index adbd1bd..e2c4226 100755 --- a/core/src/main/cpp/parser/mpFuncCommon.h +++ b/core/src/main/cpp/parser/mpFuncCommon.h @@ -198,6 +198,58 @@ MUP_NAMESPACE_START virtual IToken* Clone() const override; }; // class FunTimeDiff + //------------------------------------------------------------------------------ + /** \brief Returns the current time in the HH:MM:SS format. + \ingroup functions + */ + class FunCurrentTime : public ICallback + { + public: + FunCurrentTime(); + virtual void Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; + }; // class FunCurrentTime + + //------------------------------------------------------------------------------ + /** \brief Return the capture group of a regular expression. + \ingroup functions + */ + class FunRegex : public ICallback + { + public: + FunRegex(); + virtual void Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; + }; // class FunRegex + + //------------------------------------------------------------------------------ + /** \brief Return the week of year of a date. + \ingroup functions + */ + class FunWeekYear: public ICallback + { + public: + FunWeekYear(); + virtual void Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; + }; // class FunWeekYear + + //------------------------------------------------------------------------------ + /** \brief Return the week of year of a date. + \ingroup functions + */ + class FunWeekDay: public ICallback + { + public: + FunWeekDay(); + virtual void Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; + }; // class FunWeekDay + MUP_NAMESPACE_END #endif diff --git a/core/src/main/cpp/parser/mpFuncNonCmplx.cpp b/core/src/main/cpp/parser/mpFuncNonCmplx.cpp index 4b10329..1d206a5 100755 --- a/core/src/main/cpp/parser/mpFuncNonCmplx.cpp +++ b/core/src/main/cpp/parser/mpFuncNonCmplx.cpp @@ -33,6 +33,7 @@ */ #include "mpFuncNonCmplx.h" +#include "mpFuncRound.h" //--- Standard includes ---------------------------------------------------- #include @@ -48,16 +49,6 @@ MUP_NAMESPACE_START -//------------------------------------------------------------------------------ -// -// Auxiliary Functions -// -//------------------------------------------------------------------------------ -double round(long_double_type number, int_type precision) { - int_type decimals = std::pow(10, precision); - return (std::round(number * decimals)) / decimals; -} - //------------------------------------------------------------------------------ // // @@ -111,7 +102,6 @@ double round(long_double_type number, int_type precision) { MUP_UNARY_FUNC(FunExp, "exp", std::exp, "exp(x) - e to the power of x") // number functions MUP_UNARY_FUNC(FunAbs, "abs", std::fabs, "abs(x) - absolute value of x") - MUP_UNARY_FUNC(FunRound, "round", std::round, "round(x) - round the value of x to its nearest integer") #undef MUP_UNARY_FUNC #define MUP_BINARY_FUNC(CLASS, IDENT, FUNC, DESC) \ @@ -138,7 +128,6 @@ double round(long_double_type number, int_type precision) { MUP_BINARY_FUNC(FunHypot, "hypot", std::hypot, "hypot(x, y) - compute the length of the vector x,y") MUP_BINARY_FUNC(FunAtan2, "atan2", std::atan2, "arcus tangens with quadrant fix") MUP_BINARY_FUNC(FunFmod, "fmod", std::fmod, "fmod(x, y) - floating point remainder of x / y") - MUP_BINARY_FUNC(FunRoundDecimal, "round_decimal", round, "round_decimal(x, y) - round the x number considering y precision") MUP_BINARY_FUNC(FunRemainder, "remainder", std::remainder, "remainder(x, y) - IEEE remainder of x / y") #undef MUP_BINARY_FUNC diff --git a/core/src/main/cpp/parser/mpFuncNonCmplx.h b/core/src/main/cpp/parser/mpFuncNonCmplx.h index a07327a..4b91fd1 100755 --- a/core/src/main/cpp/parser/mpFuncNonCmplx.h +++ b/core/src/main/cpp/parser/mpFuncNonCmplx.h @@ -81,7 +81,6 @@ MUP_NAMESPACE_START MUP_UNARY_FUNC_DEF(FunExp) // number functions MUP_UNARY_FUNC_DEF(FunAbs) - MUP_UNARY_FUNC_DEF(FunRound) #undef MUP_UNARY_FUNC_DEF #define MUP_BINARY_FUNC_DEF(CLASS) \ @@ -98,7 +97,6 @@ MUP_NAMESPACE_START MUP_BINARY_FUNC_DEF(FunHypot) MUP_BINARY_FUNC_DEF(FunAtan2) MUP_BINARY_FUNC_DEF(FunFmod) - MUP_BINARY_FUNC_DEF(FunRoundDecimal) MUP_BINARY_FUNC_DEF(FunRemainder) #undef MUP_BINARY_FUNC_DEF diff --git a/core/src/main/cpp/parser/mpFuncRound.cpp b/core/src/main/cpp/parser/mpFuncRound.cpp new file mode 100644 index 0000000..47fd18c --- /dev/null +++ b/core/src/main/cpp/parser/mpFuncRound.cpp @@ -0,0 +1,94 @@ +#include "mpFuncRound.h" + +#include + +#include "mpError.h" +#include "mpValue.h" + +MUP_NAMESPACE_START + +namespace +{ + void eval_round(ICallback &callback, + ptr_val_type &ret, + const ptr_val_type *args, + int argc, + bool has_precision) + { + int required_argc = has_precision ? 2 : 1; + if (argc < required_argc) { + throw ParserError(ErrorContext(ecTOO_FEW_PARAMS, + callback.GetExprPos(), + callback.GetIdent())); + } else if (argc > required_argc + 1) { + throw ParserError(ErrorContext(ecTOO_MANY_PARAMS, + callback.GetExprPos(), + callback.GetIdent())); + } + + int_type scale = 1; + if (has_precision) { + int_type precision = args[1]->GetFloat(); + scale = std::pow(10, precision); + } + + float_type value = args[0]->GetFloat() * scale; + if (argc == required_argc) { + *ret = std::round(value) / scale; + return; + } + + string_type direction = args[required_argc]->GetString(); + if (direction == _T("up")) { + *ret = std::ceil(value) / scale; + } else if (direction == _T("down")) { + *ret = std::floor(value) / scale; + } else { + ErrorContext err(ecINVALID_PARAMETER, + callback.GetExprPos(), + callback.GetIdent()); + err.Arg = required_argc + 1; + throw ParserError(err); + } + } +} + +FunRound::FunRound() + :ICallback(cmFUNC, _T("round"), -1) +{} + +void FunRound::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) +{ + eval_round(*this, ret, a_pArg, a_iArgc, false); +} + +const char_type* FunRound::GetDesc() const +{ + return _T("round(x[, direction]) - round x normally, up or down"); +} + +IToken* FunRound::Clone() const +{ + return new FunRound(*this); +} + +FunRoundDecimal::FunRoundDecimal() + :ICallback(cmFUNC, _T("round_decimal"), -1) +{} + +void FunRoundDecimal::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) +{ + eval_round(*this, ret, a_pArg, a_iArgc, true); +} + +const char_type* FunRoundDecimal::GetDesc() const +{ + return _T("round_decimal(x, precision[, direction]) - round x at the given precision"); +} + +IToken* FunRoundDecimal::Clone() const +{ + return new FunRoundDecimal(*this); +} + +MUP_NAMESPACE_END diff --git a/core/src/main/cpp/parser/mpFuncRound.h b/core/src/main/cpp/parser/mpFuncRound.h new file mode 100644 index 0000000..739930f --- /dev/null +++ b/core/src/main/cpp/parser/mpFuncRound.h @@ -0,0 +1,28 @@ +#ifndef MUP_FUNC_ROUND_H +#define MUP_FUNC_ROUND_H + +#include "mpICallback.h" + +MUP_NAMESPACE_START + +class FunRound : public ICallback +{ +public: + FunRound(); + virtual void Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; +}; + +class FunRoundDecimal : public ICallback +{ +public: + FunRoundDecimal(); + virtual void Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; +}; + +MUP_NAMESPACE_END + +#endif diff --git a/core/src/main/cpp/parser/mpFuncStr.cpp b/core/src/main/cpp/parser/mpFuncStr.cpp index d18b17b..8532ea7 100755 --- a/core/src/main/cpp/parser/mpFuncStr.cpp +++ b/core/src/main/cpp/parser/mpFuncStr.cpp @@ -1,31 +1,31 @@ /* __________ ____ ___ _____ __ _\______ \_____ _______ ______ __________\ \/ / - / \| | \ ___/\__ \\_ __ \/ ___// __ \_ __ \ / - | Y Y \ | / | / __ \| | \/\___ \\ ___/| | \/ \ + / \| | \ ___/\__ \\_ __ \/ ___// __ \_ __ \ / + | Y Y \ | / | / __ \| | \/\___ \\ ___/| | \/ \ |__|_| /____/|____| (____ /__| /____ >\___ >__| /___/\ \ \/ \/ \/ \/ \_/ Copyright (C) 2016, Ingo Berg All rights reserved. - Redistribution and use in source and binary forms, with or without + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mpFuncStr.h" @@ -38,41 +38,10 @@ #include "mpValue.h" #include "mpError.h" +#include "equationsParser.h" MUP_NAMESPACE_START - - //------------------------------------------------------------------------------ - // - // Contains function - // - //------------------------------------------------------------------------------ - - FunStrContains::FunStrContains() - :ICallback(cmFUNC, _T("contains"), 2) - {} - - //------------------------------------------------------------------------------ - void FunStrContains::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int) - { - const string_type & str1 = a_pArg[0]->GetString(); - const string_type & str2 = a_pArg[1]->GetString(); - - *ret = str1.find(str2) != string_type::npos ? true : false; - } - - //------------------------------------------------------------------------------ - const char_type* FunStrContains::GetDesc() const - { - return _T("contains(str1, str2) - Returns if the str2 string is a sub string of str1."); - } - - //------------------------------------------------------------------------------ - IToken* FunStrContains::Clone() const - { - return new FunStrContains(*this); - } - //------------------------------------------------------------------------------ // // Concat function @@ -434,7 +403,7 @@ MUP_NAMESPACE_START in = a_pArg[0]->GetString(); -#ifndef _UNICODE +#ifndef _UNICODE sscanf(in.c_str(), "%lf", &out); #else swscanf(in.c_str(), _T("%lf"), &out); @@ -587,4 +556,67 @@ MUP_NAMESPACE_START { return new FunString(*this); } + + //------------------------------------------------------------------------------ + // + // Contains function + // + //------------------------------------------------------------------------------ + + FunStrContains::FunStrContains() + :ICallback(cmFUNC, _T("contains"), 2) + {} + + //------------------------------------------------------------------------------ + void FunStrContains::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int) + { + const string_type & str1 = a_pArg[0]->GetString(); + const string_type & str2 = a_pArg[1]->GetString(); + + *ret = str1.find(str2) != string_type::npos; + } + + //------------------------------------------------------------------------------ + const char_type* FunStrContains::GetDesc() const + { + return _T("contains(str1, str2) - Returns if the str2 string is a sub string of str1."); + } + + //------------------------------------------------------------------------------ + IToken* FunStrContains::Clone() const + { + return new FunStrContains(*this); + } + + //------------------------------------------------------------------------------ + // + // Calculate function + // + //------------------------------------------------------------------------------ + + FunStrCalculate::FunStrCalculate() + :ICallback(cmFUNC, _T("calculate"), 1) + {} + + //------------------------------------------------------------------------------ + void FunStrCalculate::Eval(ptr_val_type &ret, const ptr_val_type *a_pArg, int) + { + using namespace std; + + string_type equation = a_pArg[0]->GetString(); + + *ret = EquationsParser::Calc(equation); + } + + //------------------------------------------------------------------------------ + const char_type* FunStrCalculate::GetDesc() const + { + return _T("calculate(s) - Calculates an equation (Run equations-parser for the string input)."); + } + + //------------------------------------------------------------------------------ + IToken* FunStrCalculate::Clone() const + { + return new FunStrCalculate(*this); + } MUP_NAMESPACE_END diff --git a/core/src/main/cpp/parser/mpFuncStr.h b/core/src/main/cpp/parser/mpFuncStr.h index f2ef9bd..b3fe85d 100755 --- a/core/src/main/cpp/parser/mpFuncStr.h +++ b/core/src/main/cpp/parser/mpFuncStr.h @@ -191,6 +191,19 @@ MUP_NAMESPACE_START virtual const char_type* GetDesc() const override; virtual IToken* Clone() const override; }; // class FunString + +//------------------------------------------------------------------------------ + /** \brief Calculate equation string + \ingroup functions + */ + class FunStrCalculate : public ICallback + { + public: + FunStrCalculate (); + virtual void Eval(ptr_val_type& ret, const ptr_val_type *a_pArg, int a_iArgc) override; + virtual const char_type* GetDesc() const override; + virtual IToken* Clone() const override; + }; // class FunStrCalculate MUP_NAMESPACE_END #endif diff --git a/core/src/main/cpp/parser/mpPackageCommon.cpp b/core/src/main/cpp/parser/mpPackageCommon.cpp index 5357f86..1add84c 100755 --- a/core/src/main/cpp/parser/mpPackageCommon.cpp +++ b/core/src/main/cpp/parser/mpPackageCommon.cpp @@ -99,9 +99,15 @@ void PackageCommon::AddToParser(ParserXBase *pParser) pParser->DefineFun(new FunHoursDiff()); pParser->DefineFun(new FunCurrentDate()); pParser->DefineFun(new FunAddDays()); + pParser->DefineFun(new FunWeekYear()); + pParser->DefineFun(new FunWeekDay()); + + // String functions + pParser->DefineFun(new FunRegex()); // Time functions pParser->DefineFun(new FunTimeDiff()); + pParser->DefineFun(new FunCurrentTime()); // misc pParser->DefineFun(new FunParserID); diff --git a/core/src/main/cpp/parser/mpPackageNonCmplx.cpp b/core/src/main/cpp/parser/mpPackageNonCmplx.cpp index 6b84dc1..a4dc3fc 100755 --- a/core/src/main/cpp/parser/mpPackageNonCmplx.cpp +++ b/core/src/main/cpp/parser/mpPackageNonCmplx.cpp @@ -32,6 +32,7 @@ #include "mpParserBase.h" #include "mpFuncNonCmplx.h" +#include "mpFuncRound.h" #include "mpOprtNonCmplx.h" #include "mpOprtBinCommon.h" diff --git a/core/src/main/cpp/parser/mpPackageStr.cpp b/core/src/main/cpp/parser/mpPackageStr.cpp index 2b179ce..c028903 100755 --- a/core/src/main/cpp/parser/mpPackageStr.cpp +++ b/core/src/main/cpp/parser/mpPackageStr.cpp @@ -69,6 +69,7 @@ void PackageStr::AddToParser(ParserXBase *pParser) pParser->DefineFun(new FunStrDefaultValue()); pParser->DefineFun(new FunString()); pParser->DefineFun(new FunStrContains()); + pParser->DefineFun(new FunStrCalculate()); // Operators pParser->DefineOprt(new OprtStrAdd); diff --git a/core/src/main/cpp/parser/mpParserMessageProvider.cpp b/core/src/main/cpp/parser/mpParserMessageProvider.cpp index d28b4ae..73995cc 100755 --- a/core/src/main/cpp/parser/mpParserMessageProvider.cpp +++ b/core/src/main/cpp/parser/mpParserMessageProvider.cpp @@ -111,6 +111,8 @@ MUP_NAMESPACE_START m_vErrMsg[ecADD_HOURS_DATE] = _T("The first parameter could not be converted to a date. Please use the format: \"yyyy-mm-dd\""); m_vErrMsg[ecADD_HOURS_DATETIME] = _T("The first parameter could not be converted to a date time. Please use the format: \"yyyy-mm-ddTHH:MM\""); m_vErrMsg[ecINVALID_TYPES_MATCH] = _T("Both values of the default(x, y) function should have the same type"); + m_vErrMsg[ecUKNOWN_LOCALE] = _T("The chosen locale is not supported"); + m_vErrMsg[ecINVALID_TIME_FORMAT] = _T("Invalid time format on parameter(s). Please use the \"HH:MM:SS\" format."); } #if defined(_UNICODE) diff --git a/core/src/main/cpp/parser/mpTypes.h b/core/src/main/cpp/parser/mpTypes.h index 557d730..edcfbc3 100755 --- a/core/src/main/cpp/parser/mpTypes.h +++ b/core/src/main/cpp/parser/mpTypes.h @@ -370,9 +370,10 @@ enum EErrorCodes ecADD_HOURS_DATETIME = 57, ///< Invalid date time format for add_hours() first parameter ecINVALID_TYPES_MATCH = 58, + ecUKNOWN_LOCALE = 59, ///< The chosen locale is not supported // time related errors - ecINVALID_TIME_FORMAT = 59, ///< Invalid time format + ecINVALID_TIME_FORMAT = 60, ///< Invalid time format // The last two are special entries ecCOUNT, ///< This is no error code, It just stores the total number of error codes diff --git a/core/src/main/cpp/parser/mpValue.cpp b/core/src/main/cpp/parser/mpValue.cpp index fe5f752..1bfdd7d 100755 --- a/core/src/main/cpp/parser/mpValue.cpp +++ b/core/src/main/cpp/parser/mpValue.cpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "mpError.h" #include "mpValueCache.h" #include +#include MUP_NAMESPACE_START diff --git a/core/src/main/cpp/parser/suSortPred.h b/core/src/main/cpp/parser/suSortPred.h index 4e4a8f6..e855e21 100755 --- a/core/src/main/cpp/parser/suSortPred.h +++ b/core/src/main/cpp/parser/suSortPred.h @@ -44,7 +44,6 @@ namespace su */ template struct SortByLength - :public std::binary_function { bool operator()(const TString& a_sLeft, const TString& a_sRight) const {