Refactored function validators
This commit is contained in:
parent
e7fd7df154
commit
05fa2abbb0
|
@ -1,3 +1,4 @@
|
|||
#include <algorithm>
|
||||
#include "addressspace.h"
|
||||
|
||||
namespace domain {
|
||||
|
|
|
@ -61,7 +61,7 @@ std::optional<ValidationError> ComdelValidator::validateRule(Rule rule, Validati
|
|||
RuleContext ruleContext;
|
||||
ruleContext.addressSpaces = context.addressSpaces;
|
||||
ruleContext.attributes = context.attributes;
|
||||
ruleContext.function = callbacks;
|
||||
ruleContext.function = validators;
|
||||
auto action = rule.evaluate(ruleContext);
|
||||
if (action) {
|
||||
std::string message = this->populateMessage(action->getMessage(), context);
|
||||
|
|
|
@ -29,14 +29,19 @@ public:
|
|||
std::vector<ValidationError> validateAttribute(InstanceAttribute *attribute, ValidationContext context);
|
||||
std::optional<ValidationError> validateRule(Rule rule, ValidationContext context);
|
||||
|
||||
ComdelValidator(std::map<std::string, FunctionCallback> callbacks): callbacks(callbacks) {}
|
||||
ComdelValidator(std::vector<FunctionValidator*> validators) {
|
||||
for(auto* validator: validators) {
|
||||
validator->clear();
|
||||
this->validators.insert(std::make_pair(validator->getName(), validator));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, FunctionCallback> callbacks;
|
||||
std::map<std::string, FunctionValidator*> validators;
|
||||
|
||||
std::string populateMessage(string basicString, ValidationContext context);
|
||||
std::string populateMessage(string message, ValidationContext context);
|
||||
|
||||
string replacePlaceholder(string basicString, const string basicString1, Value value);
|
||||
string replacePlaceholder(string message, const string name, Value value);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,45 +1,138 @@
|
|||
#include <map>
|
||||
#include "functionsignature.h"
|
||||
|
||||
namespace domain {
|
||||
|
||||
FunctionSignature add(std::string name, std::vector<Value::ValueType> types, FunctionCallback callback) {
|
||||
return {name, types, callback};
|
||||
class DivisibleValidator: public FunctionValidator {
|
||||
public:
|
||||
DivisibleValidator(): FunctionValidator("divisible", {Value::INT, Value::INT}) {}
|
||||
|
||||
bool validate(std::vector<Value> values) override {
|
||||
if(validateSignature(values)) {
|
||||
long long first = values[0].asInt();
|
||||
long long second = values[1].asInt();
|
||||
return (first % second) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void clear() override {}
|
||||
};
|
||||
|
||||
class LessThenValidator: public FunctionValidator {
|
||||
public:
|
||||
LessThenValidator(): FunctionValidator("less_then", {Value::INT, Value::INT}) {}
|
||||
|
||||
bool validate(std::vector<Value> values) override {
|
||||
if(validateSignature(values)) {
|
||||
long long first = values[0].asInt();
|
||||
long long second = values[1].asInt();
|
||||
return first < second;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void clear() override {}
|
||||
};
|
||||
|
||||
class GreaterThenValidator: public FunctionValidator {
|
||||
public:
|
||||
GreaterThenValidator(): FunctionValidator("greater_then", {Value::INT, Value::INT}) {}
|
||||
|
||||
bool validate(std::vector<Value> values) override {
|
||||
if(validateSignature(values)) {
|
||||
long long first = values[0].asInt();
|
||||
long long second = values[1].asInt();
|
||||
return first > second;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void clear() override {}
|
||||
};
|
||||
|
||||
|
||||
class ContainsAddressValidator: public FunctionValidator {
|
||||
public:
|
||||
ContainsAddressValidator(): FunctionValidator("contains_address", {Value::ADDRESS_SPACE, Value::INT}) {}
|
||||
|
||||
bool validate(std::vector<Value> values) override {
|
||||
if(validateSignature(values)) {
|
||||
AddressSpace space = values[0].asAddressSpace();
|
||||
long long address = values[1].asInt();
|
||||
return space.contains(address);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void clear() override {}
|
||||
};
|
||||
|
||||
|
||||
class ContainsValidator: public FunctionValidator {
|
||||
public:
|
||||
ContainsValidator(): FunctionValidator("contains", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {}
|
||||
|
||||
bool validate(std::vector<Value> values) override {
|
||||
if(validateSignature(values)) {
|
||||
AddressSpace space = values[0].asAddressSpace();
|
||||
long long start = values[1].asInt();
|
||||
long long size = values[1].asInt();
|
||||
return space.contains(start, start + size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void clear() override {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class UniqueValidator: public FunctionValidator {
|
||||
|
||||
private:
|
||||
std::map<std::string, std::vector<std::pair<long long int, long long int>>> spaces;
|
||||
|
||||
bool overlaps(long long int start1, long long int end1, long long int start2, long long int end2) {
|
||||
return std::max((long long int)0, std::min(end1, end2) - std::max(start1, start2)) > 0;
|
||||
}
|
||||
|
||||
public:
|
||||
UniqueValidator(): FunctionValidator("unique", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {}
|
||||
|
||||
bool validate(std::vector<Value> values) override {
|
||||
if(validateSignature(values)) {
|
||||
std::string space = values[0].asAddressSpace().getName();
|
||||
long long int start = values[1].asInt();
|
||||
long long int end = start + values[2].asInt();
|
||||
if(spaces.count(space) == 0) {
|
||||
spaces.insert(std::make_pair(space, std::vector<std::pair<long long int, long long int>>{}));
|
||||
}
|
||||
for(auto& s: spaces[space]) {
|
||||
if(overlaps(s.first, s.second, start, end)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
spaces[space].push_back(std::make_pair(start, end));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void clear() override {
|
||||
spaces.clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
std::vector<FunctionValidator*> getSupportedValidators() {
|
||||
std::vector<FunctionValidator*> validators;
|
||||
|
||||
validators.push_back(new DivisibleValidator());
|
||||
validators.push_back(new LessThenValidator());
|
||||
validators.push_back(new GreaterThenValidator());
|
||||
validators.push_back(new ContainsAddressValidator());
|
||||
validators.push_back(new ContainsValidator());
|
||||
validators.push_back(new UniqueValidator());
|
||||
|
||||
return validators;
|
||||
}
|
||||
|
||||
std::vector<FunctionSignature> getSupportedFunctions() {
|
||||
std::vector<FunctionSignature> s;
|
||||
s.push_back(add("divisible", std::vector<Value::ValueType>{Value::INT, Value::INT},[](std::vector<Value> values) {
|
||||
long long first = values[0].asInt();
|
||||
long long second = values[1].asInt();
|
||||
return (first % second) == 0;
|
||||
}));
|
||||
s.push_back(add("less_then", std::vector<Value::ValueType>{Value::INT, Value::INT}, [](std::vector<Value> values) {
|
||||
long long first = values[0].asInt();
|
||||
long long second = values[1].asInt();
|
||||
return first < second;
|
||||
}));
|
||||
s.push_back(add("greater_then", std::vector<Value::ValueType>{Value::INT, Value::INT}, [](std::vector<Value> values) {
|
||||
long long first = values[0].asInt();
|
||||
long long second = values[1].asInt();
|
||||
return first > second;
|
||||
}));
|
||||
s.push_back(add("contains_address", std::vector<Value::ValueType>{Value::ADDRESS_SPACE, Value::INT}, [](std::vector<Value> values) {
|
||||
AddressSpace space = values[0].asAddressSpace();
|
||||
long long address = values[1].asInt();
|
||||
return space.contains(address);
|
||||
}));
|
||||
s.push_back(add("contains", std::vector<Value::ValueType>{Value::ADDRESS_SPACE, Value::INT, Value::INT}, [](std::vector<Value> values) {
|
||||
AddressSpace space = values[0].asAddressSpace();
|
||||
long long start = values[1].asInt();
|
||||
long long size = values[1].asInt();
|
||||
return space.contains(start, start + size);
|
||||
}));
|
||||
s.push_back(add("unique", std::vector<Value::ValueType>{Value::ADDRESS_SPACE, Value::INT, Value::INT}, [](std::vector<Value> values) {
|
||||
return true;
|
||||
}));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
} // namespace domain
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef DOMAIN_FUNCTION_SIGNATURE_H
|
||||
#define DOMAIN_FUNCTION_SIGNATURE_H
|
||||
#ifndef DOMAIN_FUNCTION_VALIDATOR_H
|
||||
#define DOMAIN_FUNCTION_VALIDATOR_H
|
||||
|
||||
#include<functional>
|
||||
#include<vector>
|
||||
|
@ -8,18 +8,46 @@
|
|||
|
||||
namespace domain {
|
||||
|
||||
typedef std::function<bool (std::vector<Value>)> FunctionCallback;
|
||||
|
||||
struct FunctionSignature {
|
||||
class FunctionValidator {
|
||||
private:
|
||||
std::string name;
|
||||
std::vector<Value::ValueType> params;
|
||||
FunctionCallback callback;
|
||||
std::vector<Value::ValueType> signature;
|
||||
|
||||
FunctionSignature(std::string name, std::vector<Value::ValueType> params, FunctionCallback callback): name(name), params(params), callback(callback) {}
|
||||
protected:
|
||||
FunctionValidator(std::string name, std::vector<Value::ValueType> signature) {
|
||||
this->name = name;
|
||||
this->signature = signature;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
std::string getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
std::vector<Value::ValueType> getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
bool validateSignature(std::vector<Value> signature) {
|
||||
if(this->signature.size() != signature.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int i=0; i<this->signature.size(); i++) {
|
||||
if(this->signature[i] != signature[i].getType()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool validate(std::vector<Value> values) = 0;
|
||||
virtual void clear() = 0;
|
||||
};
|
||||
|
||||
std::vector<FunctionSignature> getSupportedFunctions();
|
||||
std::vector<FunctionValidator*> getSupportedValidators();
|
||||
|
||||
} // namespace domain
|
||||
|
||||
#endif // DOMAIN_FUNCTIONSIGNATURE_H
|
||||
#endif // DOMAIN_FUNCTION_VALIDATOR_H
|
||||
|
|
|
@ -17,7 +17,7 @@ bool Condition::evaluate(RuleContext &context) {
|
|||
request.push_back(params[i]);
|
||||
}
|
||||
}
|
||||
bool result = context.function[function](request);
|
||||
bool result = context.function[function]->validate(request);
|
||||
return negated ? !result : result;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace domain {
|
|||
struct RuleContext {
|
||||
std::map<std::string, AddressSpace> addressSpaces;
|
||||
std::map<std::string, Value> attributes;
|
||||
std::map<std::string, FunctionCallback> function;
|
||||
std::map<std::string, FunctionValidator*> function;
|
||||
};
|
||||
|
||||
class Condition {
|
||||
|
|
|
@ -102,8 +102,8 @@ Popup::PopupType toType(PopupNode::PopupType type)
|
|||
return Popup::ON_DEMAND;
|
||||
}
|
||||
|
||||
SchemaCreator::SchemaCreator(std::vector<FunctionSignature> signatures)
|
||||
: signatures(std::move(signatures))
|
||||
SchemaCreator::SchemaCreator(std::vector<FunctionValidator*> validators)
|
||||
: validators(std::move(validators))
|
||||
{}
|
||||
|
||||
std::optional<Library> SchemaCreator::loadLibrary(LibraryNode node)
|
||||
|
@ -736,19 +736,19 @@ std::optional<Condition> SchemaCreator::loadCondition(ConditionNode node)
|
|||
{
|
||||
std::string function = node.functionName.value;
|
||||
|
||||
for(auto & signature : signatures) {
|
||||
if(signature.name == function) {
|
||||
if(signature.params.size() == node.params.size()) {
|
||||
for(auto & validator : validators) {
|
||||
if(validator->getName() == function) {
|
||||
if(validator->getSignature().size() == node.params.size()) {
|
||||
std::vector<Value> params;
|
||||
for(uint j=0; j<signature.params.size(); j++) {
|
||||
for(uint j=0; j<validator->getSignature().size(); j++) {
|
||||
bool exists = false;
|
||||
auto type = toType(node.params[j]);
|
||||
if (type.getType() == Value::UNDEFINED) {
|
||||
if(current().doesAttributeExists(type.asReference(), signature.params[j])) {
|
||||
if(current().doesAttributeExists(type.asReference(), validator->getSignature()[j])) {
|
||||
exists = true;
|
||||
type = Value::fromReference(type.asReference(), Value::ATTRIBUTE_REFERENCE);
|
||||
}
|
||||
if(signature.params[j] == Value::ADDRESS_SPACE) {
|
||||
if(validator->getSignature()[j] == Value::ADDRESS_SPACE) {
|
||||
if(hasAddressSpace(type.asReference())) {
|
||||
exists = true;
|
||||
type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE_REFERENCE);
|
||||
|
|
|
@ -61,7 +61,7 @@ class SchemaCreator
|
|||
|
||||
|
||||
std::vector<SourceError> errors;
|
||||
std::vector<FunctionSignature> signatures;
|
||||
std::vector<FunctionValidator*> validators;
|
||||
|
||||
std::optional<AddressSpace> loadAddressSpace(AddressSpaceNode node);
|
||||
std::optional<Component> loadComponent(ComponentNode node);
|
||||
|
@ -130,7 +130,7 @@ class SchemaCreator
|
|||
}
|
||||
|
||||
public:
|
||||
SchemaCreator(std::vector<FunctionSignature> signatures);
|
||||
SchemaCreator(std::vector<FunctionValidator*> validators);
|
||||
|
||||
std::vector<SourceError> getErrors() {
|
||||
return errors;
|
||||
|
|
|
@ -24,7 +24,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
setupUi();
|
||||
|
||||
// define allowed methods
|
||||
signatures = domain::getSupportedFunctions();
|
||||
validators = domain::getSupportedValidators();
|
||||
}
|
||||
|
||||
void MainWindow::setupUi()
|
||||
|
@ -79,7 +79,7 @@ void MainWindow::onLoadLibrary() {
|
|||
ParseContext parseContext;
|
||||
auto libraryNode = loadLibraryFromFile(&parseContext, filename.toStdString().c_str(), buffer);
|
||||
if(libraryNode) {
|
||||
domain::SchemaCreator generator(signatures);
|
||||
domain::SchemaCreator generator(validators);
|
||||
library = generator.loadLibrary(*libraryNode);
|
||||
|
||||
for (auto& error : generator.getErrors()) {
|
||||
|
@ -117,7 +117,7 @@ void MainWindow::onLoadSchema() {
|
|||
auto schemaNode = loadSchemaFromFile(&parseContext, filename.toStdString().c_str(), buffer);
|
||||
|
||||
if(schemaNode) {
|
||||
domain::SchemaCreator generator(signatures);
|
||||
domain::SchemaCreator generator(validators);
|
||||
library = generator.loadLibrary(*schemaNode->library);
|
||||
|
||||
librarySource = schemaNode->source->value;
|
||||
|
@ -190,13 +190,7 @@ void MainWindow::onValidateSchema(bool /*toggled*/) {
|
|||
|
||||
this->validationErrors.clear();
|
||||
|
||||
std::map<std::string, domain::FunctionCallback> callbacks;
|
||||
auto functions = domain::getSupportedFunctions();
|
||||
for(auto &func: functions) {
|
||||
callbacks[func.name] = func.callback;
|
||||
}
|
||||
|
||||
domain::ComdelValidator validator{callbacks};
|
||||
domain::ComdelValidator validator{validators};
|
||||
|
||||
domain::ValidationContext context;
|
||||
context.instance = nullptr;
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
std::optional<domain::Library> library = std::nullopt;
|
||||
domain::Schema* schema = nullptr;
|
||||
|
||||
std::vector<domain::FunctionSignature> signatures;
|
||||
std::vector<domain::FunctionValidator*> validators;
|
||||
|
||||
void setupUi();
|
||||
void clear();
|
||||
|
|
Loading…
Reference in New Issue