schema_editor/comdel/domain/comdel_validator.cpp

240 lines
9.6 KiB
C++

#include <set>
#include "comdel_validator.h"
#include "library.h"
#include "message_source.h"
namespace domain {
std::vector<ValidationError> ComdelValidator::validateSchema(Schema &schema, ValidationContext context) {
std::vector<ValidationError> errors;
context.instance = nullptr;
context.attribute = nullptr;
for (auto &instance: schema.componentInstances) {
auto result = validateComponent(instance.get(), context);
errors.insert(errors.end(), result.begin(), result.end());
}
return errors;
}
std::vector<ValidationError>
ComdelValidator::validateInstanceCount(Schema &schema, Library &library, ValidationContext context) {
std::vector<ValidationError> errors;
// validate instance count
std::map<std::string, int> instanceMap;
for (auto &inst: schema.componentInstances) {
instanceMap[inst->component.getName()]++;
}
for (auto comp: library.getComponents()) {
int count = instanceMap[comp.getName()];
context.attributes["componentName"] = Value::fromString(comp.getDisplayName());
context.attributes["min"] = Value::fromInt(comp.getCount().first);
context.attributes["max"] = Value::fromInt(comp.getCount().second);
context.attributes["count"] = Value::fromInt(count);
if (count < comp.getCount().first) {
auto message = MESSAGE_PARAM("msg_validators_component_min_count", context.map());
errors.emplace_back(Action::ERROR, message);
} else if (count > comp.getCount().second) {
auto message = MESSAGE_PARAM("msg_validators_component_max_count", context.map());
errors.emplace_back(Action::ERROR, message);
}
}
// validate bus instance count
std::map<std::string, int> busInstanceMap;
for (auto &inst: schema.busInstances) {
busInstanceMap[inst->bus.getName()]++;
}
for (auto bus: library.getBuses()) {
int count = busInstanceMap[bus.getName()];
context.attributes["busName"] = Value::fromString(bus.getDisplayName());
context.attributes["min"] = Value::fromInt(bus.getCount().first);
context.attributes["max"] = Value::fromInt(bus.getCount().second);
context.attributes["count"] = Value::fromInt(count);
if (count < bus.getCount().first) {
auto message = MESSAGE_PARAM("msg_validators_bus_min_count", context.map());
errors.emplace_back(Action::ERROR, message);
} else if (count > bus.getCount().second) {
auto message = MESSAGE_PARAM("msg_validators_bus_max_count", context.map());
errors.emplace_back(Action::ERROR, message);
}
}
return errors;
}
std::vector<ValidationError>
ComdelValidator::validatePinConnections(Schema &schema, Library &library, ValidationContext context) {
std::vector<ValidationError> errors;
for (auto &inst: schema.componentInstances) {
for (auto &pin: inst->component.getPins()) {
if (pin.getConnection().has_value()) {
if (!connectionExists(schema, inst, pin)) {
context.instance = inst.get();
auto message = MESSAGE_PARAM(pin.getConnection().value(), context.map());
errors.emplace_back(context.instance, nullptr, Action::ERROR, message);
}
}
}
}
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 = validators;
auto action = rule.evaluate(ruleContext);
if (action) {
auto message = MESSAGE_PARAM(action->getMessage(), context.map());
return ValidationError{context.instance, context.attribute, action->getType(), message};
}
return nullopt;
}
std::vector<ValidationError>
ComdelValidator::validateMemoryReferences(Schema &schema, Library &library, ValidationContext context) {
std::set<std::string> memoryInstances;
for(auto& component: schema.componentInstances) {
if(component->component.getType() == Component::MEMORY) {
memoryInstances.insert(component->name);
}
}
std::vector<ValidationError> errors;
for(auto& component: schema.componentInstances) {
if(component->component.getType() == Component::PROCESSOR) {
for(auto& attribute: component->attributes) {
if(attribute.value.isType(Value::MEMORY_REFERENCE)) {
auto memoryReference = attribute.value.asMemoryReference();
if(memoryReference != nullopt) {
if(memoryInstances.count(*memoryReference) == 0) {
context.attributes["memoryReference"] = domain::Value::fromString(memoryReference.value());
auto message = MESSAGE_PARAM("msg_validators_memory_not_found", context.map());
errors.emplace_back(component.get(), nullptr, Action::ERROR, message);
}
}
}
}
}
}
return errors;
}
std::vector<ValidationError>
ComdelValidator::validateInstanceNames(Schema &schema, Library &library, ValidationContext context) {
std::set<std::string> names;
std::vector<ValidationError> errors;
for(auto& component: schema.componentInstances) {
if(names.find(component->name) != names.end()) {
context.instance = component.get();
auto message = MESSAGE_PARAM("msg_validators_duplicates_found", context.map());
errors.emplace_back(Action::ERROR, message);
}
names.insert(component->name);
}
return errors;
}
bool ComdelValidator::connectionExists(Schema &schema, shared_ptr<ComponentInstance> &component, Pin &pin) {
for (auto conn: schema.connections) {
auto busConnection = dynamic_cast<BusConnectionInstance *>(conn.get());
if (busConnection != nullptr) {
if (busConnection->instance->name == component->name &&
busConnection->connection.getComponent().pin == pin.getName()) {
return true;
}
}
auto directConnection = dynamic_cast<DirectConnectionInstance *>(conn.get());
if (directConnection != nullptr) {
if ((directConnection->instance->name == component->name && directConnection->connection.getComponent().pin == pin.getName()) ||
(directConnection->secondInstance->name == component->name) && directConnection->connection.getSecondComponent()->pin == pin.getName()) {
return directConnection->connection.isConnecting({component->component.getName(), pin.getName()});
}
}
}
return false;
}
ComdelValidator::ComdelValidator(std::vector<FunctionValidator *> validators) {
for (auto *validator: validators) {
validator->clear();
this->validators.insert(std::make_pair(validator->getName(), validator));
}
}
std::map<std::string, std::string> ValidationContext::map() {
std::map<std::string, std::string> parametars;
if(instance != nullptr) {
parametars["instanceName"] = instance->name;
parametars["componentName"] = instance->component.getDisplayName();
}
if(attribute != nullptr) {
parametars["attributeName"] = attribute->name;
parametars["attribute"] = attribute->value.string();
}
for(auto [key, value]: attributes) {
parametars[key] = value.string();
}
return parametars;
}
}