| #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 |