BPMN-OS
BPMN for optimization and simulation
Loading...
Searching...
No Matches
Expression.cpp
Go to the documentation of this file.
1#include "Expression.h"
5
6using namespace BPMNOS::Model;
7
8Expression::Expression(std::string expression, const AttributeRegistry& attributeRegistry, bool newTarget)
9 : attributeRegistry(attributeRegistry)
10 , expression(expression)
11 , compiled(getExpression(expression))
12 , type(getType())
13{
14 if ( auto name = compiled.getTarget(); name.has_value() ) {
15 if ( name.value() == BPMNOS::Keyword::Undefined ) {
16 throw std::runtime_error("Expression: illegal assignment '" + expression +"'");
17 }
18 if ( !newTarget ) {
19 target = attributeRegistry[ name.value() ];
20 }
21 }
22
23 for ( auto& name : compiled.getVariables() ) {
24 if ( name != BPMNOS::Keyword::Undefined ) {
25 auto attribute = attributeRegistry[ name ];
26 inputs.insert(attribute);
27 variables.push_back(attribute);
28 }
29 }
30 for ( auto& name : compiled.getCollections() ) {
31 if ( name == BPMNOS::Keyword::Undefined ) {
32 throw std::runtime_error("Expression: illegal expression '" + expression +"'");
33 }
34 auto attribute = attributeRegistry[ name ];
35 inputs.insert(attribute);
36 collections.push_back(attribute);
37 }
38}
39
40LIMEX::Expression<double> Expression::getExpression(const std::string& input) const {
41 try {
42 return LIMEX::Expression<double>(encodeQuotedStrings(input));
43 }
44 catch ( const std::exception& error ) {
45 throw std::runtime_error("Expression: illegal expression '" + input + "'.\n" + error.what());
46 }
47}
48
49Expression::Type Expression::getType() const {
50 auto& variableNames = compiled.getVariables();
51 assert( compiled.getRoot().operands.size() == 1 );
52 assert( compiled.getRoot().type == LIMEX::Type::group );
53
54 // check if any of the variables is named "undefined"
55 if ( std::find( variableNames.begin(), variableNames.end(), BPMNOS::Keyword::Undefined ) != variableNames.end() ) {
56 // only lhs == undefined, lhs != undefined, and lhs := undefined are allowed
57 auto& root = compiled.getRoot();
58 auto& node = std::get< LIMEX::Node<double> >(root.operands[0]);
59
60 if ( node.type == LIMEX::Type::assign ) {
61 assert( node.operands.size() == 1 );
62 if (
63 !std::holds_alternative< LIMEX::Node<double> >(node.operands[0]) ||
64 std::get< LIMEX::Node<double> >(node.operands[0]).type != LIMEX::Type::variable
65 ) {
66 throw std::runtime_error("Expression: illegal assignment '" + expression +"'");
67 }
68 return Type::UNASSIGN;
69 }
70
71 if ( node.type != LIMEX::Type::equal_to && node.type != LIMEX::Type::not_equal_to ) {
72 throw std::runtime_error("Expression: illegal expression '" + expression +"'");
73 }
74
75 assert( node.operands.size() == 2 );
76 assert( std::holds_alternative< LIMEX::Node<double> >(node.operands[0]) );
77 assert( std::holds_alternative< LIMEX::Node<double> >(node.operands[1]) );
78 auto& lhs = std::get< LIMEX::Node<double> >(node.operands[0]);
79 auto& rhs = std::get< LIMEX::Node<double> >(node.operands[1]);
80 assert( !lhs.operands.empty() );
81 assert( !rhs.operands.empty() );
82
83 if (
84 lhs.type != LIMEX::Type::variable ||
85 variableNames.at( std::get< size_t >(lhs.operands[0]) ) == BPMNOS::Keyword::Undefined ||
86 rhs.type != LIMEX::Type::variable ||
87 variableNames.at( std::get< size_t >(rhs.operands[0]) ) != BPMNOS::Keyword::Undefined
88 ) {
89 throw std::runtime_error("Expression: illegal comparison '" + expression +"'");
90 }
91
92 return node.type == LIMEX::Type::equal_to ? Type::IS_NULL : Type::IS_NOT_NULL;
93 }
94 // all variables must be defined
95 return Type::OTHER;
96}
97
99 assert( compiled.getRoot().operands.size() == 1 );
100 assert( compiled.getRoot().type == LIMEX::Type::group );
101 auto& root = compiled.getRoot();
102 auto& node = std::get< LIMEX::Node<double> >(root.operands[0]);
103 if ( node.type == LIMEX::Type::variable ) {
104 assert(inputs.size());
105 return *inputs.begin();
106 }
107 return nullptr;
108}
109
110template <typename DataType>
111std::optional<BPMNOS::number> Expression::execute(const BPMNOS::Values& status, const DataType& data, const BPMNOS::Values& globals) const {
112 if ( type == Type::UNASSIGN ) {
113 return std::nullopt;
114 }
115 if ( type == Type::IS_NULL ) {
116 assert(variables.size() == 1);
117 auto value = attributeRegistry.getValue(variables[0],status,data,globals);
118 return number( (double)!value.has_value() );
119 }
120 if ( type == Type::IS_NOT_NULL ) {
121 assert(variables.size() == 1);
122 auto value = attributeRegistry.getValue(variables[0],status,data,globals);
123 return number( (double)value.has_value() );
124 }
125
126 // collect variable values
127 std::vector< double > variableValues;
128 for ( auto attribute : variables ) {
129 auto value = attributeRegistry.getValue(attribute,status,data,globals);
130 if ( !value.has_value() ) {
131 // return nullopt because required attribute value is not given
132 return std::nullopt;
133 }
134 variableValues.push_back( (double)value.value() );
135 }
136
137 // collect values of all variables in collection
138 std::vector< std::vector< double > > collectionValues;
139 for ( auto attribute : collections ) {
140 collectionValues.push_back( {} );
141 auto collection = attributeRegistry.getValue(attribute,status,data,globals);
142 if ( !collection.has_value() ) {
143 // return nullopt because required collection is not given
144 return std::nullopt;
145 }
146 for ( auto value : collectionRegistry[(size_t)collection.value()].values ) {
147 if ( !value.has_value() ) {
148 // return nullopt because a value in required collection is missing
149 return std::nullopt;
150 }
151 collectionValues.back().push_back( (double)value.value() );
152 }
153 }
154
155 return number(compiled.evaluate(variableValues,collectionValues));
156}
157
158template std::optional<BPMNOS::number> Expression::execute<BPMNOS::Values>(const BPMNOS::Values& status, const BPMNOS::Values& data, const BPMNOS::Values& globals) const;
159template std::optional<BPMNOS::number> Expression::execute<BPMNOS::SharedValues>(const BPMNOS::Values& status, const BPMNOS::SharedValues& data, const BPMNOS::Values& globals) const;
160
CollectionRegistry collectionRegistry
std::optional< BPMNOS::number > getValue(const Attribute *attribute, const Values &status, const Values &data, const Values &globals) const
const AttributeRegistry & attributeRegistry
Definition Expression.h:21
Expression(const std::string expression, const AttributeRegistry &attributeRegistry, bool newTarget=false)
Definition Expression.cpp:8
const Attribute * isAttribute() const
Returns pointer to the attribute if and only if expression contains nothing else.
std::set< const Attribute * > inputs
Vector containing all input attributes and collections used by the expression.
Definition Expression.h:26
std::optional< const Attribute * > target
Definition Expression.h:25
const LIMEX::Expression< double > compiled
Definition Expression.h:23
std::vector< const Attribute * > variables
Vector containing all input attributes used by the expression.
Definition Expression.h:27
const std::string expression
Definition Expression.h:22
std::vector< const Attribute * > collections
Vector containing all input collections used by the expression.
Definition Expression.h:28
std::optional< BPMNOS::number > execute(const BPMNOS::Values &status, const DataType &data, const BPMNOS::Values &globals) const
const std::string Undefined
Definition Keywords.h:10
std::string encodeQuotedStrings(std::string text)
BPMNOS_NUMBER_TYPE number
Definition Number.h:42