xref: /openbmc/entity-manager/src/entity_manager/expression.cpp (revision 59ef1e72fbf8c8eef1d5108b790a30e745cadaee)
1*59ef1e72SChristopher Meis /*
2*59ef1e72SChristopher Meis // Copyright (c) 2017 Intel Corporation
3*59ef1e72SChristopher Meis // Copyright (c) 2022 IBM Corp.
4*59ef1e72SChristopher Meis //
5*59ef1e72SChristopher Meis // Licensed under the Apache License, Version 2.0 (the "License");
6*59ef1e72SChristopher Meis // you may not use this file except in compliance with the License.
7*59ef1e72SChristopher Meis // You may obtain a copy of the License at
8*59ef1e72SChristopher Meis //
9*59ef1e72SChristopher Meis //      http://www.apache.org/licenses/LICENSE-2.0
10*59ef1e72SChristopher Meis //
11*59ef1e72SChristopher Meis // Unless required by applicable law or agreed to in writing, software
12*59ef1e72SChristopher Meis // distributed under the License is distributed on an "AS IS" BASIS,
13*59ef1e72SChristopher Meis // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*59ef1e72SChristopher Meis // See the License for the specific language governing permissions and
15*59ef1e72SChristopher Meis // limitations under the License.
16*59ef1e72SChristopher Meis */
17*59ef1e72SChristopher Meis 
18*59ef1e72SChristopher Meis #include "expression.hpp"
19*59ef1e72SChristopher Meis 
20*59ef1e72SChristopher Meis #include <iostream>
21*59ef1e72SChristopher Meis #include <stdexcept>
22*59ef1e72SChristopher Meis 
23*59ef1e72SChristopher Meis namespace expression
24*59ef1e72SChristopher Meis {
parseOperation(std::string & op)25*59ef1e72SChristopher Meis std::optional<Operation> parseOperation(std::string& op)
26*59ef1e72SChristopher Meis {
27*59ef1e72SChristopher Meis     if (op == "+")
28*59ef1e72SChristopher Meis     {
29*59ef1e72SChristopher Meis         return Operation::addition;
30*59ef1e72SChristopher Meis     }
31*59ef1e72SChristopher Meis     if (op == "-")
32*59ef1e72SChristopher Meis     {
33*59ef1e72SChristopher Meis         return Operation::subtraction;
34*59ef1e72SChristopher Meis     }
35*59ef1e72SChristopher Meis     if (op == "*")
36*59ef1e72SChristopher Meis     {
37*59ef1e72SChristopher Meis         return Operation::multiplication;
38*59ef1e72SChristopher Meis     }
39*59ef1e72SChristopher Meis     if (op == R"(%)")
40*59ef1e72SChristopher Meis     {
41*59ef1e72SChristopher Meis         return Operation::modulo;
42*59ef1e72SChristopher Meis     }
43*59ef1e72SChristopher Meis     if (op == R"(/)")
44*59ef1e72SChristopher Meis     {
45*59ef1e72SChristopher Meis         return Operation::division;
46*59ef1e72SChristopher Meis     }
47*59ef1e72SChristopher Meis 
48*59ef1e72SChristopher Meis     return std::nullopt;
49*59ef1e72SChristopher Meis }
50*59ef1e72SChristopher Meis 
evaluate(int a,Operation op,int b)51*59ef1e72SChristopher Meis int evaluate(int a, Operation op, int b)
52*59ef1e72SChristopher Meis {
53*59ef1e72SChristopher Meis     switch (op)
54*59ef1e72SChristopher Meis     {
55*59ef1e72SChristopher Meis         case Operation::addition:
56*59ef1e72SChristopher Meis         {
57*59ef1e72SChristopher Meis             return a + b;
58*59ef1e72SChristopher Meis         }
59*59ef1e72SChristopher Meis         case Operation::subtraction:
60*59ef1e72SChristopher Meis         {
61*59ef1e72SChristopher Meis             return a - b;
62*59ef1e72SChristopher Meis         }
63*59ef1e72SChristopher Meis         case Operation::multiplication:
64*59ef1e72SChristopher Meis         {
65*59ef1e72SChristopher Meis             return a * b;
66*59ef1e72SChristopher Meis         }
67*59ef1e72SChristopher Meis         case Operation::division:
68*59ef1e72SChristopher Meis         {
69*59ef1e72SChristopher Meis             if (b == 0)
70*59ef1e72SChristopher Meis             {
71*59ef1e72SChristopher Meis                 throw std::runtime_error(
72*59ef1e72SChristopher Meis                     "Math error: Attempted to divide by Zero\n");
73*59ef1e72SChristopher Meis             }
74*59ef1e72SChristopher Meis             return a / b;
75*59ef1e72SChristopher Meis         }
76*59ef1e72SChristopher Meis         case Operation::modulo:
77*59ef1e72SChristopher Meis         {
78*59ef1e72SChristopher Meis             if (b == 0)
79*59ef1e72SChristopher Meis             {
80*59ef1e72SChristopher Meis                 throw std::runtime_error(
81*59ef1e72SChristopher Meis                     "Math error: Attempted to divide by Zero\n");
82*59ef1e72SChristopher Meis             }
83*59ef1e72SChristopher Meis             return a % b;
84*59ef1e72SChristopher Meis         }
85*59ef1e72SChristopher Meis 
86*59ef1e72SChristopher Meis         default:
87*59ef1e72SChristopher Meis             throw std::invalid_argument("Unrecognised operation");
88*59ef1e72SChristopher Meis     }
89*59ef1e72SChristopher Meis }
90*59ef1e72SChristopher Meis 
evaluate(int substitute,std::vector<std::string>::iterator curr,std::vector<std::string>::iterator & end)91*59ef1e72SChristopher Meis int evaluate(int substitute, std::vector<std::string>::iterator curr,
92*59ef1e72SChristopher Meis              std::vector<std::string>::iterator& end)
93*59ef1e72SChristopher Meis {
94*59ef1e72SChristopher Meis     bool isOperator = true;
95*59ef1e72SChristopher Meis     std::optional<Operation> next = Operation::addition;
96*59ef1e72SChristopher Meis 
97*59ef1e72SChristopher Meis     for (; curr != end; curr++)
98*59ef1e72SChristopher Meis     {
99*59ef1e72SChristopher Meis         if (isOperator)
100*59ef1e72SChristopher Meis         {
101*59ef1e72SChristopher Meis             next = expression::parseOperation(*curr);
102*59ef1e72SChristopher Meis             if (!next)
103*59ef1e72SChristopher Meis             {
104*59ef1e72SChristopher Meis                 break;
105*59ef1e72SChristopher Meis             }
106*59ef1e72SChristopher Meis         }
107*59ef1e72SChristopher Meis         else
108*59ef1e72SChristopher Meis         {
109*59ef1e72SChristopher Meis             try
110*59ef1e72SChristopher Meis             {
111*59ef1e72SChristopher Meis                 int constant = std::stoi(*curr);
112*59ef1e72SChristopher Meis                 substitute = evaluate(substitute, *next, constant);
113*59ef1e72SChristopher Meis             }
114*59ef1e72SChristopher Meis             catch (const std::invalid_argument&)
115*59ef1e72SChristopher Meis             {
116*59ef1e72SChristopher Meis                 std::cerr << "Parameter not supported for templates " << *curr
117*59ef1e72SChristopher Meis                           << "\n";
118*59ef1e72SChristopher Meis                 continue;
119*59ef1e72SChristopher Meis             }
120*59ef1e72SChristopher Meis         }
121*59ef1e72SChristopher Meis         isOperator = !isOperator;
122*59ef1e72SChristopher Meis     }
123*59ef1e72SChristopher Meis 
124*59ef1e72SChristopher Meis     end = curr;
125*59ef1e72SChristopher Meis     return substitute;
126*59ef1e72SChristopher Meis }
127*59ef1e72SChristopher Meis } // namespace expression
128