// // Created by bbr on 27.05.22.. // #include "application.h" #include "comdel/parser/parse_context.h" #include "comdel/parser/parser_util.h" #include "comdel/domain/schema_creator.h" #include "comdel/domain/comdel_generator.h" #include "comdel/domain/comdel_validator.h" std::optional Application::getLibrary() { return library; } domain::Schema *Application::getSchema() { return schema; } void Application::clear() { if (schema != nullptr) { delete schema; schema = nullptr; } library = std::nullopt; libraryPath = ""; } bool Application::loadLibrary(std::string &filename, std::ostream &errorOutput) { clear(); ParseContext parseContext; auto libraryNode = load_library_from_file(&parseContext, filename.c_str(), errorOutput); if (libraryNode) { domain::SchemaCreator generator(validators); library = generator.loadLibrary(*libraryNode); for (auto &error: generator.getErrors()) { parseContext.formatError(error, errorOutput, "ERROR: "); } if (library.has_value()) { libraryPath = filename; // on library load we create a new schema schema = new domain::Schema(library.value()); } else { errorOutput << "Failed creating library model" << std::endl; return false; } } else { errorOutput << "Failed parsing library" << std::endl; return false; } return true; } std::pair> Application::loadSchema(std::string &filename, std::ostream &errorOutput) { clear(); std::vector errors; ParseContext parseContext; auto schemaNode = load_schema_from_file(&parseContext, filename.c_str(), errorOutput); if (schemaNode) { domain::SchemaCreator generator(validators); library = generator.loadLibrary(*schemaNode->library); libraryPath = schemaNode->source->asString(); for (auto &error: generator.getErrors()) { parseContext.formatError(error, errorOutput, "ERROR: "); } if (library) { schema = generator.loadSchema(*schemaNode, *library); for (auto &error: generator.getErrors()) { parseContext.formatError(error, errorOutput, "ERROR: "); } if (schema == nullptr) { clear(); return {false, errors}; } } else { clear(); return {false, errors}; } } else { errorOutput << "Failed schema library" << std::endl; return {false, errors}; } domain::ComdelValidator validator{validators}; domain::ValidationContext context; context.instance = nullptr; context.attribute = nullptr; context.addressSpaces = {}; auto memoryReferenceValidation = validator.validateMemoryReferences(*schema, *library, context); errors.insert(errors.end(), memoryReferenceValidation.begin(), memoryReferenceValidation.end()); auto nameValidation = validator.validateInstanceNames(*schema, *library, context); errors.insert(errors.end(), nameValidation.begin(), nameValidation.end()); if(!errors.empty()) { clear(); return {false, errors}; } return {true, errors}; } bool Application::generateSchema(std::ostringstream &output) { if (schema == nullptr) { return false; } domain::generate_schema(libraryPath, schema, output); return true; } std::vector Application::validateSchema() { if (schema == nullptr) { return std::vector{domain::ValidationError(domain::Action::ERROR, "No schema loaded")}; } domain::ComdelValidator validator{validators}; domain::ValidationContext context; context.instance = nullptr; context.attribute = nullptr; context.addressSpaces = {}; for (auto &lib: library->getAddressSpaces()) { context.addressSpaces.insert(std::make_pair(lib.getName(), lib)); } auto errors = validator.validateSchema(*schema, context); auto memoryReferenceValidation = validator.validateMemoryReferences(*schema, *library, context); errors.insert(errors.end(), memoryReferenceValidation.begin(), memoryReferenceValidation.end()); auto nameValidation = validator.validateInstanceNames(*schema, *library, context); errors.insert(errors.end(), nameValidation.begin(), nameValidation.end()); auto countValidation = validator.validateInstanceCount(*schema, *library, context); errors.insert(errors.end(), countValidation.begin(), countValidation.end()); auto pinValidation = validator.validatePinConnections(*schema, *library, context); errors.insert(errors.end(), pinValidation.begin(), pinValidation.end()); return errors; } std::vector Application::generateComdel(std::ostringstream &output) { auto errors = validateSchema(); if (!Application::hasErrors(errors)) { // as long as all validation errors are warning we continue with build domain::generate_comdel(schema, library.value(), output); } return errors; } bool Application::hasErrors(std::vector errors) { for (auto &err: errors) { if (err.type == domain::Action::ERROR) { return true; } } return false; } // static instance of application static Application *application = nullptr; Application *Application::instance() { if (application == nullptr) { application = new Application(); } return application; } std::shared_ptr Application::addComponent(domain::Component component, std::vector attributes, int x, int y) { std::set names; for (const auto &c: schema->componentInstances) { names.insert(c->name); } std::string name = generateName(names, component.getInstanceName()); schema->componentInstances.push_back( std::make_shared(name, attributes, std::make_pair(x, y), component)); return schema->componentInstances.back(); } std::shared_ptr Application::addBus(domain::Bus bus, int x, int y) { std::set names; for (const auto &b: schema->busInstances) { names.insert(b->name); } std::string name = generateName(names, bus.getInstanceName()); schema->busInstances.push_back(std::make_shared(name, std::make_pair(x, y), bus)); return schema->busInstances.back(); } std::string Application::generateName(std::set &names, std::string instanceName) { if (names.find(instanceName) == names.end()) { return instanceName; } char buffer[4]; for (int i = 0; i < 1000; i++) { sprintf(buffer, "%03d", i); auto name = instanceName + "_" + buffer; if (names.find(name) == names.end()) { return name; } } // return default value as this should never happen return instanceName; } bool Application::removeComponent(std::string componentName) { auto component = findComponentByName(componentName); if (component == nullptr) { return false; } std::set automaticBusses; schema->connections.erase( std::remove_if( schema->connections.begin(), schema->connections.end(), [component, &automaticBusses](const std::shared_ptr &conn) { auto busConnection = dynamic_cast(conn.get()); if (busConnection) { if (busConnection->instance == component) { return true; } } auto directConnection = dynamic_cast(conn.get()); if (directConnection) { if (directConnection->instance == component || directConnection->secondInstance == component) { automaticBusses.insert(directConnection->bus); return true; } } return false; }), schema->connections.end() ); schema->busInstances.erase( std::remove_if( schema->busInstances.begin(), schema->busInstances.end(), [&automaticBusses](const std::shared_ptr &bus) { return automaticBusses.count(bus.get()); }), schema->busInstances.end() ); if(component->component.getType() == domain::Component::MEMORY) { for(auto& comp: schema->componentInstances) { if(comp->component.getType() == domain::Component::PROCESSOR) { for(auto& attribute: comp->attributes) { if(attribute.value.isType(domain::Value::MEMORY_REFERENCE) && attribute.value.asMemoryReference() == component->name) { attribute.value = domain::Value::fromMemoryReference(std::nullopt); } } } } } for(auto iter = schema->componentInstances.begin(); iter != schema->componentInstances.end(); ++iter) { if(iter->get() == component) { schema->componentInstances.erase(iter); break; } } return true; } void Application::removeConnection(domain::ConnectionInstance *connectionInstance) { if(auto directConnection = dynamic_cast(connectionInstance)) { schema->busInstances.erase( std::remove_if( schema->busInstances.begin(), schema->busInstances.end(), [directConnection](const std::shared_ptr &bus) { return directConnection->bus == bus.get(); }), schema->busInstances.end() ); } schema->connections.erase( std::remove_if( schema->connections.begin(), schema->connections.end(), [connectionInstance](const std::shared_ptr &conn) { return connectionInstance == conn.get(); }), schema->connections.end() ); } bool Application::removeBus(std::string busName) { auto bus = findBusByName(busName); if (bus == nullptr) { return false; } schema->connections.erase( std::remove_if( schema->connections.begin(), schema->connections.end(), [bus](const std::shared_ptr &conn) { auto busConnection = dynamic_cast(conn.get()); if (busConnection) { if (busConnection->bus == bus) { return true; } } return false; }), schema->connections.end() ); for(auto iter = schema->busInstances.begin(); iter != schema->busInstances.end(); ++iter) { if(iter->get() == bus) { schema->busInstances.erase(iter); break; } } return true; } domain::ComponentInstance *Application::findComponentByName(std::string componentName) { for (auto &comp: schema->componentInstances) { if (comp->name == componentName) { return comp.get(); } } return nullptr; } domain::BusInstance *Application::findBusByName(std::string busName) { for (auto &bus: schema->busInstances) { if (bus->name == busName) { return bus.get(); } } return nullptr; } void Application::renameComponent(std::string currentName, std::string newName) { if(currentName == newName) { return; } auto component = findComponentByName(currentName); if(component) { component->name = newName; if(component->component.getType() == domain::Component::MEMORY) { for(auto& comp: schema->componentInstances) { if(comp.get()->component.getType() == domain::Component::PROCESSOR) { for(auto& attribute: comp.get()->attributes) { if(attribute.value.isType(domain::Value::MEMORY_REFERENCE) && attribute.value.asMemoryReference() == currentName) { attribute.value = domain::Value::fromMemoryReference(newName); } } } } } } } void Application::renameBus(std::string currentName, std::string newName) { if(currentName == newName) { return; } auto bus = findBusByName(currentName); if(bus) { bus->name = newName; } }