#include #include "comdel_validator.h" #include "library.h" #include "message_source.h" namespace domain { std::vector ComdelValidator::validateSchema(Schema &schema, ValidationContext context) { std::vector 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 ComdelValidator::validateInstanceCount(Schema &schema, Library &library, ValidationContext context) { std::vector errors; // validate instance count std::map 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 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 ComdelValidator::validatePinConnections(Schema &schema, Library &library, ValidationContext context) { std::vector 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 ComdelValidator::validateComponent(ComponentInstance *instance, ValidationContext context) { std::vector 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 ComdelValidator::validateAttribute(InstanceAttribute *attribute, ValidationContext context) { std::vector errors; if (attribute->attribute.getPopup()) { Popup popup = *attribute->attribute.getPopup(); context.attribute = attribute; context.attributes = std::map{{attribute->name, attribute->value}}; for (auto &rule: popup.getRules()) { auto result = validateRule(rule, context); if (result) { errors.push_back(*result); } } } return errors; } std::optional 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 ComdelValidator::validateMemoryReferences(Schema &schema, Library &library, ValidationContext context) { std::set memoryInstances; for(auto& component: schema.componentInstances) { if(component->component.getType() == Component::MEMORY) { memoryInstances.insert(component->name); } } std::vector 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 ComdelValidator::validateInstanceNames(Schema &schema, Library &library, ValidationContext context) { std::set names; std::vector 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 &component, Pin &pin) { for (auto conn: schema.connections) { auto busConnection = dynamic_cast(conn.get()); if (busConnection != nullptr) { if (busConnection->instance->name == component->name && busConnection->connection.getComponent().pin == pin.getName()) { return true; } } auto directConnection = dynamic_cast(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 validators) { for (auto *validator: validators) { validator->clear(); this->validators.insert(std::make_pair(validator->getName(), validator)); } } std::map ValidationContext::map() { std::map 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; } }