schema_editor/application.cpp

199 lines
6.0 KiB
C++

//
// 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<domain::Library> 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()) {
errorOutput<<"Failed creating library model"<<std::endl;
return false;
} else {
libraryPath = filename;
// on library load we create a new schema
schema = new domain::Schema();
}
} else {
errorOutput<<"Failed parsing library"<<std::endl;
return false;
}
return true;
}
bool Application::loadSchema(std::string &filename, std::ostream &errorOutput) {
clear();
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;
}
} else {
clear();
return false;
}
} else {
errorOutput<<"Failed parsing library"<<std::endl;
return false;
}
return true;
}
bool Application::generateSchema(std::ostringstream &output) {
if(schema == nullptr) {
return false;
}
domain::generate_schema(libraryPath, schema, output);
return true;
}
std::vector<domain::ValidationError> Application::validateSchema() {
if(schema == nullptr) {
return std::vector<domain::ValidationError>{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 countValidation = validator.validateInstanceCount(*schema, *library, context);
errors.insert(errors.end(), countValidation.begin(), countValidation.end());
auto nameValidation = validator.validateInstanceNames(*schema, *library, context);
errors.insert(errors.end(), nameValidation.begin(), nameValidation.end());
auto pinValidation = validator.validatePinConnections(*schema, *library, context);
errors.insert(errors.end(), pinValidation.begin(), pinValidation.end());
return errors;
}
std::vector<domain::ValidationError> 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<domain::ValidationError> 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<domain::ComponentInstance> Application::addComponent(domain::Component component, std::vector<domain::InstanceAttribute> attributes, int x, int y) {
std::set<std::string> 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<domain::ComponentInstance>(name, attributes, std::make_pair(x, y), component));
return schema->componentInstances.back();
}
std::shared_ptr<domain::BusInstance> Application::addBus(domain::Bus bus, int x, int y) {
std::set<std::string> 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<domain::BusInstance>(name, std::make_pair(x, y), bus));
return schema->busInstances.back();
}
std::string Application::generateName(std::set<std::string>& 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;
}