1
/* PeTe - Petri Engine exTremE
2
* Copyright (C) 2011 Jonas Finnemann Jensen <jopsen@gmail.com>,
3
* Thomas Søndersø Nielsen <primogens@gmail.com>,
4
* Lars Kærlund Østergaard <larsko@gmail.com>,
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19
#include "ValidationBuilder.h"
21
#include "PQL/PQLParser.h"
22
#include "PQL/Contexts.h"
30
namespace PetriEngine{
33
/** Auxiliary function for converting into to string */
34
inline string int2string(int i){
40
ValidationBuilder::ValidationBuilder() : AbstractPetriNetBuilder() {}
42
void ValidationBuilder::addVariable(const std::string& name,
45
_varNames.push_back(name);
46
if(initialValue > range){ //TODO: Figure out if this is > or >=
47
string msg = "Initial value " + int2string(initialValue)
48
+ " is larger than range " + int2string(range);
49
_errors.push_back(ValidationError(name, msg));
53
void ValidationBuilder::addPlace(const std::string& name,
57
_placeNames.push_back(name);
59
string msg = "Initial marking " + int2string(tokens)
60
+ " is less than zero";
61
_errors.push_back(ValidationError(name, msg));
65
void ValidationBuilder::addTransition(const std::string& name,
66
const std::string& conditions,
67
const std::string& assignments,
70
_transitionNames.push_back(name);
71
_conditions.push_back(conditions);
72
_assignments.push_back(assignments);
75
void ValidationBuilder::addInputArc(const std::string& place,
76
const std::string& transition,
78
_inputArcs.push_back(Arc(place, transition));
80
string msg = "Weight is " + int2string(weight)
81
+ " is less than zero";
82
_errors.push_back(ValidationError(place, transition, msg));
86
void ValidationBuilder::addOutputArc(const std::string& transition,
87
const std::string& place,
89
_outputArcs.push_back(Arc(transition, place));
91
string msg = "Weight is " + int2string(weight)
92
+ " is less than zero";
93
_errors.push_back(ValidationError(transition, place, msg));
97
/** Get the number of matching identifiers */
98
int ValidationBuilder::countMatchingIds(const std::string& id){
100
for(size_t i = 0; i < _varNames.size(); i++)
101
if(_varNames[i] == id) count++;
102
for(size_t i = 0; i < _placeNames.size(); i++)
103
if(_placeNames[i] == id) count++;
104
for(size_t i = 0; i < _transitionNames.size(); i++)
105
if(_transitionNames[i] == id) count++;
109
bool ValidationBuilder::validate(){
110
//Check for duplicate identifiers
111
set<string> reportedDuplicates; //Use a set to avoid reporting them more than once
112
//Check variable names
113
for(size_t i = 0; i < _varNames.size(); i++){
114
const string& id = _varNames[i];
115
int count = countMatchingIds(id);
117
if(count > 1 && reportedDuplicates.count(id) == 0){
118
reportedDuplicates.insert(id);
119
_errors.push_back(ValidationError(id,
120
"The identifiers must be unique, \""
121
+ id + "\" is shared by "
122
+ int2string(count) + " entities"));
126
for(size_t i = 0; i < _placeNames.size(); i++){
127
const string& id = _placeNames[i];
128
int count = countMatchingIds(id);
130
if(count > 1 && reportedDuplicates.count(id) == 0){
131
reportedDuplicates.insert(id);
132
_errors.push_back(ValidationError(id,
133
"The identifiers must be unique, \""
134
+ id + "\" is shared by "
135
+ int2string(count) + " entities"));
138
//Check transition names
139
for(size_t i = 0; i < _transitionNames.size(); i++){
140
const string& id = _transitionNames[i];
141
int count = countMatchingIds(id);
143
if(count > 1 && reportedDuplicates.count(id) == 0){
144
reportedDuplicates.insert(id);
145
_errors.push_back(ValidationError(id,
146
"The identifiers must be unique, \""
147
+ id + "\" is shared by "
148
+ int2string(count) + " entities"));
152
//Check all input arcs
153
for(size_t i = 0; i < _inputArcs.size(); i++){
154
const Arc& arc = _inputArcs[i];
155
bool foundPlace = false;
156
bool foundTransition = false;
158
for(size_t j = 0; j < _placeNames.size(); j++){
159
foundPlace |= _placeNames[j] == arc.start;
160
if(foundPlace) break;
162
//Look for transition
163
for(size_t j = 0; j < _transitionNames.size(); j++){
164
foundTransition |= _transitionNames[j] == arc.end;
165
if(foundTransition) break;
168
if(!foundPlace || !foundTransition){
170
if(!foundPlace && !foundTransition)
171
msg = "Neigther end-points found";
173
msg = "Start-place \"" + arc.start + "\" not found";
175
msg = "End-transition \"" + arc.end + "\" not found";
176
_errors.push_back(ValidationError(arc.start,
181
//Check all output arcs
182
for(size_t i = 0; i < _outputArcs.size(); i++){
183
const Arc& arc = _outputArcs[i];
184
bool foundPlace = false;
185
bool foundTransition = false;
186
//Look for transition
187
for(size_t j = 0; j < _transitionNames.size(); j++){
188
foundTransition |= _transitionNames[j] == arc.start;
189
if(foundTransition) break;
192
for(size_t j = 0; j < _placeNames.size(); j++){
193
foundPlace |= _placeNames[j] == arc.end;
194
if(foundPlace) break;
197
if(!foundPlace || !foundTransition){
199
if(!foundPlace && !foundTransition)
200
msg = "Neither end-points found";
202
msg = "End-place \"" + arc.end + "\" not found";
204
msg = "Start-transition \"" + arc.start + "\" not found";
205
_errors.push_back(ValidationError(arc.start,
211
//Attempt to parse all non-empty conditions
212
for(size_t i = 0; i < _conditions.size(); i++){
213
if(_conditions[i].empty()) continue;
214
PQL::Condition* cond = PQL::ParseQuery(_conditions[i]);
216
PQL::AnalysisContext context(_placeNames, _varNames);
217
cond->analyze(context);
218
for(size_t j = 0; j < context.errors().size(); j++){
219
_errors.push_back(ValidationError(_transitionNames[i],
226
_errors.push_back(ValidationError(_transitionNames[i],
227
"Unable to parse non-empty condition"));
229
//Attempt to parse all non-empty assignments
230
for(size_t i = 0; i < _assignments.size(); i++){
231
if(_assignments[i].empty()) continue;
232
PQL::AssignmentExpression* a = PQL::ParseAssignment(_assignments[i]);
234
PQL::AnalysisContext context(_placeNames, _varNames);
236
for(size_t j = 0; j < context.errors().size(); j++){
237
_errors.push_back(ValidationError(_transitionNames[i],
244
_errors.push_back(ValidationError(_transitionNames[i],
245
"Unable to parse non-empty assignment"));
248
return _errors.empty();