Added rule validation
This commit is contained in:
1 parent
23e63f7b6f
commit
e8505f9cef
13 files changed
+284
-13
No files matched your search
@@ -16,4 +16,12 @@ long long AddressSpace::getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
bool AddressSpace::contains(long long int address) {
|
||||
return address >= start && address < end;
|
||||
}
|
||||
|
||||
bool AddressSpace::contains(long long int pstart, long long int pend) {
|
||||
return pstart >= start && pend < end;
|
||||
}
|
||||
|
||||
} // namespace domain
|
||||
@@ -17,6 +17,9 @@ public:
|
||||
std::string getName();
|
||||
long long getStart();
|
||||
long long getEnd();
|
||||
|
||||
bool contains(long long int address);
|
||||
bool contains(long long int start, long long int end);
|
||||
};
|
||||
|
||||
} // namespace domain
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "comdelvalidator.h"
|
||||
|
||||
namespace domain {
|
||||
|
||||
std::vector<ValidationError> ComdelValidator::validateSchema(Schema &schema, ValidationContext context) {
|
||||
std::vector<ValidationError> errors;
|
||||
|
||||
context.instance = nullptr;
|
||||
context.attribute = nullptr;
|
||||
|
||||
for(auto &inst: schema.instances) {
|
||||
auto *instance = dynamic_cast<ComponentInstance*>(inst);
|
||||
if(instance) {
|
||||
auto result = validateComponent(instance, context);
|
||||
errors.insert(errors.end(), result.begin(), result.end());
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
std::vector<ValidationError> ComdelValidator::validateComponent(ComponentInstance *instance, ValidationContext context) {
|
||||
std::vector<ValidationError> errors;
|
||||
|
||||
context.instance = instance;
|
||||
context.attributes.clear();
|
||||
|
||||
for(auto &attribute: instance->attributes) {
|
||||
context.attributes[attribute->name] = attribute->value;
|
||||
}
|
||||
|
||||
for(auto &rule: instance->component.getRules()) {
|
||||
auto result = validateRule(rule, context);
|
||||
if(result) {
|
||||
errors.push_back(*result);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &attribute: instance->attributes) {
|
||||
auto result = validateAttribute(attribute, context);
|
||||
errors.insert(errors.end(), result.begin(), result.end());
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
std::vector<ValidationError> ComdelValidator::validateAttribute(InstanceAttribute *attribute, ValidationContext context) {
|
||||
std::vector<ValidationError> errors;
|
||||
if(attribute->attribute.getPopup()) {
|
||||
Popup popup = *attribute->attribute.getPopup();
|
||||
context.attribute = attribute;
|
||||
context.attributes = std::map<std::string, Value>{{attribute->name, attribute->value}};
|
||||
|
||||
for(auto &rule: popup.getRules()) {
|
||||
auto result = validateRule(rule, context);
|
||||
if(result) {
|
||||
errors.push_back(*result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
std::optional<ValidationError> ComdelValidator::validateRule(Rule rule, ValidationContext context) {
|
||||
RuleContext ruleContext;
|
||||
ruleContext.addressSpaces = context.addressSpaces;
|
||||
ruleContext.attributes = context.attributes;
|
||||
ruleContext.function = callbacks;
|
||||
auto action = rule.evaluate(ruleContext);
|
||||
if (action) {
|
||||
std::string message = this->populateMessage(action->getMessage(), context);
|
||||
return ValidationError{context.instance, context.attribute, action->getType(), message};
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
std::string ComdelValidator::populateMessage(string source, ValidationContext context) {
|
||||
for(auto &[key, value]: context.attributes) {
|
||||
source = replacePlaceholder(source, key, value);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
string ComdelValidator::replacePlaceholder(string source, string key, Value value) {
|
||||
key = "{" + key + "}";
|
||||
auto placeholderValue = value.string();
|
||||
|
||||
auto found = source.find(key);
|
||||
while(found != string::npos) {
|
||||
source.replace(found, key.length(), placeholderValue);
|
||||
found = source.find(key);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef COMDEL_VALIDATOR_H
|
||||
#define COMDEL_VALIDATOR_H
|
||||
|
||||
#include "instance.h"
|
||||
#include "schema.h"
|
||||
|
||||
namespace domain {
|
||||
|
||||
struct ValidationError
|
||||
{
|
||||
Instance *instance;
|
||||
InstanceAttribute *attribute;
|
||||
Action::ActionType type;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
struct ValidationContext {
|
||||
Instance *instance;
|
||||
InstanceAttribute *attribute;
|
||||
std::map<std::string, AddressSpace> addressSpaces;
|
||||
std::map<std::string, Value> attributes;
|
||||
};
|
||||
|
||||
class ComdelValidator
|
||||
{
|
||||
public:
|
||||
std::vector<ValidationError> validateSchema(Schema& schema, ValidationContext context);
|
||||
std::vector<ValidationError> validateComponent(ComponentInstance *instance, ValidationContext context);
|
||||
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) {}
|
||||
|
||||
private:
|
||||
std::map<std::string, FunctionCallback> callbacks;
|
||||
|
||||
std::string populateMessage(string basicString, ValidationContext context);
|
||||
|
||||
string replacePlaceholder(string basicString, const string basicString1, Value value);
|
||||
};
|
||||
|
||||
}
|
||||
#endif //COMDEL_VALIDATOR_H
|
||||
@@ -2,4 +2,44 @@
|
||||
|
||||
namespace domain {
|
||||
|
||||
FunctionSignature add(std::string name, std::vector<Value::ValueType> types, FunctionCallback callback) {
|
||||
return {name, types, callback};
|
||||
}
|
||||
|
||||
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
|
||||
@@ -11,10 +11,13 @@ typedef std::function<bool (std::vector<Value>)> FunctionCallback;
|
||||
struct FunctionSignature {
|
||||
std::string name;
|
||||
std::vector<Value::ValueType> params;
|
||||
FunctionCallback callback;
|
||||
|
||||
FunctionSignature(std::string name, std::vector<Value::ValueType> params): name(name), params(params) {}
|
||||
FunctionSignature(std::string name, std::vector<Value::ValueType> params, FunctionCallback callback): name(name), params(params), callback(callback) {}
|
||||
};
|
||||
|
||||
std::vector<FunctionSignature> getSupportedFunctions();
|
||||
|
||||
} // namespace domain
|
||||
|
||||
#endif // DOMAIN_FUNCTIONSIGNATURE_H
|
||||
@@ -9,7 +9,9 @@ Condition::Condition(std::string function, std::vector<Value> params, bool negat
|
||||
bool Condition::evaluate(RuleContext &context) {
|
||||
std::vector<Value> request;
|
||||
for(uint i=0; i<params.size(); i++) {
|
||||
if(params[i].isType(Value::ATTRIBUTE_REFERENCE)) {
|
||||
if(params[i].isType(Value::ADDRESS_SPACE_REFERENCE)) {
|
||||
request.push_back(Value::fromAddressSpace(context.addressSpaces.at(params[i].asReference())));
|
||||
} else if(params[i].isType(Value::ATTRIBUTE_REFERENCE)) {
|
||||
request.push_back(context.attributes[params[i].asReference()]);
|
||||
} else {
|
||||
request.push_back(params[i]);
|
||||
|
||||
@@ -706,7 +706,7 @@ std::optional<Condition> SchemaCreator::loadCondition(ConditionNode node)
|
||||
if(signatures[i].params[j] == Value::ADDRESS_SPACE) {
|
||||
if(hasAddressSpace(type.asReference())) {
|
||||
exists = true;
|
||||
type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE);
|
||||
type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE_REFERENCE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
-1
@@ -4,6 +4,32 @@
|
||||
|
||||
namespace domain {
|
||||
|
||||
std::string Value::string() {
|
||||
switch (type) {
|
||||
case INT:
|
||||
return std::to_string(intValue);
|
||||
case BOOL:
|
||||
return boolValue ? "true" : "false";
|
||||
case STRING:
|
||||
return stringValue;
|
||||
case NIL:
|
||||
return "null";
|
||||
case UNDEFINED:
|
||||
return "undefined";
|
||||
case ADDRESS_SPACE:
|
||||
return "AddressSpace::" + addressSpace->getName();
|
||||
case WIRE_REFERENCE:
|
||||
return "Wire::" + reference;
|
||||
case ADDRESS_SPACE_REFERENCE:
|
||||
return "AddressSpace::" + reference;
|
||||
case ATTRIBUTE_REFERENCE:
|
||||
return "Attribute::" + reference;
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Value::ValueType Value::getType() {
|
||||
return type;
|
||||
}
|
||||
@@ -36,7 +62,7 @@ AddressSpace Value::asAddressSpace() {
|
||||
throw std::exception();
|
||||
}
|
||||
std::string Value::asReference() {
|
||||
if(isType(Value::WIRE_REFERENCE) || isType(Value::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) {
|
||||
if(isType(Value::WIRE_REFERENCE) || isType(Value::ADDRESS_SPACE_REFERENCE) || isType(Value::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) {
|
||||
return reference;
|
||||
}
|
||||
throw std::exception();
|
||||
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
STRING,
|
||||
BOOL,
|
||||
ADDRESS_SPACE,
|
||||
ADDRESS_SPACE_REFERENCE,
|
||||
ATTRIBUTE_REFERENCE,
|
||||
WIRE_REFERENCE,
|
||||
NIL,
|
||||
@@ -38,6 +39,8 @@ public:
|
||||
this->type = UNDEFINED;
|
||||
}
|
||||
|
||||
std::string string();
|
||||
|
||||
ValueType getType();
|
||||
bool isType(ValueType type);
|
||||
|
||||
|
||||
Reference in new issue
Block a user