blob: 1a8f7e39721f8570a48760645eecb40a46fb8e80 [file] [log] [blame]
#include "tlbmc/configs/expression.h"
#include <cstddef>
#include <string>
#include <string_view>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_replace.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "g3/macros.h"
namespace milotic_tlbmc {
constexpr absl::string_view kExpressionTokens = "0123456789+-*/";
absl::StatusOr<std::string> EvaluateStrExpressionSubstitution(
absl::string_view expression, absl::string_view sub_key,
absl::string_view sub_value) {
size_t start = expression.find(sub_key);
std::string expression_subbed =
absl::StrReplaceAll(expression, {{sub_key, sub_value}}).substr(start);
ECCLESIA_ASSIGN_OR_RETURN(std::string result,
EvaluateStrExpression(expression_subbed));
return absl::StrCat(expression.substr(0, start), result);
}
absl::StatusOr<std::string> EvaluateStrExpression(
absl::string_view expression) {
std::vector<absl::string_view> tokens =
absl::StrSplit(expression, ' ', absl::SkipEmpty());
if (tokens.empty()) {
return absl::InvalidArgumentError(
"Invalid expression: Expression is empty");
}
std::string remainder;
int result;
if (!absl::SimpleAtoi(tokens[0], &result)) {
// The substituted expression is not an integer expression, return as is.
return absl::StrCat(expression);
}
for (std::vector<absl::string_view>::iterator it = tokens.begin() + 1;
it != tokens.end(); it += 2) {
// If the current token is not a valid expression token, reached the end of
// the expression, return the remainder.
if (it->find_first_not_of(kExpressionTokens) != std::string::npos) {
remainder = absl::StrJoin(it, tokens.end(), " ");
break;
}
absl::string_view op_str = *it;
if (op_str.size() != 1) {
return absl::InvalidArgumentError(
absl::StrCat("Invalid expression: Illformed expression: ", expression,
" invalid operator: ", op_str));
}
char op = op_str[0];
int operand = 0;
if (it + 1 >= tokens.end() || !absl::SimpleAtoi(*(it + 1), &operand)) {
return absl::InvalidArgumentError(
absl::StrCat("Invalid expression: Illformed expression: ", expression,
" hanging operator: ", op_str));
}
if (op == '+') {
result += operand;
} else if (op == '-') {
result -= operand;
} else if (op == '*') {
result *= operand;
} else if (op == '/') {
if (operand == 0) {
return absl::InvalidArgumentError(
absl::StrCat("Invalid expression: Division by zero: ", expression));
}
result /= operand;
} else {
return absl::InvalidArgumentError(
absl::StrCat("Invalid expression: Illformed expression: ", expression,
" invalid operator: ", op_str));
}
}
return remainder.empty() ? absl::StrCat(result)
: absl::StrCat(result, " ", remainder);
}
} // namespace milotic_tlbmc