Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions core/src/main/cpp/parser/equationsParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include "equationsParser.h"

#include <string>
#include <iostream>
#include <cmath>
#include <vector>

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<string> equations, vector<string> &out) {
for(string equation : equations) {
out.push_back(CalcJson(equation));
}
}

EQUATIONS_PARSER_END
21 changes: 21 additions & 0 deletions core/src/main/cpp/parser/equationsParser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef EQUATIONS_PARSER_H
#define EQUATIONS_PARSER_H

#include <string>
//--- 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<std::string> in, std::vector<std::string> &out);

EQUATIONS_PARSER_END

#endif
129 changes: 129 additions & 0 deletions core/src/main/cpp/parser/mpFuncCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,4 +828,133 @@ MUP_NAMESPACE_START
return new FunTimeDiff(*this);
}

//------------------------------------------------------------------------------
// |
// Functions for regex matching |
// Usage: regex("string", "regex") |
// |
//------------------------------------------------------------------------------

FunRegex::FunRegex()
:ICallback(cmFUNC, _T("regex"), -1)
{}

std::vector<std::vector<std::string>> capture_regex_groups(const std::string& input, const std::string& pattern) {
std::vector<std::vector<std::string>> 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<std::string> 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);
}

MUP_NAMESPACE_END
26 changes: 26 additions & 0 deletions core/src/main/cpp/parser/mpFuncCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,32 @@ MUP_NAMESPACE_START
virtual IToken* Clone() const override;
}; // class FunTimeDiff

//------------------------------------------------------------------------------
/** \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

MUP_NAMESPACE_END

#endif
Loading