Compare commits

..

24 Commits

Author SHA1 Message Date
Borna Rajković 947f6e464b Updated translations 2022-06-30 08:56:08 +02:00
Borna Rajković 9c332ac3e7 Updated minimum model 2022-06-27 11:44:19 +02:00
Borna Rajković edfd7fdf37 Generation fix 2022-06-27 11:39:13 +02:00
Borna Rajković 6ed60a2c26 Updated docs 2022-06-20 17:24:12 +02:00
Borna Rajković 9129a4bf43 Updated QT .pro file 2022-06-19 20:43:39 +02:00
Borna Rajković 350aa95da5 Updated examples 2022-06-19 20:38:24 +02:00
Borna Rajković d2fc849cc2 Added message source and arm example 2022-06-19 20:10:52 +02:00
Borna Rajković eaa115d115 Added display name 2022-06-14 21:27:40 +02:00
Borna Rajković 7be3a1b5bc Refactored validation 2022-06-14 00:53:46 +02:00
Borna Rajković fe4a39803c Cleanup 2022-06-13 00:55:54 +02:00
Borna Rajković 1ec0433cfe Added comments and cleaned up ast nodes and parser 2022-06-13 00:48:12 +02:00
Borna Rajković ae2a3c64ef Fixed pin selection 2022-06-12 16:40:35 +02:00
Borna Rajković 09991904e9 Added dynamic color support + text display item 2022-06-12 16:02:24 +02:00
Borna Rajković e6bbaabde4 Added antialiasing 2022-06-12 13:43:35 +02:00
Borna Rajković 6dfe86335d Added cancel to dialogs 2022-06-12 11:51:57 +02:00
Borna Rajković 4d4cf136fb Added pin connection editing 2022-06-09 23:42:45 +02:00
Borna Rajković f66fc1db26 Updated translations + bugfixes 2022-06-09 20:24:27 +02:00
Borna Rajković 1759adf25a Moved connection determination to schema 2022-06-07 21:13:21 +02:00
Borna Rajković 1ec8b10ef5 Fixed schema generation 2022-06-06 01:10:11 +02:00
Borna Rajković 9b7ede933a Added single automatic connection dialog + bugfixes 2022-06-05 19:02:44 +02:00
Borna Rajković 3172d7e4cf Added component/bus deletion and rename 2022-06-02 01:37:14 +02:00
Borna Rajković f93a2afa63 Updated component and bus generation logic + bugfixes 2022-05-31 01:05:08 +02:00
Borna Rajković 86b8861533 Extracted schema and library management to Application 2022-05-30 23:11:06 +02:00
Borna Rajković 0c4afe87d9 Basic refactor 2022-05-27 08:18:17 +02:00
123 changed files with 11726 additions and 7915 deletions

View File

@ -14,29 +14,28 @@ add_executable(SchemeEditor
comdel/domain/value.cpp comdel/domain/value.cpp
comdel/domain/schema.cpp comdel/domain/schema.cpp
comdel/domain/component.cpp comdel/domain/component.cpp
comdel/domain/connectioninstance.cpp comdel/domain/connection_instance.cpp
comdel/domain/rule.cpp comdel/domain/rule.cpp
comdel/domain/wireinstance.cpp
comdel/domain/attribute.cpp comdel/domain/attribute.cpp
comdel/domain/bus.cpp comdel/domain/bus.cpp
comdel/domain/pin.cpp comdel/domain/pin.cpp
comdel/domain/display.cpp comdel/domain/display.cpp
comdel/domain/library.cpp comdel/domain/library.cpp
comdel/domain/functionsignature.cpp comdel/domain/function_signature.cpp
comdel/domain/addressspace.cpp comdel/domain/address_space.cpp
comdel/domain/instanceattribute.cpp comdel/domain/instance_attribute.cpp
comdel/domain/connection.cpp comdel/domain/connection.cpp
comdel/domain/instance.cpp comdel/domain/instance.cpp
comdel/domain/schemacreator.cpp comdel/domain/schema_creator.cpp
comdel/parser/comdelparser.cpp comdel/parser/comdel_parser.cpp
comdel/parser/token.cpp comdel/parser/token.cpp
comdel/parser/sourceerror.cpp comdel/parser/source_error.cpp
comdel/parser/parsecontext.cpp comdel/parser/parse_context.cpp
comdel/parser/tokenstype.cpp comdel/parser/tokens_type.cpp
comdel/parser/astnode.cpp comdel/parser/ast_nodes.cpp
comdel/parser/parserutil.cpp comdel/parser/parser_util.cpp
comdel/parser/comdellexer.cpp comdel/parser/comdel_lexer.cpp
main.cpp main.cpp
mainwindow.ui mainwindow.ui
comdel/domain/comdelvalidator.cpp comdel/domain/comdelvalidator.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h) comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.h comdel/display/dialog/attribute_dialog.cpp comdel/display/dialog/attribute_dialog.h comdel/display/dialog/name_dialog.cpp comdel/display/dialog/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/dialog/single_automatic_dialog.cpp comdel/display/dialog/single_automatic_dialog.h comdel/parser/color.h comdel/display/dialog/generic_dialog.cpp comdel/display/dialog/generic_dialog.h comdel/display/dialog/warning_dialog.cpp comdel/display/dialog/warning_dialog.h comdel/display/dialog/error_dialog.cpp comdel/display/dialog/error_dialog.h comdel/display/dialog/memory_dialog.cpp comdel/display/dialog/memory_dialog.h comdel/display/dialog/success_dialog.cpp comdel/display/dialog/success_dialog.h message_source.cpp message_source.h)
target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets) target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets)

View File

@ -9,77 +9,92 @@ CONFIG += c++17
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \ SOURCES += \
comdel/display/dialog/attribute_dialog.cpp \
comdel/display/dialog/error_dialog.cpp \
comdel/display/dialog/generic_dialog.cpp \
comdel/display/dialog/memory_dialog.cpp \
comdel/display/dialog/name_dialog.cpp \
comdel/display/dialog/single_automatic_dialog.cpp \
comdel/display/dialog/success_dialog.cpp \
comdel/display/dialog/warning_dialog.cpp \
comdel/display/component_display.cpp \ comdel/display/component_display.cpp \
comdel/display/library_display.cpp \ comdel/display/library_display.cpp \
comdel/display/library_list.cpp \
comdel/display/schema_display.cpp \ comdel/display/schema_display.cpp \
comdel/domain/addressspace.cpp \ comdel/domain/address_space.cpp \
comdel/domain/attribute.cpp \ comdel/domain/attribute.cpp \
comdel/domain/bus.cpp \ comdel/domain/bus.cpp \
comdel/domain/schemacreator.cpp \ comdel/domain/comdel_generator.cpp \
comdel/domain/comdel_validator.cpp \
comdel/domain/component.cpp \ comdel/domain/component.cpp \
comdel/domain/connection.cpp \ comdel/domain/connection.cpp \
comdel/domain/comdelvalidator.cpp \ comdel/domain/connection_instance.cpp \
comdel/domain/connectioninstance.cpp \
comdel/domain/display.cpp \ comdel/domain/display.cpp \
comdel/domain/functionsignature.cpp \ comdel/domain/function_signature.cpp \
comdel/domain/instance.cpp \ comdel/domain/instance.cpp \
comdel/domain/instanceattribute.cpp \ comdel/domain/instance_attribute.cpp \
comdel/domain/library.cpp \ comdel/domain/library.cpp \
comdel/domain/pin.cpp \ comdel/domain/pin.cpp \
comdel/domain/rule.cpp \ comdel/domain/rule.cpp \
comdel/domain/schema.cpp \ comdel/domain/schema.cpp \
comdel/domain/schema_creator.cpp \
comdel/domain/value.cpp \ comdel/domain/value.cpp \
comdel/domain/wireinstance.cpp \ comdel/parser/ast_nodes.cpp \
comdel/parser/astnode.cpp \ comdel/parser/comdel_lexer.cpp \
comdel/parser/comdellexer.cpp \ comdel/parser/comdel_parser.cpp \
comdel/parser/comdelparser.cpp \ comdel/parser/parse_context.cpp \
comdel/parser/parsecontext.cpp \ comdel/parser/parser_util.cpp \
comdel/parser/parserutil.cpp \ comdel/parser/source_error.cpp \
comdel/parser/sourceerror.cpp \
comdel/parser/token.cpp \ comdel/parser/token.cpp \
comdel/parser/tokenstype.cpp \ comdel/parser/tokens_type.cpp \
comdel/display/dialogmanager.cpp \ application.cpp \
comdel/display/attribute_dialog.cpp \
comdel/display/name_dialog.cpp \
main.cpp \ main.cpp \
message_source.cpp \
mainwindow.cpp mainwindow.cpp
HEADERS += \ HEADERS += \
comdel/display/dialog/attribute_dialog.h \
comdel/display/dialog/error_dialog.h \
comdel/display/dialog/generic_dialog.h \
comdel/display/dialog/memory_dialog.h \
comdel/display/dialog/name_dialog.h \
comdel/display/dialog/single_automatic_dialog.h \
comdel/display/dialog/success_dialog.h \
comdel/display/dialog/warning_dialog.h \
comdel/display/component_display.h \ comdel/display/component_display.h \
comdel/display/library_display.h \ comdel/display/library_display.h \
comdel/display/library_list.h \
comdel/display/schema_display.h \ comdel/display/schema_display.h \
comdel/domain/addressspace.h \ comdel/domain/address_space.h \
comdel/domain/attribute.h \ comdel/domain/attribute.h \
comdel/domain/bus.h \ comdel/domain/bus.h \
comdel/domain/schemacreator.h \ comdel/domain/comdel_generator.h \
comdel/domain/comdel_validator.h \
comdel/domain/component.h \ comdel/domain/component.h \
comdel/domain/connection.h \ comdel/domain/connection.h \
comdel/domain/comdelvalidator.h \ comdel/domain/connection_instance.h \
comdel/domain/connectioninstance.h \
comdel/domain/display.h \ comdel/domain/display.h \
comdel/domain/functionsignature.h \ comdel/domain/function_signature.h \
comdel/domain/instance.h \ comdel/domain/instance.h \
comdel/domain/instanceattribute.h \ comdel/domain/instance_attribute.h \
comdel/domain/library.h \ comdel/domain/library.h \
comdel/domain/pin.h \ comdel/domain/pin.h \
comdel/domain/rule.h \ comdel/domain/rule.h \
comdel/domain/schema.h \ comdel/domain/schema.h \
comdel/domain/schema_creator.h \
comdel/domain/value.h \ comdel/domain/value.h \
comdel/domain/wireinstance.h \ comdel/parser/ast_nodes.h \
comdel/parser/astnode.h \ comdel/parser/comdel_lexer.h \
comdel/parser/comdellexer.h \ comdel/parser/comdel_parser.h \
comdel/parser/comdelparser.h \
comdel/parser/expected.h \ comdel/parser/expected.h \
comdel/parser/parsecontext.h \ comdel/parser/parse_context.h \
comdel/parser/parserutil.h \ comdel/parser/parser_util.h \
comdel/parser/poly.h \ comdel/parser/poly.h \
comdel/parser/presult.h \ comdel/parser/presult.h \
comdel/parser/sourceerror.h \ comdel/parser/source_error.h \
comdel/parser/token.h \ comdel/parser/token.h \
comdel/parser/tokenstype.h \ comdel/parser/tokens_type.h \
comdel/display/dialogmanager.h \ message_source.h \
comdel/display/attribute_dialog.h \
comdel/display/name_dialog.h \
mainwindow.h mainwindow.h
FORMS += \ FORMS += \

394
application.cpp Normal file
View File

@ -0,0 +1,394 @@
//
// 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()) {
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<bool, std::vector<domain::ValidationError>> Application::loadSchema(std::string &filename, std::ostream &errorOutput) {
clear();
std::vector<domain::ValidationError> 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<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 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<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;
}
bool Application::removeComponent(std::string componentName) {
auto component = findComponentByName(componentName);
if (component == nullptr) {
return false;
}
std::set<domain::BusInstance*> automaticBusses;
schema->connections.erase(
std::remove_if(
schema->connections.begin(),
schema->connections.end(),
[component, &automaticBusses](const std::shared_ptr<domain::ConnectionInstance> &conn) {
auto busConnection = dynamic_cast<domain::BusConnectionInstance *>(conn.get());
if (busConnection) {
if (busConnection->instance == component) {
return true;
}
}
auto directConnection = dynamic_cast<domain::DirectConnectionInstance *>(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<domain::BusInstance> &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<domain::DirectConnectionInstance*>(connectionInstance)) {
schema->busInstances.erase(
std::remove_if(
schema->busInstances.begin(),
schema->busInstances.end(),
[directConnection](const std::shared_ptr<domain::BusInstance> &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<domain::ConnectionInstance> &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<domain::ConnectionInstance> &conn) {
auto busConnection = dynamic_cast<domain::BusConnectionInstance *>(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;
}
}

60
application.h Normal file
View File

@ -0,0 +1,60 @@
//
// Created by bbr on 27.05.22..
//
#ifndef SCHEMEEDITOR_APPLICATION_H
#define SCHEMEEDITOR_APPLICATION_H
#include <set>
#include "comdel/domain/library.h"
#include "comdel/domain/schema.h"
#include "comdel/domain/comdel_validator.h"
class Application {
private:
std::string libraryPath;
std::optional<domain::Library> library = std::nullopt;
domain::Schema* schema = nullptr;
std::vector<domain::FunctionValidator*> validators = domain::getSupportedValidators();
std::string generateName(std::set<std::string>& names, std::string instanceName);
domain::ComponentInstance *findComponentByName(std::string componentName);
domain::BusInstance *findBusByName(std::string busName);
public:
std::optional<domain::Library> getLibrary();
domain::Schema* getSchema();
void clear();
bool loadLibrary(std::string& filename, std::ostream& errorOutput);
std::pair<bool, std::vector<domain::ValidationError>> loadSchema(std::string& filename, std::ostream& errorOutput);
static Application* instance();
bool generateSchema(std::ostringstream &output);
std::vector<domain::ValidationError> validateSchema();
std::vector<domain::ValidationError> generateComdel(std::ostringstream &output);
std::shared_ptr<domain::ComponentInstance> addComponent(domain::Component component, std::vector<domain::InstanceAttribute> attributes, int x, int y);
bool removeComponent(std::string component);
std::shared_ptr<domain::BusInstance> addBus(domain::Bus bus, int x, int y);
bool removeBus(std::string bus);
static bool hasErrors(std::vector<domain::ValidationError> empty);
~Application() = default;
void renameComponent(std::string currentName, std::string newName);
void renameBus(std::string currentName, std::string newName);
void removeConnection(domain::ConnectionInstance *pInstance);
};
#endif //SCHEMEEDITOR_APPLICATION_H

View File

@ -1,66 +0,0 @@
//
// Created by bbr on 18. 04. 2022..
//
#include "attribute_dialog.h"
#include "mainwindow.h"
namespace display {
void AttributeDialog::onUpdate() {
auto oldValue = attributeValue->value;
attributeValue->value = value;
domain::ComdelValidator validator(domain::getSupportedValidators());
domain::ValidationContext context;
for (auto &addressSpace: MainWindow::getLibrary()->getAddressSpaces()) {
context.addressSpaces.insert(std::make_pair(addressSpace.getName(), addressSpace));
}
auto validationErrors = validator.validateAttribute(attributeValue, context);
if(validationErrors.empty()) {
accept();
} else {
bool canAccept = true;
std::vector<domain::ValidationError> errors;
std::vector<domain::ValidationError> warnings;
for(auto& err: validationErrors) {
if(err.type == domain::Action::ERROR) {
errors.push_back(err);
} else {
warnings.push_back(err);
}
}
if(!errors.empty()) {
canAccept = false;
auto errorDialog = new ErrorDialog(errors);
errorDialog->exec();
}
for(auto& warning: warnings) {
auto warningDialog = new WarningDialog(warning);
int response = warningDialog->exec();
if(response == QDialog::Rejected) {
canAccept = false;
}
}
if(canAccept) {
accept();
} else {
attributeValue->value = oldValue;
}
}
}
void MemoryDialog::onUpdate() {
attributeValue->value = value;
accept();
}
}

View File

@ -1,268 +0,0 @@
#ifndef ATTRIBUTE_DIALOG_H
#define ATTRIBUTE_DIALOG_H
#include <QIntValidator>
#include <QPushButton>
#include <QComboBox>
#include <QGroupBox>
#include <QRadioButton>
#include <QDialog>
#include <QLineEdit>
#include <QLabel>
#include <QVBoxLayout>
#include <utility>
#include <comdel/domain/instanceattribute.h>
#include <comdel/domain/value.h>
#include "comdel/domain/comdelvalidator.h"
namespace display {
class AttributeDialog: public QDialog {
domain::Value value;
long long int parseInt(std::string expression) {
try {
if (expression.size() > 2) {
if (expression.substr(0, 2) == "0x") {
return std::stoll(expression, 0, 16);
} else if (expression.substr(0, 2) == "0b") {
return std::stoll(expression, 0, 2);
} else {
return std::stoll(expression, 0, 10);
}
} else {
return std::stoll(expression, 0, 10);
}
} catch (std::exception &e) {
return 0;
}
}
domain::InstanceAttribute* attributeValue;
public:
AttributeDialog(domain::InstanceAttribute *attribute) {
setAttribute(Qt::WA_DeleteOnClose);
attributeValue = attribute;
this->setWindowTitle(QString::fromStdString("Izmjeni " + attribute->attribute.getName()));
auto layout = new QVBoxLayout(this);
this->setLayout(layout);
auto popup = *attribute->attribute.getPopup();
layout->addWidget(new QLabel(popup.getTitle().c_str()));
layout->addWidget(new QLabel(popup.getText().c_str()));
auto type = attribute->attribute.getDefault().getType();
value = attribute->value;
if(attribute->attribute.getPopup()->isEnumerated()) {
auto* combo = new QComboBox(this);
auto enumeration = attribute->attribute.getPopup()->getEnumeration();
for(auto entry: enumeration) {
combo->addItem(QString::fromStdString(entry.getName()));
}
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &AttributeDialog::onEnumerationChanged);
layout->addWidget(combo);
for(int i=0; i<enumeration.size(); i++) {
if(attributeValue->value.equals(enumeration[i].getValue())) {
combo->setCurrentIndex(i);
break;
}
}
} else if(!(type == domain::Value::ValueType::WIRE_REFERENCE || type == domain::Value::ValueType::BOOL)) {
auto edit = new QLineEdit(this);
connect(edit, &QLineEdit::textChanged, this, &AttributeDialog::onTextChanged);
layout->addWidget(edit);
switch (attribute->attribute.getDefault().getType()) {
case domain::Value::ValueType::INT:
edit->setValidator(new QIntValidator(-10000000, 10000000, edit));
edit->insert(std::to_string(attribute->value.asInt()).c_str());
break;
case domain::Value::ValueType::STRING:
edit->insert(attribute->value.asString().c_str());
break;
}
} else if(type == domain::Value::ValueType::BOOL) {
auto *group = new QGroupBox(this);
auto *radioLayout = new QHBoxLayout(group);
group->setLayout(radioLayout);
auto isTrue = new QRadioButton("true", group);
connect(isTrue, &QRadioButton::clicked, [this]() {
this->value = domain::Value::fromBool(true);
});
auto isFalse = new QRadioButton("false", group);
connect(isFalse, &QRadioButton::clicked, [this]() {
this->value = domain::Value::fromBool(false);
});
if(attribute->value.asBool()) {
isTrue->setChecked(true);
} else {
isFalse->setChecked(true);
}
radioLayout->addWidget(isTrue);
radioLayout->addWidget(isFalse);
layout->addWidget(group);
}
auto button = new QPushButton("Ažuriraj");
connect(button, &QPushButton::clicked, this, &AttributeDialog::onUpdate);
layout->addWidget(button);
}
public slots:
void onTextChanged(const QString& string) {
switch (value.getType()) {
case domain::Value::STRING:
value.setString(string.toStdString());
break;
case domain::Value::INT:
value = domain::Value::fromInt(parseInt(string.toStdString()));
}
};
void onEnumerationChanged(int index) {
value = attributeValue->attribute.getPopup()->getEnumeration()[index].getValue();
}
void onUpdate();
};
class MemoryDialog: public QDialog {
domain::Value value;
domain::InstanceAttribute* attributeValue;
std::vector<std::string> memoryInstances;
public:
MemoryDialog(domain::InstanceAttribute *attribute, std::vector<std::shared_ptr<domain::ComponentInstance>> instances) {
memoryInstances = std::vector<std::string>();
setAttribute(Qt::WA_DeleteOnClose);
attributeValue = attribute;
this->setWindowTitle(QString::fromStdString("Izmjeni " + attribute->attribute.getName()));
for(auto& instance: instances) {
if(instance->component.getType() == domain::Component::MEMORY) {
memoryInstances.push_back(instance->name);
}
}
auto layout = new QVBoxLayout(this);
this->setLayout(layout);
auto popup = *attribute->attribute.getPopup();
layout->addWidget(new QLabel(popup.getTitle().c_str()));
layout->addWidget(new QLabel(popup.getText().c_str()));
value = attribute->value;
auto* combo = new QComboBox(this);
for(auto& entry: memoryInstances) {
combo->addItem(QString::fromStdString(entry));
}
combo->addItem("null");
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MemoryDialog::onMemoryChanged);
layout->addWidget(combo);
combo->setCurrentIndex(memoryInstances.size());
for(int i=0; i<memoryInstances.size(); i++) {
if(attributeValue->value.asMemoryReference().has_value() && attributeValue->value.asMemoryReference() == memoryInstances[i]) {
combo->setCurrentIndex(i);
break;
}
}
auto button = new QPushButton("Ažuriraj");
connect(button, &QPushButton::clicked, this, &MemoryDialog::onUpdate);
layout->addWidget(button);
}
public slots:
void onMemoryChanged(int index) {
if(index == memoryInstances.size()) {
value = domain::Value::fromMemoryReference(std::nullopt);
} else {
value = domain::Value::fromMemoryReference(memoryInstances[index]);
}
}
void onUpdate();
};
class ErrorDialog: public QDialog {
public:
ErrorDialog(std::vector<domain::ValidationError> errors) {
setAttribute(Qt::WA_DeleteOnClose);
this->setWindowTitle("Greške");
auto layout = new QVBoxLayout(this);
this->setLayout(layout);
for(auto& err: errors) {
layout->addWidget(new QLabel(QString::fromStdString(err.message), this));
}
}
};
class WarningDialog: public QDialog {
public:
WarningDialog(domain::ValidationError error) {
setAttribute(Qt::WA_DeleteOnClose);
this->setWindowTitle("Upozorenje");
auto layout = new QVBoxLayout(this);
this->setLayout(layout);
layout->addWidget(new QLabel(QString::fromStdString(error.message), this));
auto buttonLayout = new QHBoxLayout(this);
auto okButton = new QPushButton("U redu", this);
auto cancelButton = new QPushButton("Odustani", this);
connect(okButton, &QPushButton::clicked, [this]() { accept(); });
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
layout->addItem(buttonLayout);
}
};
}
#endif //ATTRIBUTE_DIALOG_H

View File

@ -1,43 +1,145 @@
#include "component_display.h" #include "component_display.h"
#include "attribute_dialog.h" #include "comdel/display/dialog/attribute_dialog.h"
#include "name_dialog.h" #include "comdel/display/dialog/name_dialog.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "application.h"
#include "comdel/display/dialog/single_automatic_dialog.h"
#include "comdel/display/dialog/memory_dialog.h"
#include "message_source.h"
#include <QMenu> #include <QMenu>
#include <QLine> #include <QLine>
#include <QPen>
#include <QGraphicsSceneContextMenuEvent> #include <QGraphicsSceneContextMenuEvent>
#include <set>
namespace display { namespace display {
QPen connectionPen(QColor::fromRgb(150, 150, 250));
Component::Component(const std::shared_ptr<domain::ComponentInstance> &instance): instance(instance) {
setFlag(ItemSendsGeometryChanges, true);
setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName()));
instance->component.getDisplay().render(this, domain::ui::DisplayContext(instance.get()));
}
void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
QMenu menu; QMenu menu;
menu.addAction("Izmjeni ime", [this](){ menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() {
auto dialog = new NameDialog(this->instance.get()); std::set<std::string> names;
for(const auto &component: Application::instance()->getSchema()->componentInstances) {
names.insert(component->name);
}
auto dialog = new NameDialog(this->instance->name, names);
dialog->exec(); dialog->exec();
auto currentName = this->instance->name;
auto newName = dialog->getName();
Application::instance()->renameComponent(currentName, newName);
setToolTip(QString::fromStdString(instance->name + "::" + instance->component.getDisplayName()));
}); });
menu.addSeparator(); menu.addSeparator();
for (int i = 0; i < this->instance->attributes.size(); i++) { for (int i = 0; i < this->instance->attributes.size(); i++) {
auto *attr = &this->instance->attributes[i]; auto *attr = &this->instance->attributes[i];
bool enabled = attr->attribute.getPopup().has_value(); bool enabled = attr->attribute.getPopup().has_value();
auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name),
[attr]() {
if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) { if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) {
auto dialog = new MemoryDialog(attr, MainWindow::getSchema()->componentInstances); menu.addAction(QMESSAGE("msg_dialog_memory_update"), [attr]() {
auto dialog = new MemoryDialog(MESSAGE("msg_dialog_memory_update"),
MESSAGE("msg_dialog_actions_update"),
attr,
Application::instance()->getSchema()->componentInstances);
dialog->exec(); dialog->exec();
});
} else { } else {
auto dialog = new AttributeDialog(attr); std::map<std::string, std::string> params = {{"attribute", attr->attribute.getDisplayName()}};
auto action = menu.addAction(QMESSAGE_PARAM("msg_dialog_attribute_update", params),
[attr]() {
std::map<std::string, std::string> params = {{"attribute", attr->attribute.getDisplayName()}};
auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_attribute_update", params),
"msg_dialog_actions_update",
attr);
dialog->exec(); dialog->exec();
}
}); });
action->setEnabled(enabled); action->setEnabled(enabled);
} }
}
menu.addSeparator();
std::map<std::string, std::string> params = {{"name", instance->name}};
menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() {
Application::instance()->removeComponent(this->instance->name);
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
view->refreshContent();
});
menu.exec(event->screenPos()); menu.exec(event->screenPos());
} }
void Pin::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { void Pin::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
QMenu menu; QMenu menu;
menu.addAction("Connect pin", [&]() {});
auto pinConnections = Application::instance()->getSchema()->getConnections(componentInstance->name, pin.getName());
if(isSingleAutomatic(pinConnections)) {
auto *update = menu.addMenu(QMESSAGE("msg_pin_update"));
auto *remove = menu.addMenu(QMESSAGE("msg_pin_remove"));
for (auto pinConnection: pinConnections) {
// this always must be true as only directConnections can be connected multiple times
if (auto directConnection = dynamic_cast<domain::DirectConnectionInstance *>(pinConnection)) {
if (directConnection->bus->bus.getType() == domain::Bus::SINGLE_AUTOMATIC) {
auto params = MessageSource::instance()->map(
{{"wire1", directConnection->attributes[0].value},
{"wire2", directConnection->attributes[1].value}}
);
update->addAction(QMESSAGE_PARAM("msg_sa_pin_update_title", params),
[directConnection]() {
auto params = MessageSource::instance()->map(
{{"wire1", directConnection->attributes[0].value},
{"wire2", directConnection->attributes[1].value}}
);
auto dialog = new SingleAutomaticDialog(MESSAGE_PARAM("msg_sa_pin_update_title", params),
MESSAGE("msg_pin_update_action"),
directConnection->attributes);
dialog->exec();
});
remove->addAction(QMESSAGE_PARAM("msg_sa_pin_remove_title", params),
[this, directConnection]() {
Application::instance()->removeConnection(directConnection);
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
view->refreshContent();
});
}
}
}
} else if(!pinConnections.empty()) {
auto pinConnection = pinConnections[0];
if(auto busConnection = dynamic_cast<domain::BusConnectionInstance*>(pinConnection)) {
menu.addSection(QString::fromStdString(busConnection->bus->name));
} else if(auto directConnection = dynamic_cast<domain::DirectConnectionInstance*>(pinConnection)) {
if(directConnection->instance == componentInstance.get()) {
menu.addSection(QString::fromStdString(directConnection->secondInstance->name + "." + directConnection->connection.getSecondComponent()->pin));
} else {
menu.addSection(QString::fromStdString(directConnection->instance->name + "." + directConnection->connection.getComponent().pin));
}
}
for (int i = 0; i < pinConnection->attributes.size(); i++) {
auto *attr = &pinConnection->attributes[i];
std::map<std::string, std::string> params = {{"name", attr->attribute.getDisplayName()}};
menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_update_named", params),
[attr]() {
std::map<std::string, std::string> params = {{"name", attr->attribute.getDisplayName()}};
auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_actions_update_named", params), "msg_pin_update_action", attr);
dialog->exec();
});
}
menu.addAction(QMESSAGE("msg_pin_remove_action"), [this, pinConnection]() {
Application::instance()->removeConnection(pinConnection);
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
view->refreshContent();
});
}
menu.exec(event->screenPos()); menu.exec(event->screenPos());
} }
@ -46,8 +148,12 @@ void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]); auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
view->state = Schema::CREATING_CONNECTION; view->state = Schema::CREATING_CONNECTION;
view->context.pin = this; view->context.pin = this;
view->context.startingPoint = dynamic_cast<ComponentGroup*>(this->parentItem())->pos() + QPointF(pin.getDisplayPin().getConnectionX(), pin.getDisplayPin().getConnectionY()); view->context.startingPoint = dynamic_cast<ComponentGroup *>(this->parentItem())->pos() +
QPointF(pin.getDisplayPin().getConnectionX(),
pin.getDisplayPin().getConnectionY());
view->context.line = new QGraphicsLineItem(QLineF(view->context.startingPoint, event->scenePos())); view->context.line = new QGraphicsLineItem(QLineF(view->context.startingPoint, event->scenePos()));
view->context.line->setPen(QPen(QColor::fromRgb(100, 100, 250), 1, Qt::PenStyle::DashLine));
view->context.line->setZValue(1000);
this->scene()->addItem(view->context.line); this->scene()->addItem(view->context.line);
view->showConnectable(this); view->showConnectable(this);
@ -73,11 +179,54 @@ void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
} }
} }
domain::Pin &Pin::getPin() {
return pin;
}
domain::ComponentInstance *Pin::getComponentInstance() {
return componentInstance.get();
}
bool Pin::isSingleAutomatic(std::vector<domain::ConnectionInstance *> pinConnections) {
if(pinConnections.empty()) {
return false;
}
auto pinConnection = pinConnections[0];
if(auto directConnection = dynamic_cast<domain::DirectConnectionInstance*>(pinConnection)) {
return directConnection->bus->bus.getType() == domain::Bus::SINGLE_AUTOMATIC;
} else {
return false;
}
}
Bus::Bus(const std::shared_ptr<domain::BusInstance> &instance): busInstance(instance) {
instance->bus.getDisplayBus()->render(this, instance->size);
setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getName()));
}
void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
QMenu menu; QMenu menu;
menu.addAction("Izmjeni ime", [this](){ menu.addAction(QMESSAGE("msg_dialog_name_update"), [this]() {
auto dialog = new NameDialog(this->busInstance.get()); std::set<std::string> names;
for(const auto &component: Application::instance()->getSchema()->busInstances) {
names.insert(component->name);
}
auto dialog = new NameDialog(this->busInstance->name, names);
dialog->exec(); dialog->exec();
auto currentName = this->busInstance->name;
auto newName = dialog->getName();
Application::instance()->renameBus(currentName, newName);
setToolTip(QString::fromStdString(busInstance->name + "::" + busInstance->bus.getDisplayName()));
});
menu.addSeparator();
std::map<std::string, std::string> params = {{"name", busInstance->name}};
menu.addAction(QMESSAGE_PARAM("msg_dialog_actions_remove_named", params), [this]() {
Application::instance()->removeBus(this->busInstance->name);
auto view = dynamic_cast<Schema *>(this->scene()->views()[0]);
view->refreshContent();
}); });
menu.exec(event->screenPos()); menu.exec(event->screenPos());
} }
@ -85,7 +234,7 @@ void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
QVariant BusGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { QVariant BusGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) {
if (change == ItemPositionChange && scene()) { if (change == ItemPositionChange && scene()) {
// value is the new position. // value is the new position.
QPointF newPos = value.toPointF(); QPoint newPos = value.toPointF().toPoint();
busInstance->position.first = newPos.x(); busInstance->position.first = newPos.x();
busInstance->position.second = newPos.y(); busInstance->position.second = newPos.y();
@ -111,7 +260,7 @@ void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
QVariant ComponentGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { QVariant ComponentGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) {
if (change == ItemPositionChange && scene()) { if (change == ItemPositionChange && scene()) {
// value is the new position. // value is the new position.
QPointF newPos = value.toPointF(); QPoint newPos = value.toPointF().toPoint();
componentInstance->position.first = newPos.x(); componentInstance->position.first = newPos.x();
componentInstance->position.second = newPos.y(); componentInstance->position.second = newPos.y();
@ -121,40 +270,87 @@ void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
return QGraphicsItem::itemChange(change, value); return QGraphicsItem::itemChange(change, value);
} }
void BusConnection::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { std::shared_ptr<domain::ComponentInstance> ComponentGroup::getComponentInstance() {
QMenu menu; return componentInstance;
menu.addAction("Ukloni poveznicu", [this](){});
menu.addSeparator();
for(int i=0; i<this->connection->attributes.size(); i++) {
auto* attr = &this->connection->attributes[i];
bool enabled = attr->attribute.getPopup().has_value();
auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name),
[attr]() {
auto dialog = new AttributeDialog(attr);
dialog->exec();
});
action->setEnabled(enabled);
}
menu.exec(event->screenPos());
} }
void DirectConnection::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { std::vector<display::Pin *> &ComponentGroup::getPins() {
QMenu menu; return pins;
menu.addAction("Ukloni poveznicu", [this](){});
menu.addSeparator();
for(int i=0; i<this->connection->attributes.size(); i++) {
auto* attr = &this->connection->attributes[i];
bool enabled = attr->attribute.getPopup().has_value();
auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name),
[attr]() {
auto dialog = new AttributeDialog(attr);
dialog->exec();
});
action->setEnabled(enabled);
} }
menu.exec(event->screenPos());
ComponentGroup::ComponentGroup(const std::shared_ptr<domain::ComponentInstance> &instance): componentInstance(
instance) {
setFlag(ItemIsMovable, true);
setFlag(ItemSendsGeometryChanges, true);
setHandlesChildEvents(false);
addToGroup(new display::Component(instance));
for (auto &pin: instance->component.getPins()) {
pins.push_back(new display::Pin(pin, componentInstance));
addToGroup(pins.back());
}
setPos(instance->position.first, instance->position.second);
}
BusConnection::BusConnection(domain::BusConnectionInstance *connection, ComponentGroup *component, BusGroup *bus): connection(
connection), component(component), bus(bus) {
updateConnection();
setPen(connectionPen);
setZValue(-1);
setHandlesChildEvents(false);
}
void BusConnection::updateConnection() {
auto busPosition = bus->boundingRect();
auto pin = connection->instance->component.getPin(
connection->connection.getComponent().pin).getDisplayPin();
setLine(connection->instance->position.first + pin.getConnectionX(),
connection->instance->position.second + pin.getConnectionY(),
connection->bus->position.first + busPosition.width() / 2,
connection->bus->position.second + busPosition.height() / 2);
connection->start.first = connection->instance->position.first + pin.getConnectionX();
connection->start.second = connection->instance->position.second + pin.getConnectionY();
connection->end.first = connection->bus->position.first + busPosition.width() / 2;
connection->end.second = connection->bus->position.second + busPosition.height() / 2;
}
DirectConnection::DirectConnection(domain::DirectConnectionInstance *connection, ComponentGroup *first,
ComponentGroup *second): connection(connection), first(first), second(second) {
updateConnection();
setPen(connectionPen);
setZValue(-1);
setHandlesChildEvents(false);
}
void DirectConnection::updateConnection() {
domain::ui::Pin pin1, pin2;
if(connection->connection.getComponent().component == connection->instance->component.getName()) {
pin1 = connection->instance->component.getPin(
connection->connection.getComponent().pin).getDisplayPin();
pin2 = connection->secondInstance->component.getPin(
connection->connection.getSecondComponent()->pin).getDisplayPin();
} else {
pin1 = connection->instance->component.getPin(
connection->connection.getSecondComponent()->pin).getDisplayPin();
pin2 = connection->secondInstance->component.getPin(
connection->connection.getComponent().pin).getDisplayPin();
}
setLine(connection->instance->position.first + pin1.getConnectionX(),
connection->instance->position.second + pin1.getConnectionY(),
connection->secondInstance->position.first + pin2.getConnectionX(),
connection->secondInstance->position.second + pin2.getConnectionY());
connection->start.first = connection->instance->position.first + pin1.getConnectionX();
connection->start.second = connection->instance->position.second + pin1.getConnectionY();
connection->end.first = connection->secondInstance->position.first + pin2.getConnectionX();
connection->end.second = connection->secondInstance->position.second + pin2.getConnectionY();
} }
} // namespace display } // namespace display

View File

@ -2,99 +2,78 @@
#define DISPLAY_COMPONENT_H #define DISPLAY_COMPONENT_H
#include <comdel/domain/instance.h> #include <comdel/domain/instance.h>
#include <comdel/domain/wireinstance.h>
#include <QGraphicsItemGroup> #include <QGraphicsItemGroup>
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
#include "comdel/domain/connectioninstance.h" #include <utility>
#include "comdel/domain/connection_instance.h"
namespace display { namespace display {
class Pin: public QGraphicsItemGroup class Pin : public QGraphicsItemGroup {
{
private: private:
domain::Pin pin; domain::Pin pin;
std::shared_ptr<domain::ComponentInstance> componentInstance; std::shared_ptr<domain::ComponentInstance> componentInstance;
public: public:
Pin(domain::Pin pin, std::shared_ptr<domain::ComponentInstance> componentInstance): pin(pin), componentInstance(componentInstance) { Pin(domain::Pin pin, std::shared_ptr<domain::ComponentInstance> componentInstance) : pin(pin), componentInstance(std::move(componentInstance)) {
pin.getDisplayPin().render(this); pin.getDisplayPin().render(this);
this->setToolTip(QString::fromStdString(pin.getTooltip()));
} }
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
domain::Pin& getPin() { domain::Pin &getPin();
return pin;
}
domain::ComponentInstance* getComponentInstance() { domain::ComponentInstance *getComponentInstance();
return componentInstance.get();
} bool isSingleAutomatic(std::vector<domain::ConnectionInstance *> pinConnections);
}; };
class Component: public QGraphicsItemGroup class Component : public QGraphicsItemGroup {
{
private: private:
std::shared_ptr<domain::ComponentInstance> instance; std::shared_ptr<domain::ComponentInstance> instance;
public: public:
Component(const std::shared_ptr<domain::ComponentInstance>& instance): instance(instance) { explicit Component(const std::shared_ptr<domain::ComponentInstance> &instance);
setFlag(ItemSendsGeometryChanges, true);
instance->component.getDisplay().render(this);
}
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
}; };
class Bus: public QGraphicsItemGroup class Bus : public QGraphicsItemGroup {
{
std::shared_ptr<domain::BusInstance> busInstance; std::shared_ptr<domain::BusInstance> busInstance;
public: public:
Bus(const std::shared_ptr<domain::BusInstance>& instance): busInstance(instance) { explicit Bus(const std::shared_ptr<domain::BusInstance> &instance);
instance->bus.getDisplayBus()->render(this, instance->size);
}
domain::BusInstance *getBusInstance() { return busInstance.get(); }
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
}; };
class ComponentGroup: public QGraphicsItemGroup class ComponentGroup : public QGraphicsItemGroup {
{
private: private:
std::shared_ptr<domain::ComponentInstance> componentInstance; std::shared_ptr<domain::ComponentInstance> componentInstance;
std::vector<display::Pin *> pins; std::vector<display::Pin *> pins;
public: public:
std::shared_ptr<domain::ComponentInstance> getComponentInstance() { return componentInstance; } std::shared_ptr<domain::ComponentInstance> getComponentInstance();
std::vector<display::Pin*>& getPins() { return pins; }
explicit ComponentGroup(const std::shared_ptr<domain::ComponentInstance>& instance): componentInstance(instance) { std::vector<display::Pin *> &getPins();
setFlag(ItemIsMovable, true);
setFlag(ItemSendsGeometryChanges, true);
setHandlesChildEvents(false); explicit ComponentGroup(const std::shared_ptr<domain::ComponentInstance> &instance);
addToGroup(new display::Component(instance));
for(auto &pin: instance->component.getPins()) {
pins.push_back(new display::Pin(pin, componentInstance));
addToGroup(pins.back());
}
setPos(instance->position.first, instance->position.second);
}
protected: protected:
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
}; };
class BusGroup: public QGraphicsItemGroup class BusGroup : public QGraphicsItemGroup {
{
private: private:
std::shared_ptr<domain::BusInstance> busInstance; std::shared_ptr<domain::BusInstance> busInstance;
display::Bus *bus; display::Bus *bus;
@ -102,71 +81,33 @@ private:
public: public:
explicit BusGroup(const std::shared_ptr<domain::BusInstance> &instance); explicit BusGroup(const std::shared_ptr<domain::BusInstance> &instance);
display::Bus* getBus() { return bus; }
protected: protected:
virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
}; };
class BusConnection: public QGraphicsLineItem class BusConnection : public QGraphicsLineItem {
{
private: private:
domain::BusConnectionInstance *connection; domain::BusConnectionInstance *connection;
ComponentGroup *component; ComponentGroup *component;
BusGroup *bus; BusGroup *bus;
public: public:
BusConnection(domain::BusConnectionInstance* connection, ComponentGroup *component, BusGroup *bus): connection(connection), component(component), bus(bus) { BusConnection(domain::BusConnectionInstance *connection, ComponentGroup *component, BusGroup *bus);
updateConnection();
setHandlesChildEvents(false); void updateConnection();
}
void updateConnection() {
auto busPosition = bus->boundingRect();
auto pin = connection->instance->component.getPin(connection->connection.getComponent().pin).getDisplayPin();
setLine(connection->instance->position.first + pin.getConnectionX(), connection->instance->position.second + pin.getConnectionY(), connection->bus->position.first + busPosition.width()/2, connection->bus->position.second + busPosition.height()/2);
connection->start.first = connection->instance->position.first + pin.getConnectionX();
connection->start.second = connection->instance->position.second + pin.getConnectionY();
connection->end.first = connection->bus->position.first + busPosition.width()/2;
connection->end.second = connection->bus->position.second + busPosition.height()/2;
}
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
}; };
class DirectConnection: public QGraphicsLineItem class DirectConnection : public QGraphicsLineItem {
{
private: private:
domain::DirectConnectionInstance *connection; domain::DirectConnectionInstance *connection;
ComponentGroup *first; ComponentGroup *first;
ComponentGroup *second; ComponentGroup *second;
public: public:
DirectConnection(domain::DirectConnectionInstance* connection, ComponentGroup *first, ComponentGroup *second): connection(connection), first(first), second(second) { DirectConnection(domain::DirectConnectionInstance *connection, ComponentGroup *first, ComponentGroup *second);
updateConnection();
setHandlesChildEvents(false);
}
void updateConnection() { void updateConnection();
auto pin1 = connection->instance->component.getPin(connection->connection.getComponent().pin).getDisplayPin();
auto pin2 = connection->secondInstance->component.getPin(connection->connection.getSecondComponent()->pin).getDisplayPin();
setLine(connection->instance->position.first + pin1.getConnectionX(), connection->instance->position.second + pin1.getConnectionY(),
connection->secondInstance->position.first + pin2.getConnectionX(), connection->secondInstance->position.second + pin2.getConnectionY());
connection->start.first = connection->instance->position.first + pin1.getConnectionX();
connection->start.second = connection->instance->position.second + pin1.getConnectionY();
connection->end.first = connection->secondInstance->position.first + pin2.getConnectionX();
connection->end.second = connection->secondInstance->position.second + pin2.getConnectionY();
}
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
}; };

View File

@ -0,0 +1,182 @@
#include "attribute_dialog.h"
#include "mainwindow.h"
#include "application.h"
#include "error_dialog.h"
#include "warning_dialog.h"
#include "message_source.h"
#include <stdexcept>
namespace display {
long long int parseInt(std::string expression) {
try {
if (expression.size() > 2) {
if (expression.substr(0, 2) == "0x") {
return std::stoll(expression, nullptr, 16);
} else if (expression.substr(0, 2) == "0b") {
return std::stoll(expression, nullptr, 2);
} else {
return std::stoll(expression, nullptr, 10);
}
} else {
return std::stoll(expression, nullptr, 10);
}
} catch (std::exception &e) {
return 0;
}
}
AttributeDialog::AttributeDialog(std::string title, std::string action, domain::InstanceAttribute *attribute):
GenericDialog(title, action), attributeValue(attribute), value(attribute->value), popup(*attribute->attribute.getPopup()) {
auto *contentLayout = new QVBoxLayout();
content->setLayout(contentLayout);
contentLayout->addWidget(new QLabel(popup.getTitle().c_str()));
contentLayout->addWidget(new QLabel(popup.getText().c_str()));
auto type = attribute->value.getType();
if(popup.isEnumerated()) {
contentLayout->addWidget(setupEnumeration());
} else if(type == domain::Value::INT || type == domain::Value::STRING) {
contentLayout->addWidget(setupLineEdit(type));
} else if(type == domain::Value::BOOL) {
contentLayout->addWidget(setupBool());
}
}
bool AttributeDialog::onUpdate() {
auto validationErrors = validate();
if (validationErrors.empty()) {
attributeValue->value = value;
return true;
}
std::vector<domain::ValidationError> errors, warnings;
for (auto &err: validationErrors) {
if (err.type == domain::Action::ERROR) {
errors.push_back(err);
} else {
warnings.push_back(err);
}
}
if (!errors.empty()) {
auto errorDialog = new ErrorDialog(errors);
errorDialog->exec();
return false;
}
bool canAccept = true;
for (auto &warning: warnings) {
auto warningDialog = new WarningDialog(warning);
int response = warningDialog->exec();
if (response == QDialog::Rejected) {
canAccept = false;
}
}
if(canAccept) {
attributeValue->value = value;
}
return canAccept;
}
void AttributeDialog::onTextChanged(const QString &string) {
switch (value.getType()) {
case domain::Value::STRING:
value.setString(string.toStdString());
break;
case domain::Value::INT:
value = domain::Value::fromInt(parseInt(string.toStdString()));
break;
default:
throw std::runtime_error("invalid value type in text change");
}
}
void AttributeDialog::onEnumerationChanged(int index) {
value = attributeValue->attribute.getPopup()->getEnumeration()[index].getValue();
}
QComboBox *AttributeDialog::setupEnumeration() {
auto *combo = new QComboBox(this);
auto enumeration = popup.getEnumeration();
for (auto entry: enumeration) {
combo->addItem(QString::fromStdString(entry.getName()));
}
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&AttributeDialog::onEnumerationChanged);
for (int i = 0; i < enumeration.size(); i++) {
if (attributeValue->value.equals(enumeration[i].getValue())) {
combo->setCurrentIndex(i);
break;
}
}
return combo;
}
QLineEdit *AttributeDialog::setupLineEdit(domain::Value::ValueType type) {
auto edit = new QLineEdit(this);
connect(edit, &QLineEdit::textChanged, this, &AttributeDialog::onTextChanged);
switch (type) {
case domain::Value::ValueType::INT:
edit->setValidator(new QIntValidator(-10000000, 10000000, edit));
edit->insert(std::to_string(value.asInt()).c_str());
break;
case domain::Value::ValueType::STRING:
edit->insert(value.asString().c_str());
break;
}
return edit;
}
QGroupBox *AttributeDialog::setupBool() {
auto *group = new QGroupBox(this);
auto *radioLayout = new QHBoxLayout(group);
group->setLayout(radioLayout);
auto isTrue = new QRadioButton(QMESSAGE("msg_boolean_true"), group);
connect(isTrue, &QRadioButton::clicked, [this]() {
this->value = domain::Value::fromBool(true);
});
auto isFalse = new QRadioButton(QMESSAGE("msg_boolean_false"), group);
connect(isFalse, &QRadioButton::clicked, [this]() {
this->value = domain::Value::fromBool(false);
});
if (value.asBool()) {
isTrue->setChecked(true);
} else {
isFalse->setChecked(true);
}
radioLayout->addWidget(isTrue);
radioLayout->addWidget(isFalse);
return group;
}
std::vector<domain::ValidationError> AttributeDialog::validate() {
domain::ComdelValidator validator(domain::getSupportedValidators());
auto currentValue = attributeValue->value;
attributeValue->value = value;
domain::ValidationContext context;
for (auto &addressSpace: Application::instance()->getLibrary()->getAddressSpaces()) {
context.addressSpaces.insert(std::make_pair(addressSpace.getName(), addressSpace));
}
auto errors = validator.validateAttribute(attributeValue, context);
attributeValue->value = currentValue;
return errors;
}
}

View File

@ -0,0 +1,47 @@
#ifndef ATTRIBUTE_DIALOG_H
#define ATTRIBUTE_DIALOG_H
#include <QIntValidator>
#include <QPushButton>
#include <QComboBox>
#include <QGroupBox>
#include <QRadioButton>
#include <QDialog>
#include <QLineEdit>
#include <QLabel>
#include <QVBoxLayout>
#include <utility>
#include "comdel/domain/instance_attribute.h"
#include "comdel/domain/value.h"
#include "comdel/domain/comdel_validator.h"
#include "generic_dialog.h"
namespace display {
class AttributeDialog : public GenericDialog {
public:
AttributeDialog(std::string title, std::string action, domain::InstanceAttribute *attribute);
public slots:
void onTextChanged(const QString &string);
void onEnumerationChanged(int index);
protected:
bool onUpdate() override;
private:
QComboBox *setupEnumeration();
QLineEdit *setupLineEdit(domain::Value::ValueType type);
QGroupBox *setupBool();
std::vector<domain::ValidationError> validate();
domain::Value value;
domain::InstanceAttribute *attributeValue;
domain::Popup popup;
};
}
#endif //ATTRIBUTE_DIALOG_H

View File

@ -0,0 +1,34 @@
#include <QVBoxLayout>
#include <QLabel>
#include <QPlainTextEdit>
#include "error_dialog.h"
namespace display {
ErrorDialog::ErrorDialog(std::vector<domain::ValidationError> errors)
: GenericDialog("msg_dialog_error_title", std::nullopt, "msg_dialog_error_close") {
auto contentLayout = new QVBoxLayout();
content->setLayout(contentLayout);
for (auto &err: errors) {
contentLayout->addWidget(new QLabel(QString::fromStdString(err.message), this));
}
}
ErrorDialog::ErrorDialog(std::ostringstream& errorStream)
: GenericDialog("msg_dialog_error_title", std::nullopt, "msg_dialog_error_close") {
auto contentLayout = new QVBoxLayout();
content->setLayout(contentLayout);
setMinimumWidth(1000);
auto log = new QPlainTextEdit();
log->setFont(QFont("Courier"));
log->appendPlainText(QString::fromStdString(errorStream.str()));
log->setReadOnly(true);
contentLayout->addWidget(log);
}
} // display

View File

@ -0,0 +1,22 @@
#ifndef SCHEMEEDITOR_ERROR_DIALOG_H
#define SCHEMEEDITOR_ERROR_DIALOG_H
#include "generic_dialog.h"
#include "comdel/domain/comdel_validator.h"
#include <sstream>
namespace display {
class ErrorDialog : public GenericDialog {
public:
ErrorDialog(std::vector<domain::ValidationError> errors);
ErrorDialog(std::ostringstream& errorStream);
protected:
bool onUpdate() override { return true; }
};
} // display
#endif //SCHEMEEDITOR_ERROR_DIALOG_H

View File

@ -0,0 +1,35 @@
#include <QVBoxLayout>
#include "generic_dialog.h"
#include "message_source.h"
display::GenericDialog::GenericDialog(std::string title, std::optional<std::string> action, std::string cancel) {
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle(QMESSAGE(title));
setLayout(new QVBoxLayout());
content = new QWidget(this);
layout()->addWidget(content);
auto actionWidget = new QWidget(this);
auto actionBar = new QHBoxLayout(actionWidget);
layout()->addWidget(actionWidget);
// if action isn't defined only close button is offered
if(action.has_value()) {
okButton = new QPushButton(QMESSAGE(*action), this);
connect(okButton, &QPushButton::clicked, this, [this](){
if(this->onUpdate()) {
this->accept();
}
});
actionBar->addWidget(okButton);
}
cancelButton = new QPushButton(QMESSAGE(cancel), this);
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
actionBar->addWidget(cancelButton);
}
void display::GenericDialog::setOkButtonDisabled(bool disabled) {
okButton->setDisabled(disabled);
}

View File

@ -0,0 +1,33 @@
#ifndef SCHEMEEDITOR_GENERIC_DIALOG_H
#define SCHEMEEDITOR_GENERIC_DIALOG_H
#include <QDialog>
#include <QWidget>
#include <QPushButton>
#include <optional>
namespace display {
class GenericDialog: public QDialog {
public:
explicit GenericDialog(std::string title,
std::optional<std::string> action = "msg_dialog_actions_update",
std::string cancel = "msg_dialog_actions_cancel");
protected:
void setOkButtonDisabled(bool disabled);
virtual bool onUpdate() = 0;
private:
QPushButton *okButton;
QPushButton *cancelButton;
protected:
QWidget *content;
};
}
#endif //SCHEMEEDITOR_GENERIC_DIALOG_H

View File

@ -0,0 +1,60 @@
#include <QVBoxLayout>
#include <QLabel>
#include "memory_dialog.h"
#include "message_source.h"
namespace display {
MemoryDialog::MemoryDialog(std::string title, std::string action, domain::InstanceAttribute *attribute,
std::vector<std::shared_ptr<domain::ComponentInstance>> instances)
: GenericDialog(title, action), value(attribute->value), attributeValue(attribute), popup(*attribute->attribute.getPopup()) {
for (auto &instance: instances) {
if (instance->component.getType() == domain::Component::MEMORY) {
memoryInstances.push_back(instance->name);
}
}
auto contentLayout = new QVBoxLayout(content);
content->setLayout(contentLayout);
contentLayout->addWidget(new QLabel(popup.getTitle().c_str()));
contentLayout->addWidget(new QLabel(popup.getText().c_str()));
contentLayout->addWidget(setupEnumeration());
}
bool MemoryDialog::onUpdate() {
attributeValue->value = value;
return true;
}
QComboBox *MemoryDialog::setupEnumeration() {
auto *combo = new QComboBox(this);
for (const auto& entry: memoryInstances) {
combo->addItem(QString::fromStdString(entry));
}
combo->addItem(QMESSAGE("msg_dialog_memory_default"));
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) {
if(index == memoryInstances.size()) {
value = domain::Value::fromMemoryReference(std::nullopt);
} else {
value = domain::Value::fromMemoryReference(this->memoryInstances[index]);
}
});
combo->setCurrentIndex(memoryInstances.size());
for (int i = 0; i < memoryInstances.size(); i++) {
if (attributeValue->value.equals(domain::Value::fromMemoryReference(memoryInstances[i]))) {
combo->setCurrentIndex(i);
break;
}
}
return combo;
}
} // display

View File

@ -0,0 +1,33 @@
#ifndef SCHEMEEDITOR_MEMORY_DIALOG_H
#define SCHEMEEDITOR_MEMORY_DIALOG_H
#include <QComboBox>
#include "generic_dialog.h"
#include "comdel/domain/instance_attribute.h"
#include "comdel/domain/instance.h"
namespace display {
class MemoryDialog : public GenericDialog {
public:
MemoryDialog(std::string title, std::string action, domain::InstanceAttribute *attribute,
std::vector<std::shared_ptr<domain::ComponentInstance>> instances);
protected:
bool onUpdate() override;
private:
QComboBox *setupEnumeration();
domain::Value value;
domain::InstanceAttribute *attributeValue;
std::vector<std::string> memoryInstances;
domain::Popup popup;
};
} // display
#endif //SCHEMEEDITOR_MEMORY_DIALOG_H

View File

@ -0,0 +1,40 @@
#include <set>
#include "name_dialog.h"
#include "message_source.h"
namespace display {
NameDialog::NameDialog(std::string currentName, std::set<std::string> &names)
: GenericDialog("msg_dialog_name_update"), currentName(currentName), usedNames(names) {
usedNames.erase(currentName);
auto *contentLayout = new QVBoxLayout();
contentLayout->addWidget(new QLabel(QMESSAGE("msg_dialog_name_update"), this));
edit = new QLineEdit(this);
edit->insert(currentName.c_str());
connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate);
contentLayout->addWidget(edit);
content->setLayout(contentLayout);
}
void NameDialog::onNameUpdate(const QString &text) {
if(usedNames.find(text.toStdString()) == usedNames.end()) {
setOkButtonDisabled(false);
} else {
setOkButtonDisabled(true);
}
}
std::string NameDialog::getName() {
return currentName;
}
bool NameDialog::onUpdate() {
currentName = edit->text().toStdString();
return true;
}
}

View File

@ -0,0 +1,40 @@
#ifndef NAME_DIALOG_H
#define NAME_DIALOG_H
#include <QDialog>
#include <QLabel>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <set>
#include "comdel/domain/instance.h"
#include "generic_dialog.h"
namespace display {
class NameDialog : public GenericDialog {
public:
NameDialog(std::string currentName, std::set<std::string>& names);
std::string getName();
protected:
bool onUpdate() override;
public slots:
void onNameUpdate(const QString& text);
private:
std::set<std::string> usedNames;
QLineEdit *edit = nullptr;
std::string currentName;
};
}
#endif //NAME_DIALOG_H

View File

@ -0,0 +1,65 @@
#include "single_automatic_dialog.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QComboBox>
#include <QPushButton>
namespace display {
SingleAutomaticDialog::SingleAutomaticDialog(std::string title, std::string action,
std::vector<domain::InstanceAttribute> &values)
: GenericDialog(title, action), attributes(values) {
firstValue = values[0].value;
secondValue = values[1].value;
auto *contentLayout = new QHBoxLayout();
auto *firstLayout = new QVBoxLayout();
auto *secondLayout = new QVBoxLayout();
content->setLayout(contentLayout);
contentLayout->addLayout(firstLayout);
contentLayout->addLayout(secondLayout);
setupValues(firstLayout, values[0], &SingleAutomaticDialog::onFirstEnumerationChanged);
setupValues(secondLayout, values[1], &SingleAutomaticDialog::onSecondEnumerationChanged);
}
void SingleAutomaticDialog::setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)) {
auto popup = *attribute.attribute.getPopup();
layout->addWidget(new QLabel(popup.getTitle().c_str()));
layout->addWidget(new QLabel(popup.getText().c_str()));
auto *combo = new QComboBox(this);
auto enumeration = attribute.attribute.getPopup()->getEnumeration();
for (auto entry: enumeration) {
combo->addItem(QString::fromStdString(entry.getName()));
}
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this,handler);
layout->addWidget(combo);
for (int i = 0; i < enumeration.size(); i++) {
if (attribute.value.equals(enumeration[i].getValue())) {
combo->setCurrentIndex(i);
break;
}
}
}
void SingleAutomaticDialog::onFirstEnumerationChanged(int index) {
firstValue = attributes[0].attribute.getPopup()->getEnumeration()[index].getValue();
}
void SingleAutomaticDialog::onSecondEnumerationChanged(int index) {
secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue();
}
bool SingleAutomaticDialog::onUpdate() {
attributes[0].value = firstValue;
attributes[1].value = secondValue;
return true;
}
} // display

View File

@ -0,0 +1,36 @@
#ifndef SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
#define SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
#include <vector>
#include <QDialog>
#include <QVBoxLayout>
#include "comdel/domain/value.h"
#include "comdel/domain/instance_attribute.h"
#include "generic_dialog.h"
namespace display {
class SingleAutomaticDialog: public GenericDialog {
domain::Value firstValue;
domain::Value secondValue;
std::vector<domain::InstanceAttribute> &attributes;
public:
explicit SingleAutomaticDialog(
std::string title,
std::string action,
std::vector<domain::InstanceAttribute>& values);
protected:
bool onUpdate() override;
void setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int));
public slots:
void onFirstEnumerationChanged(int index);
void onSecondEnumerationChanged(int index);
};
} // display
#endif //SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H

View File

@ -0,0 +1,19 @@
#include <QVBoxLayout>
#include <QLabel>
#include <QPushButton>
#include "success_dialog.h"
#include "message_source.h"
namespace display {
SuccessDialog::SuccessDialog(std::string message) {
setLayout(new QVBoxLayout());
setWindowTitle(QMESSAGE("msg_dialog_success_title"));
layout()->addWidget(new QLabel(QString::fromStdString(message)));
auto button = new QPushButton(QMESSAGE("msg_dialog_actions_ok"));
connect(button, &QPushButton::clicked, [this]() {accept();});
layout()->addWidget(button);
}
} // display

View File

@ -0,0 +1,19 @@
//
// Created by bbr on 14.06.22..
//
#ifndef SCHEMEEDITOR_SUCCESS_DIALOG_H
#define SCHEMEEDITOR_SUCCESS_DIALOG_H
#include <QDialog>
namespace display {
class SuccessDialog: public QDialog {
public:
explicit SuccessDialog(std::string message);
};
} // display
#endif //SCHEMEEDITOR_SUCCESS_DIALOG_H

View File

@ -0,0 +1,16 @@
#include <QVBoxLayout>
#include <QLabel>
#include "warning_dialog.h"
namespace display {
WarningDialog::WarningDialog(domain::ValidationError error)
: GenericDialog("msg_dialog_warning_title", "msg_dialog_actions_ok") {
auto contentLayout = new QVBoxLayout();
content->setLayout(contentLayout);
contentLayout->addWidget(new QLabel(QString::fromStdString(error.message), this));
}
} // display

View File

@ -0,0 +1,20 @@
#ifndef SCHEMEEDITOR_WARNING_DIALOG_H
#define SCHEMEEDITOR_WARNING_DIALOG_H
#include "generic_dialog.h"
#include "comdel/domain/comdel_validator.h"
namespace display {
class WarningDialog : public GenericDialog {
public:
WarningDialog(domain::ValidationError error);
protected:
bool onUpdate() override { return true; };
};
} // display
#endif //SCHEMEEDITOR_WARNING_DIALOG_H

View File

@ -1,30 +1,37 @@
#include "library_display.h" #include "library_display.h"
#include "message_source.h"
#include <QLabel> #include <QLabel>
#include <QListWidget> #include <QListWidget>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <application.h>
namespace display { namespace display {
Library::Library() Library::Library() {
{
auto layout = new QVBoxLayout(); auto layout = new QVBoxLayout();
this->setLayout(layout); this->setLayout(layout);
componentList = new LibraryList(this); componentList = new LibraryList(this);
busList = new LibraryList(this); busList = new LibraryList(this);
layout->setMargin(4); layout->setContentsMargins(4, 4, 4, 4);
layout->addWidget(new QLabel("Components:"));
componentsLabel = new QLabel(QMESSAGE("msg_sidebar_components"));
busLabel = new QLabel(QMESSAGE("msg_sidebar_busses"));
layout->addWidget(componentsLabel);
layout->addWidget(componentList, 1); layout->addWidget(componentList, 1);
layout->addSpacing(8); layout->addSpacing(8);
layout->addWidget(new QLabel("Buses:")); layout->addWidget(busLabel);
layout->addWidget(busList, 1); layout->addWidget(busList, 1);
setLibrary(library);
} }
void Library::setLibrary(std::optional<domain::Library> library) { void Library::refreshContent() {
library = Application::instance()->getLibrary();
componentsLabel->setText(QMESSAGE("msg_sidebar_components"));
busLabel->setText(QMESSAGE("msg_sidebar_busses"));
componentList->clear(); componentList->clear();
busList->clear(); busList->clear();
@ -34,14 +41,15 @@ void Library::setLibrary(std::optional<domain::Library> library) {
} }
for (auto &component: library->getComponents()) { for (auto &component: library->getComponents()) {
auto item = new LibraryListItem{component.getName(), "comdel/component", component.getName(), componentList}; auto item = new LibraryListItem{component.getDisplayName(), "comdel/component", component.getName(),
componentList};
item->setToolTip(QString::fromStdString(component.getTooltip())); item->setToolTip(QString::fromStdString(component.getTooltip()));
componentList->addItem(item); componentList->addItem(item);
} }
for (auto &bus: library->getBuses()) { for (auto &bus: library->getBuses()) {
if (bus.getType() == domain::Bus::REGULAR) { if (bus.getType() == domain::Bus::REGULAR) {
auto item = new LibraryListItem{bus.getName(), "comdel/bus", bus.getName(), busList}; auto item = new LibraryListItem{bus.getDisplayName(), "comdel/bus", bus.getName(), busList};
item->setToolTip(QString::fromStdString(bus.getTooltip())); item->setToolTip(QString::fromStdString(bus.getTooltip()));
busList->addItem(item); busList->addItem(item);
} }

View File

@ -5,16 +5,16 @@
#include <QWidget> #include <QWidget>
#include <comdel/domain/library.h> #include <comdel/domain/library.h>
#include <QLabel>
#include "library_list.h" #include "library_list.h"
namespace display { namespace display {
class Library: public QWidget class Library : public QWidget {
{
public: public:
Library(); Library();
void setLibrary(std::optional<domain::Library> library); void refreshContent();
private: private:
std::optional<domain::Library> library; std::optional<domain::Library> library;
@ -22,6 +22,8 @@ private:
LibraryList *componentList; LibraryList *componentList;
LibraryList *busList; LibraryList *busList;
QLabel *componentsLabel;
QLabel *busLabel;
}; };
} // namespace display } // namespace display

View File

@ -25,7 +25,8 @@ namespace display {
return nullptr; return nullptr;
} }
LibraryListItem::LibraryListItem(std::string title, std::string mimeType, std::string value, QListWidget *parent): QListWidgetItem(parent), mimeType(mimeType), value(value) { LibraryListItem::LibraryListItem(std::string title, std::string mimeType, std::string value, QListWidget *parent)
: QListWidgetItem(parent), mimeType(mimeType), value(value) {
setText(QString::fromStdString(title)); setText(QString::fromStdString(title));
} }
} // display } // display

View File

@ -1,5 +0,0 @@
//
// Created by bbr on 18. 04. 2022..
//
#include "name_dialog.h"

View File

@ -1,64 +0,0 @@
#ifndef NAME_DIALOG_H
#define NAME_DIALOG_H
#include <QDialog>
#include <QLabel>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QPushButton>
#include <comdel/domain/instance.h>
namespace display {
class NameDialog: public QDialog {
QLineEdit *edit = nullptr;
domain::ComponentInstance *componentInstance = nullptr;
domain::BusInstance *busInstance = nullptr;
public:
NameDialog(domain::ComponentInstance *instance): componentInstance(instance) {
auto *layout = new QVBoxLayout(this);
layout->addWidget(new QLabel("Izmjeni ime", this));
edit = new QLineEdit(this);
edit->insert(instance->name.c_str());
layout->addWidget(edit);
this->setWindowTitle("Izmjeni ime");
auto *button = new QPushButton("Ažuriraj", this);
connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange);
layout->addWidget(button);
this->setLayout(layout);
}
NameDialog(domain::BusInstance *instance): busInstance(instance) {
auto *layout = new QVBoxLayout(this);
layout->addWidget(new QLabel("Izmjeni ime", this));
edit = new QLineEdit(this);
edit->insert(instance->name.c_str());
layout->addWidget(edit);
this->setWindowTitle("Izmjeni ime");
auto *button = new QPushButton("Ažuriraj", this);
connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange);
layout->addWidget(button);
this->setLayout(layout);
}
public slots:
void onNameChange() {
if(componentInstance != nullptr) {
componentInstance->name = this->edit->text().toStdString();
} else if(busInstance != nullptr) {
busInstance->name = this->edit->text().toStdString();
}
this->close();
}
};
}
#endif //NAME_DIALOG_H

View File

@ -1,31 +1,39 @@
#include "component_display.h" #include "component_display.h"
#include "schema_display.h" #include "schema_display.h"
#include "application.h"
#include "comdel/display/dialog/attribute_dialog.h"
#include "comdel/display/dialog/single_automatic_dialog.h"
#include "comdel/display/dialog/memory_dialog.h"
#include <QDrag> #include <QDrag>
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QMimeData> #include <QMimeData>
#include "message_source.h"
namespace display { namespace display {
Schema::Schema() Schema::Schema() {
{ schema = nullptr;
this->selectedBrush.setColor(QColor::fromRgb(20,20,125)); library = std::nullopt;
this->selectedPen.setColor(QColor::fromRgb(20, 20, 125)); setRenderHint(QPainter::Antialiasing);
setAlignment(Qt::AlignCenter);
this->setScene(&scene); this->setScene(&scene);
this->setAcceptDrops(true); this->setAcceptDrops(true);
} }
void Schema::setSchema(domain::Schema* _schema, domain::Library* _library) void Schema::refreshContent() {
{ schema = Application::instance()->getSchema();
library = Application::instance()->getLibrary();
components.clear(); components.clear();
buses.clear(); buses.clear();
scene.clear(); scene.clear();
pins.clear();
busConnections.clear(); busConnections.clear();
this->schema = _schema; directConnections.clear();
this->library = _library;
if (schema != nullptr) { if (schema != nullptr) {
for (auto &instance: schema->componentInstances) { for (auto &instance: schema->componentInstances) {
auto group = new display::ComponentGroup(instance); auto group = new display::ComponentGroup(instance);
@ -47,13 +55,15 @@ void Schema::setSchema(domain::Schema* _schema, domain::Library* _library)
for (auto &connection: schema->connections) { for (auto &connection: schema->connections) {
auto busInstance = dynamic_cast<domain::BusConnectionInstance *>(connection.get()); auto busInstance = dynamic_cast<domain::BusConnectionInstance *>(connection.get());
if (busInstance != nullptr) { if (busInstance != nullptr) {
auto con = new display::BusConnection(busInstance, components[busInstance->instance->name], buses[busInstance->bus->name]); auto con = new display::BusConnection(busInstance, components[busInstance->instance->name],
buses[busInstance->bus->name]);
busConnections.push_back(con); busConnections.push_back(con);
scene.addItem(con); scene.addItem(con);
} }
auto directInstance = dynamic_cast<domain::DirectConnectionInstance *>(connection.get()); auto directInstance = dynamic_cast<domain::DirectConnectionInstance *>(connection.get());
if (directInstance != nullptr) { if (directInstance != nullptr) {
auto con = new display::DirectConnection(directInstance, components[directInstance->instance->name], components[directInstance->secondInstance->name]); auto con = new display::DirectConnection(directInstance, components[directInstance->instance->name],
components[directInstance->secondInstance->name]);
directConnections.push_back(con); directConnections.push_back(con);
scene.addItem(con); scene.addItem(con);
} }
@ -83,15 +93,14 @@ void Schema::updateConnections() {
if (event->mimeData()->hasFormat("comdel/component")) { if (event->mimeData()->hasFormat("comdel/component")) {
auto component = library->getComponent(event->mimeData()->data("comdel/component").toStdString()); auto component = library->getComponent(event->mimeData()->data("comdel/component").toStdString());
auto attributes = std::vector<domain::InstanceAttribute>(); auto attributes = populateAttributes(component.getAttributes());
for(auto attr: component.getAttributes()) { if(attributes.size() != component.getAttributes().size()) {
attributes.emplace_back(attr.getName(), attr.getDefault(), attr); return;
} }
auto currentPos = this->mapToScene(event->pos()); auto currentPos = this->mapToScene(event->pos()).toPoint();
auto instance = std::make_shared<domain::ComponentInstance>(component.getInstanceName(), attributes, std::make_pair(currentPos.x(), currentPos.y()), component); auto instance = Application::instance()->addComponent(component, attributes, currentPos.x(), currentPos.y());
schema->componentInstances.push_back(instance);
auto group = new display::ComponentGroup(instance); auto group = new display::ComponentGroup(instance);
scene.addItem(group); scene.addItem(group);
@ -108,10 +117,9 @@ void Schema::updateConnections() {
if (event->mimeData()->hasFormat("comdel/bus")) { if (event->mimeData()->hasFormat("comdel/bus")) {
auto bus = library->getBus(event->mimeData()->data("comdel/bus").toStdString()); auto bus = library->getBus(event->mimeData()->data("comdel/bus").toStdString());
auto currentPos = this->mapToScene(event->pos()); auto currentPos = this->mapToScene(event->pos()).toPoint();
auto instance = std::make_shared<domain::BusInstance>(bus.getName(), std::make_pair(currentPos.x(), currentPos.y()), bus); auto instance = Application::instance()->addBus(bus, currentPos.x(), currentPos.y());
schema->busInstances.push_back(instance);
auto group = new display::BusGroup(instance); auto group = new display::BusGroup(instance);
scene.addItem(group); scene.addItem(group);
@ -129,18 +137,26 @@ void Schema::updateConnections() {
auto instance = context.pin->getComponentInstance(); auto instance = context.pin->getComponentInstance();
auto &pin = context.pin->getPin(); auto &pin = context.pin->getPin();
auto busInstances = getAvailableConnectionBusses(instance, pin); auto availableConnections = schema->availableConnections(instance->name, pin.getName(), true);
for(auto &bus: busInstances) { for(auto &connection: availableConnections) {
if(connection.type != domain::ConnectionEntry::BUS) {
continue;
}
auto bus = connection.busInstance.value();
if(buses[bus->name] == nullptr) {
continue;
}
auto rect = buses[bus->name]->boundingRect(); auto rect = buses[bus->name]->boundingRect();
rect = QRectF(buses[bus->name]->x(), buses[bus->name]->y(), rect.width(), rect.height()); rect = QRectF(buses[bus->name]->x(), buses[bus->name]->y(), rect.width(), rect.height());
if (rect.contains(endPoint)) { if (rect.contains(endPoint)) {
auto con = library->getConnection({instance->component.getName(), pin.getName()}, bus->bus.getName()); auto con = library->getConnection({instance->component.getName(), pin.getName()}, bus->bus.getName());
if (con.has_value()) { if (con.has_value()) {
std::vector<domain::InstanceAttribute> attributes; auto attributes = populateAttributes(con->getAttributes());
for(auto attr: con->getAttributes()) { if(attributes.size() != con->getAttributes().size()) {
attributes.emplace_back(attr.getName(), attr.getDefault(), attr); clearSelectable();
return;
} }
auto conInstance = std::make_shared<domain::BusConnectionInstance>(instance, attributes, bus, *con); auto conInstance = std::make_shared<domain::BusConnectionInstance>(instance, attributes, bus, *con);
@ -157,31 +173,54 @@ void Schema::updateConnections() {
} }
} }
auto pinInstances = getAvailableConnectionPins(instance, pin); for (auto &connection: availableConnections) {
if(connection.type != domain::ConnectionEntry::COMPONENT) {
continue;
}
auto pinInstance = domain::ConnectionComponent{connection.componentInstance.value()->name, connection.pin.value().getName()};
auto pin = pins[pinInstance]->getPin().getDisplayPin();
auto position = pins[pinInstance]->getComponentInstance()->position;
for(auto &pinInstance: pinInstances) { auto rect = QRectF(position.first + pin.x, position.second + pin.y, pin.w, pin.h);
auto rect = pins[pinInstance]->boundingRect();
rect.setX(pins[pinInstance]->scenePos().x());
rect.setY(pins[pinInstance]->scenePos().y());
if (rect.contains(endPoint)) { if (rect.contains(endPoint)) {
auto name = components[pinInstance.component]->getComponentInstance()->component.getName(); auto name = components[pinInstance.component]->getComponentInstance()->component.getName();
auto con = library->getConnection({instance->component.getName(), pin.getName()}, {name, pinInstance.pin}); auto con = library->getConnection({instance->component.getName(), context.pin->getPin().getName()},
{name, pinInstance.pin});
if (con.has_value()) { if (con.has_value()) {
auto bus = library->getBus(con->getBus()); auto busInstance = Application::instance()->addBus(library->getBus(con->getBus()), 0, 0);
auto busInstance = std::make_shared<domain::BusInstance>(bus.getName(), bus);
schema->busInstances.push_back(busInstance);
std::vector<domain::InstanceAttribute> attributes; std::vector<domain::InstanceAttribute> attributes;
for(auto attr: con->getAttributes()) { if(library->getBus(con->getBus()).getType() == domain::Bus::SINGLE_AUTOMATIC) {
attributes.emplace_back(attr.getName(), attr.getDefault(), attr); attributes = populateSingleAutomaticConnection(*con);
} else {
attributes = populateAttributes(con->getAttributes());
}
if(attributes.size() != con->getAttributes().size()) {
clearSelectable();
return;
}
std::shared_ptr<domain::DirectConnectionInstance> conInstance = nullptr;
if(con->getComponent() == domain::ConnectionComponent{instance->component.getName(), context.pin->getPin().getName()}) {
conInstance = std::make_shared<domain::DirectConnectionInstance>(instance,
components[pinInstance.component]->getComponentInstance().get(),
attributes, busInstance.get(),
*con);
} else {
conInstance = std::make_shared<domain::DirectConnectionInstance>(components[pinInstance.component]->getComponentInstance().get(),
instance,
attributes, busInstance.get(),
*con);
} }
auto conInstance = std::make_shared<domain::DirectConnectionInstance>(instance, components[pinInstance.component]->getComponentInstance().get(), attributes, busInstance.get(), *con);
schema->connections.push_back(conInstance); schema->connections.push_back(conInstance);
if (conInstance != nullptr) { if (conInstance != nullptr) {
auto c = new display::DirectConnection(conInstance.get(), components[conInstance->instance->name], components[conInstance->secondInstance->name]); auto c = new display::DirectConnection(conInstance.get(),
components[conInstance->instance->name],
components[conInstance->secondInstance->name]);
directConnections.push_back(c); directConnections.push_back(c);
scene.addItem(c); scene.addItem(c);
} }
@ -190,25 +229,25 @@ void Schema::updateConnections() {
} }
} }
updateConnections(); clearSelectable();
for(auto& item: this->context.selectable) {
this->scene.removeItem(item);
delete item;
}
this->context.selectable.clear();
} }
void Schema::showConnectable(Pin *domainPin) { void Schema::showConnectable(Pin *domainPin) {
auto &pin = domainPin->getPin(); auto &pin = domainPin->getPin();
auto busInstances = getAvailableConnectionBusses(domainPin->getComponentInstance(), domainPin->getPin()); auto availableConnections = schema->availableConnections(domainPin->getComponentInstance()->name, pin.getName(), true);
for(auto bus: busInstances) { for(auto &connection: availableConnections) {
if(connection.type != domain::ConnectionEntry::BUS) {
continue;
}
auto bus = connection.busInstance.value();
auto &group = buses[bus->name]; auto &group = buses[bus->name];
if(group == nullptr) {
continue;
}
auto rect = new QGraphicsRectItem(group->boundingRect()); auto rect = new QGraphicsRectItem(group->boundingRect());
rect->setPen(selectedPen); rect->setBrush(selectedBrush);
rect->setPos(group->scenePos()); rect->setPos(group->scenePos());
auto _rect = rect->rect(); auto _rect = rect->rect();
@ -220,11 +259,14 @@ void Schema::updateConnections() {
scene.addItem(rect); scene.addItem(rect);
} }
std::vector<domain::ConnectionComponent> pinInstances = getAvailableConnectionPins(domainPin->getComponentInstance(), domainPin->getPin()); for (auto &connection: availableConnections) {
if(connection.type != domain::ConnectionEntry::COMPONENT) {
for(auto& pinInstance: pinInstances) { continue;
}
auto pinInstance = domain::ConnectionComponent{connection.componentInstance.value()->name, connection.pin.value().getName()};
auto &instance = pins[pinInstance]; auto &instance = pins[pinInstance];
auto rect = new QGraphicsRectItem(instance->boundingRect()); auto rect = new QGraphicsRectItem(instance->boundingRect());
rect->setBrush(selectedBrush);
rect->setPen(selectedPen); rect->setPen(selectedPen);
rect->setPos(instance->scenePos()); rect->setPos(instance->scenePos());
@ -239,26 +281,57 @@ void Schema::updateConnections() {
} }
std::vector<domain::BusInstance*> Schema::getAvailableConnectionBusses(domain::ComponentInstance *instance, domain::Pin &pin) { std::vector<domain::InstanceAttribute> Schema::populateAttributes(std::vector<domain::Attribute>& attributes) {
std::vector<domain::BusInstance*> instances; std::vector<domain::InstanceAttribute> instanceAttributes;
for(const auto& bus: schema->busInstances) {
if(library->hasConnection(domain::ConnectionComponent{instance->component.getName(), pin.getName()}, bus->bus.getName())) { for (auto attr: attributes) {
instances.push_back(bus.get()); domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr);
if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) {
if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) {
auto dialog = new MemoryDialog("msg_dialog_memory_set", "msg_dialog_actions_set", &attribute, schema->componentInstances);
if(dialog->exec() == QDialog::Rejected) {
// if any dialog isn't set, whole creation is rejected
return {};
}
} else {
std::map<std::string, std::string> params = {{"attribute", attribute.attribute.getDisplayName()}};
auto dialog = new AttributeDialog(MESSAGE_PARAM("msg_dialog_attribute_set", params), "msg_dialog_actions_set", &attribute);
if(dialog->exec() == QDialog::Rejected) {
// if any dialog isn't set, whole creation is rejected
return {};
} }
} }
return instances; }
instanceAttributes.push_back(attribute);
}
return instanceAttributes;
} }
std::vector<domain::ConnectionComponent> Schema::getAvailableConnectionPins(domain::ComponentInstance *instance, domain::Pin &pin) { std::vector<domain::InstanceAttribute> Schema::populateSingleAutomaticConnection(domain::Connection connection) {
std::vector<domain::ConnectionComponent> instances; std::vector<domain::InstanceAttribute> instanceAttributes;
domain::ConnectionComponent source{instance->component.getName(), pin.getName()};
for(const auto& entry: pins) { for (auto attr: connection.getAttributes()) {
std::string name = components[entry.first.component]->getComponentInstance()->component.getName(); instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr);
if(library->hasConnection(source, domain::ConnectionComponent{name, entry.first.pin})) {
instances.push_back(entry.first);
} }
auto dialog = new display::SingleAutomaticDialog("msg_dialog_sa_pin_set", "msg_dialog_actions_set", instanceAttributes);
if(dialog->exec() == QDialog::Rejected) {
// if dialog is rejected, whole creation is rejected
return {};
} }
return instances;
return instanceAttributes;
}
void Schema::clearSelectable() {
updateConnections();
for (auto &item: this->context.selectable) {
this->scene.removeItem(item);
delete item;
}
this->context.selectable.clear();
} }
} // namespace display } // namespace display

View File

@ -4,6 +4,7 @@
#include <QGraphicsView> #include <QGraphicsView>
#include <QWidget> #include <QWidget>
#include <QColor>
#include <QGraphicsLineItem> #include <QGraphicsLineItem>
#include <comdel/domain/schema.h> #include <comdel/domain/schema.h>
@ -14,14 +15,14 @@ namespace display {
class BusConnection; class BusConnection;
class Schema: public QGraphicsView class Schema : public QGraphicsView {
{
Q_OBJECT Q_OBJECT
public: public:
QBrush selectedBrush; QBrush selectedBrush = QBrush(QColor::fromRgb(50, 50, 150, 100), Qt::BrushStyle::SolidPattern);
QPen selectedPen; QPen selectedPen = QPen(QColor::fromRgb(50, 50, 150), 1, Qt::PenStyle::SolidLine);
QPen activeLinePen = QPen(QColor::fromRgb(250, 100, 100));
enum State { enum State {
DEFAULT, DEFAULT,
@ -47,29 +48,33 @@ public:
std::vector<BusConnection *> busConnections; std::vector<BusConnection *> busConnections;
std::vector<DirectConnection *> directConnections; std::vector<DirectConnection *> directConnections;
void setSchema(domain::Schema* schema, domain::Library* library);
void updateConnections(); void updateConnections();
void removeConnectable(QPointF f); void removeConnectable(QPointF f);
void showConnectable(Pin *pin); void showConnectable(Pin *pin);
void refreshContent();
protected: protected:
void dragEnterEvent(QDragEnterEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override;
void dropEvent(QDropEvent *event) override; void dropEvent(QDropEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override; void dragMoveEvent(QDragMoveEvent *event) override;
private: private:
QGraphicsScene scene; QGraphicsScene scene;
domain::Schema* schema; domain::Schema *schema{};
domain::Library* library; std::optional<domain::Library> library;
std::vector<domain::BusInstance*> getAvailableConnectionBusses(domain::ComponentInstance *instance, domain::Pin &pin); std::vector<domain::InstanceAttribute> populateAttributes(std::vector<domain::Attribute>& attributes);
std::vector<domain::ConnectionComponent> getAvailableConnectionPins(domain::ComponentInstance *instance, domain::Pin &pin); std::vector<domain::InstanceAttribute> populateSingleAutomaticConnection(domain::Connection connection);
void clearSelectable();
}; };
} // namespace display } // namespace display

View File

@ -0,0 +1,29 @@
#include <algorithm>
#include "address_space.h"
namespace domain {
AddressSpace::AddressSpace(std::string name, long long start, long long end) :
name(name), start(start), end(end) {}
std::string AddressSpace::getName() {
return name;
}
long long AddressSpace::getStart() const {
return start;
}
long long AddressSpace::getEnd() const {
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

View File

@ -0,0 +1,29 @@
#ifndef DOMAIN_ADDRESS_SPACE_H
#define DOMAIN_ADDRESS_SPACE_H
#include <string>
namespace domain {
class AddressSpace {
std::string name;
long long start;
long long end;
public:
AddressSpace(std::string name, long long start, long long end);
std::string getName();
long long getStart() const;
long long getEnd() const;
bool contains(long long int address);
bool contains(long long int start, long long int end);
};
} // namespace domain
#endif // DOMAIN_ADDRESS_SPACE_H

View File

@ -1,28 +0,0 @@
#include <algorithm>
#include "addressspace.h"
namespace domain {
AddressSpace::AddressSpace(std::string name, long long start, long long end):
name(name), start(start), end(end)
{}
std::string AddressSpace::getName() {
return name;
}
long long AddressSpace::getStart() const {
return start;
}
long long AddressSpace::getEnd() const {
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

View File

@ -1,27 +0,0 @@
#ifndef DOMAIN_ADDRESS_SPACE_H
#define DOMAIN_ADDRESS_SPACE_H
#include <string>
namespace domain {
class AddressSpace
{
std::string name;
long long start;
long long end;
public:
AddressSpace(std::string name, long long start, long long end);
std::string getName();
long long getStart() const;
long long getEnd() const;
bool contains(long long int address);
bool contains(long long int start, long long int end);
};
} // namespace domain
#endif // DOMAIN_ADDRESS_SPACE_H

View File

@ -3,30 +3,34 @@
namespace domain { namespace domain {
Enumeration::Enumeration(std::string name, Value value) Enumeration::Enumeration(std::string name, Value value)
: name(name), value(value) : name(name), value(value) {}
{}
std::string &Enumeration::getName() { std::string &Enumeration::getName() {
return name; return name;
} }
Value Enumeration::getValue() { Value Enumeration::getValue() {
return value; return value;
} }
Popup::Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules, std::vector<Enumeration> enumeration) Popup::Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules,
: title(title), text(text), type(type), rules(rules), enumerated(enumeration.size() > 0), enumeration(enumeration) std::vector<Enumeration> enumeration)
{} : title(title), text(text), type(type), rules(rules), enumerated(enumeration.size() > 0),
enumeration(enumeration) {}
std::string Popup::getTitle() { std::string Popup::getTitle() {
return title; return title;
} }
std::string Popup::getText() { std::string Popup::getText() {
return text; return text;
} }
Popup::PopupType Popup::getType() { Popup::PopupType Popup::getType() {
return type; return type;
} }
std::vector<Rule> Popup::getRules() { std::vector<Rule> Popup::getRules() {
return rules; return rules;
} }
@ -34,23 +38,36 @@ std::vector<Rule> Popup::getRules() {
bool Popup::isEnumerated() { bool Popup::isEnumerated() {
return enumerated; return enumerated;
} }
std::vector<Enumeration> &Popup::getEnumeration() { std::vector<Enumeration> &Popup::getEnumeration() {
return enumeration; return enumeration;
} }
Attribute::Attribute(std::string name, Value defaultValue, std::optional<Popup> popup) Attribute::Attribute(std::string name, std::optional<std::string> displayName, Value defaultValue, std::optional<Popup> popup)
: name(name), defaultValue(defaultValue), popup(popup) : name(name), displayName(displayName), defaultValue(defaultValue), popup(popup) {}
{}
std::string Attribute::getDisplayName() {
if(displayName.has_value()) {
return *displayName;
}
return name;
}
std::string Attribute::getName() { std::string Attribute::getName() {
return name; return name;
} }
Value Attribute::getDefault() { Value Attribute::getDefault() {
return defaultValue; return defaultValue;
} }
std::optional<Popup> Attribute::getPopup() { std::optional<Popup> Attribute::getPopup() {
return popup; return popup;
} }
void Attribute::setPupup(std::optional<Popup> popup) {
this->popup = popup;
}
} // namespace domain } // namespace domain

View File

@ -16,6 +16,7 @@ public:
Enumeration(std::string name, Value value); Enumeration(std::string name, Value value);
std::string &getName(); std::string &getName();
Value getValue(); Value getValue();
}; };
@ -36,34 +37,44 @@ private:
std::vector<Rule> rules; std::vector<Rule> rules;
public: public:
Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules, std::vector<Enumeration> enumeration); Popup(std::string title, std::string text, PopupType type, std::vector<Rule> rules,
std::vector<Enumeration> enumeration);
std::string getTitle(); std::string getTitle();
std::string getText(); std::string getText();
PopupType getType(); PopupType getType();
std::vector<Rule> getRules(); std::vector<Rule> getRules();
bool isEnumerated(); bool isEnumerated();
std::vector<Enumeration> &getEnumeration(); std::vector<Enumeration> &getEnumeration();
void setEnumeration(std::vector<Enumeration> enums) { void setEnumeration(std::vector<Enumeration> enums) {
enumerated = true; enumerated = true;
enumeration = std::move(enums); enumeration = enums;
} }
}; };
class Attribute class Attribute {
{
std::string name; std::string name;
std::optional<std::string> displayName;
Value defaultValue; Value defaultValue;
std::optional<Popup> popup; std::optional<Popup> popup;
public: public:
Attribute(std::string name, Value defaultValue, std::optional<Popup> popup = std::nullopt); Attribute(std::string name, std::optional<std::string> displayName, Value defaultValue, std::optional<Popup> popup = std::nullopt);
std::string getName(); std::string getName();
std::string getDisplayName();
Value getDefault(); Value getDefault();
std::optional<Popup> getPopup(); std::optional<Popup> getPopup();
void setPupup(std::optional<Popup> popup);
}; };
} // namespace domain } // namespace domain

View File

@ -3,15 +3,22 @@
namespace domain { namespace domain {
Wire::Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith) Wire::Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith)
: name(name), type(type), width(width), hidden(hidden), hasTerminate(hasTerminate), terminateWith(terminateWith) : name(name), type(type), width(width), hidden(hidden), hasTerminate(hasTerminate),
{} terminateWith(terminateWith) {}
std::string Wire::getName() { std::string Wire::getName() {
return name; return name;
} }
std::string Bus::getInstanceName() {
return instanceName;
}
int Wire::getWidth() { int Wire::getWidth() {
return width; return width;
} }
bool Wire::isHidden() { bool Wire::isHidden() {
return hidden; return hidden;
} }
@ -19,32 +26,46 @@ bool Wire::isHidden() {
bool Wire::hasTerminateWith() { bool Wire::hasTerminateWith() {
return hasTerminate; return hasTerminate;
} }
Value Wire::getTerminateWith() { Value Wire::getTerminateWith() {
return terminateWith; return terminateWith;
} }
Wire::WireType Wire::getType() { Wire::WireType Wire::getType() {
return type; return type;
} }
Bus::Bus(std::string name, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, std::optional<ui::Bus> displayBus) Bus::Bus(std::string name, std::optional<std::string> displayName, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires,
: name(name), tooltip(tooltip), type(type), count(count), wires(wires), displayBus(displayBus) std::optional<ui::Bus> displayBus)
{} : name(name), displayName(displayName), instanceName(instanceName), tooltip(tooltip), type(type), count(count), wires(wires), displayBus(displayBus) {}
std::string Bus::getName() { std::string Bus::getName() {
return name; return name;
} }
std::string Bus::getDisplayName() {
if(displayName.has_value()) {
return *displayName;
}
return name;
}
std::string Bus::getTooltip() { std::string Bus::getTooltip() {
return tooltip; return tooltip;
} }
Bus::BusType Bus::getType() { Bus::BusType Bus::getType() {
return type; return type;
} }
std::pair<int, int> Bus::getCount() { std::pair<int, int> Bus::getCount() {
return count; return count;
} }
std::vector<Wire> Bus::getWires() { std::vector<Wire> Bus::getWires() {
return wires; return wires;
} }
std::optional<ui::Bus> Bus::getDisplayBus() { std::optional<ui::Bus> Bus::getDisplayBus() {
return displayBus; return displayBus;
} }

View File

@ -11,8 +11,7 @@
namespace domain { namespace domain {
class Wire class Wire {
{
public: public:
enum WireType { enum WireType {
WIRE_DEFAULT, WIRE_DEFAULT,
@ -26,23 +25,27 @@ private:
std::string name; std::string name;
WireType type; WireType type;
int width; int width;
bool hidden; bool hidden = false;
bool hasTerminate; bool hasTerminate = false;
Value terminateWith; Value terminateWith;
public: public:
Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith); Wire(std::string name, WireType type, int width, bool hidden, bool hasTerminate, Value terminateWith);
std::string getName(); std::string getName();
int getWidth(); int getWidth();
bool isHidden(); bool isHidden();
bool hasTerminateWith(); bool hasTerminateWith();
Value getTerminateWith(); Value getTerminateWith();
WireType getType(); WireType getType();
}; };
class Bus class Bus {
{
public: public:
enum BusType { enum BusType {
AUTOMATIC, AUTOMATIC,
@ -51,6 +54,8 @@ public:
}; };
private: private:
std::string name; std::string name;
std::optional<std::string> displayName;
std::string instanceName;
std::string tooltip; std::string tooltip;
BusType type; BusType type;
@ -59,13 +64,23 @@ private:
std::vector<Wire> wires; std::vector<Wire> wires;
public: public:
Bus(std::string name, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires, std::optional<ui::Bus> display = std::nullopt); Bus(std::string name, std::optional<std::string> displayName, std::string instanceName, std::string tooltip, BusType type, std::pair<int, int> count, std::vector<Wire> wires,
std::optional<ui::Bus> display = std::nullopt);
std::string getName(); std::string getName();
std::string getDisplayName();
std::string getInstanceName();
std::string getTooltip(); std::string getTooltip();
BusType getType(); BusType getType();
std::pair<int, int> getCount(); std::pair<int, int> getCount();
std::vector<Wire> getWires(); std::vector<Wire> getWires();
std::optional<ui::Bus> getDisplayBus(); std::optional<ui::Bus> getDisplayBus();
}; };

View File

@ -3,18 +3,21 @@
// //
#include <set> #include <set>
#include <QLayout>
#include "comdel_generator.h" #include "comdel_generator.h"
namespace domain { namespace domain {
void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream &buffer) { void generate_schema(std::string &librarySource, Schema *schema, std::ostream &buffer) {
buffer << "@source " << librarySource << std::endl << std::endl; buffer << "@source \"" << librarySource << "\"" << std::endl << std::endl;
buffer << "@schema {" << std::endl; buffer << "@schema {" << std::endl;
for (auto &componentInstance: schema->componentInstances) { for (auto &componentInstance: schema->componentInstances) {
buffer << "\t" << "@instance " << componentInstance->name << " " << componentInstance->component.getName() << " {" << std::endl; buffer << "\t" << "@instance " << componentInstance->name << " " << componentInstance->component.getName()
buffer << "\t\t" << "@position (" << componentInstance->position.first << ", " << componentInstance->position.second << ")" << std::endl; << " {" << std::endl;
buffer << "\t\t" << "@position (" << componentInstance->position.first << ", "
<< componentInstance->position.second << ")" << std::endl;
for (auto &attribute: componentInstance->attributes) { for (auto &attribute: componentInstance->attributes) {
buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl;
@ -24,8 +27,10 @@ void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream
} }
for (auto &busInstance: schema->busInstances) { for (auto &busInstance: schema->busInstances) {
buffer << "\t" << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {" << std::endl; buffer << "\t" << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {"
buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second << ")" << std::endl; << std::endl;
buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second
<< ")" << std::endl;
buffer << "\t\t" << "@size " << busInstance->size << std::endl; buffer << "\t\t" << "@size " << busInstance->size << std::endl;
buffer << "\t}" << std::endl << std::endl; buffer << "\t}" << std::endl << std::endl;
} }
@ -33,23 +38,27 @@ void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream
for (auto &conn: schema->connections) { for (auto &conn: schema->connections) {
auto busConn = dynamic_cast<domain::BusConnectionInstance *>(conn.get()); auto busConn = dynamic_cast<domain::BusConnectionInstance *>(conn.get());
if (busConn) { if (busConn) {
buffer << "\t" << "@connection (" << busConn->instance->name << "." << busConn->connection.getComponent().pin << ", " << busConn->bus->name << ") {" << std::endl; buffer << "\t" << "@connection (" << busConn->instance->name << "."
<< busConn->connection.getComponent().pin << ", " << busConn->bus->name << ") {" << std::endl;
for (auto attribute: busConn->attributes) { for (auto attribute: busConn->attributes) {
buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify()
<< std::endl;
} }
buffer << "\t" << "}" << std::endl; buffer << "\t" << "}" << std::endl;
} }
auto dirConn = dynamic_cast<domain::DirectConnectionInstance *>(conn.get()); auto dirConn = dynamic_cast<domain::DirectConnectionInstance *>(conn.get());
if (dirConn) { if (dirConn) {
buffer << "\t" << "@connection (" << dirConn->instance->name << "." << dirConn->connection.getComponent().pin << ", " buffer << "\t" << "@connection (" << dirConn->instance->name << "."
<< dirConn->connection.getComponent().pin << ", "
<< dirConn->bus->name << ", " << dirConn->bus->name << ", "
<< dirConn->secondInstance->name << "." << dirConn->connection.getSecondComponent()->pin << dirConn->secondInstance->name << "." << dirConn->connection.getSecondComponent()->pin
<< ") {" << std::endl; << ") {" << std::endl;
for (auto attribute: dirConn->attributes) { for (auto attribute: dirConn->attributes) {
buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl; buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify()
<< std::endl;
} }
buffer << "\t" << "}" << std::endl; buffer << "\t" << "}" << std::endl;
@ -67,7 +76,7 @@ void generateSubComponents(Schema *schema, map <string, string> &wires, ostream
void generateDisplay(Schema *schema, ostream &buffer); void generateDisplay(Schema *schema, ostream &buffer);
void generateComdelFile(Schema *schema, Library &library, std::ostream &buffer) { void generate_comdel(Schema *schema, Library &library, std::ostream &buffer) {
buffer << library.getHeader() << std::endl; buffer << library.getHeader() << std::endl;
std::set<std::string> imports = createImports(schema); std::set<std::string> imports = createImports(schema);
@ -94,13 +103,15 @@ void generateComdelFile(Schema *schema, Library &library, std::ostream &buffer)
} }
void generateBus(BusInstance *bus, ostream &buffer); void generateBus(BusInstance *bus, ostream &buffer);
void generateConnection(ConnectionInstance *connection, ostream &buffer); void generateConnection(ConnectionInstance *connection, ostream &buffer);
void generateDisplay(Schema *schema, ostream &buffer) { void generateDisplay(Schema *schema, ostream &buffer) {
buffer << "\n\tdisplay {\n"; buffer << "\n\tdisplay {\n";
for (auto &component: schema->componentInstances) { for (auto &component: schema->componentInstances) {
buffer << "\t\tcomponent { x: " << component->position.first << "; y: " << component->position.second << "; ref: \"" << component->name << "\"; }" << std::endl; buffer << "\t\tcomponent { x: " << component->position.first << "; y: " << component->position.second
<< "; ref: \"" << component->name << "\"; }" << std::endl;
} }
for (auto &bus: schema->busInstances) { for (auto &bus: schema->busInstances) {
@ -117,8 +128,18 @@ void generateDisplay(Schema *schema, ostream &buffer) {
} }
void generateConnection(ConnectionInstance *connection, ostream &buffer) { void generateConnection(ConnectionInstance *connection, ostream &buffer) {
buffer << "\t\tline {x1:" << connection->start.first << "; y1:" << connection->start.second << "; " <<
"x2:" << connection->end.first << "; y2:" << connection->end.second << ";}" << "\n"; auto x1 = connection->start.first;
auto y1 = connection->start.second;
auto x2 = connection->end.first;
auto y2 = connection->end.second;
buffer << "\t\tpath {\n";
buffer << "\t\t\tx:0; y:0;\n";
buffer << "\t\t\tpoints: (";
buffer << "(" << x1 << ", " << y1 << "),";
buffer << "(" << (x2 - x1) << "," << (y2 - y1) << "));\n";
buffer << "\t\t}" << std::endl;
} }
void generateBus(BusInstance *bus, ostream &buffer) { void generateBus(BusInstance *bus, ostream &buffer) {
@ -138,13 +159,10 @@ std::map<string, string> generateWires(Schema *schema, ostream &buffer) {
for (auto &bus: schema->busInstances) { for (auto &bus: schema->busInstances) {
buffer << "\t//" << bus->name << std::endl; buffer << "\t//" << bus->name << std::endl;
for (auto &wire: bus->bus.getWires()) { for (auto &wire: bus->bus.getWires()) {
std::string name = wire.getName(); auto name = wire.getName();
if(usedNames.count(wire.getName()) > 0) { if (usedNames.count(name) > 0) {
name = bus->name + "__" + wire.getName(); name = bus->name + "__" + wire.getName();
} }
if(wire.isHidden()) {
name = "--" + name;
}
usedNames.insert(name); usedNames.insert(name);
usedMappings.insert(std::make_pair(bus->name + "." + wire.getName(), name)); usedMappings.insert(std::make_pair(bus->name + "." + wire.getName(), name));
@ -174,7 +192,11 @@ void generateWire(std::string &name, Wire& wire, ostream &buffer) {
if (wire.getWidth() != 1) { if (wire.getWidth() != 1) {
buffer << "<" << wire.getWidth() << ">"; buffer << "<" << wire.getWidth() << ">";
} }
buffer << " " << name << ";" << std::endl; buffer << " " << (wire.isHidden() ? "--" : "") << name;
if(wire.hasTerminateWith()) {
buffer << " = " << wire.getTerminateWith().asInt();
}
buffer << ";" << std::endl;
} }
std::set<std::string> createImports(Schema *schema) { std::set<std::string> createImports(Schema *schema) {
@ -185,12 +207,17 @@ std::set<std::string> createImports(Schema *schema) {
return importSet; return importSet;
} }
void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, stringstream &buffer); void
generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames,
stringstream &buffer);
void generateSingleAutomaticPin(DirectConnectionInstance *instance, string name, string pin, void generateSingleAutomaticPin(DirectConnectionInstance *instance, string name, string pin,
map<string, string> &wireNames, map<string, string> &wireNames,
stringstream &buffer); stringstream &buffer);
void generateSingleAutomaticPin(std::vector<ConnectionInstance*> connections, ComponentInstance *instance, string pin,
map<string, string> &wireNames, stringstream &buffer);
void generateComponent(Schema *schema, map<string, string> &wires, ostream &buffer, void generateComponent(Schema *schema, map<string, string> &wires, ostream &buffer,
shared_ptr<ComponentInstance> &component); shared_ptr<ComponentInstance> &component);
@ -238,7 +265,9 @@ void generateComponent(Schema *schema, map <string, string> &wires, ostream &buf
for (auto &pin: component->component.getPins()) { for (auto &pin: component->component.getPins()) {
if (schema->hasConnection(component->name, pin.getName())) { if (schema->hasConnection(component->name, pin.getName())) {
auto conn = schema->getConnection(component->name, pin.getName()); auto connections = schema->getConnections(component->name, pin.getName());
if(connections.size() == 1) {
auto conn = connections[0];
auto busConn = dynamic_cast<BusConnectionInstance *>(conn); auto busConn = dynamic_cast<BusConnectionInstance *>(conn);
if (busConn != nullptr) { if (busConn != nullptr) {
for (auto wire: busConn->connection.getWires()) { for (auto wire: busConn->connection.getWires()) {
@ -270,13 +299,20 @@ void generateComponent(Schema *schema, map <string, string> &wires, ostream &buf
generateSingleAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput); generateSingleAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput);
} }
} }
} else {
generateSingleAutomaticPin(connections, component.get(), pin.getName(), wires, tempOutput);
}
} else { } else {
// if no connection exists than defaults must exist // if no connection exists than defaults must exist
for (auto &wire: *pin.getWires()) { for (auto &wire: *pin.getWires()) {
if(wire.isType(Value::NIL)) {
tempOutput << "*, ";
} else {
tempOutput << wire.stringify() << ", "; tempOutput << wire.stringify() << ", ";
} }
} }
} }
}
auto wireList = tempOutput.str(); auto wireList = tempOutput.str();
wireList.pop_back(); wireList.pop_back();
@ -292,34 +328,64 @@ void generateComponent(Schema *schema, map <string, string> &wires, ostream &buf
} }
void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map <string, string> &wireNames, stringstream &buffer) { void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin,
map<string, string> &wireNames, stringstream &buffer) {
std::vector<Value> wires; std::vector<Value> wires;
std::string selected; std::string selected;
std::vector<Value> defaults; std::vector<Value> defaults;
if (connection->instance->name == name && connection->connection.getComponent().pin == pin) { if (connection->instance->name == name && connection->connection.getComponent().pin == pin) {
wires = connection->connection.getWires(); wires = connection->connection.getWires();
selected = connection->attributes[0].value.asReference(); selected = connection->attributes[0].value.asString();
defaults = *connection->instance->component.getPin(pin).getWires(); defaults = *connection->instance->component.getPin(pin).getWires();
} else { } else {
wires = *connection->connection.getSecondWires(); wires = *connection->connection.getSecondWires();
selected = connection->attributes[1].value.asReference(); selected = connection->attributes[1].value.asString();
defaults = *connection->secondInstance->component.getPin(pin).getWires(); defaults = *connection->secondInstance->component.getPin(pin).getWires();
} }
for (int i = 0; i < wires.size(); i++) { for (int i = 0; i < wires.size(); i++) {
if (wires[i].isType(Value::STRING)) { if (wires[i].isType(Value::STRING)) {
if (wires[i].asString() == selected) { if (wires[i].asString() == selected) {
buffer << wireNames[connection->bus->name + "." + connection->bus->bus.getWires()[0].getName()] << ", "; auto wireName = connection->bus->name + "." + connection->bus->bus.getWires()[0].getName();
buffer << wireNames[wireName] << ", ";
} else if(defaults[i].isType(Value::NIL)) {
buffer << "*, ";
} else { } else {
buffer << defaults[i].stringify(); buffer << defaults[i].stringify() << ", ";
} }
} else if(defaults[i].isType(Value::NIL)) {
buffer << "*, ";
} else { } else {
buffer << wires[i].stringify() << ", "; buffer << wires[i].stringify() << ", ";
} }
} }
} }
void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, stringstream &buffer) { void generateSingleAutomaticPin(std::vector<ConnectionInstance*> connections, ComponentInstance *instance, string pin,
map<string, string> &wireNames, stringstream &buffer) {
std::map<int, BusInstance*> selectedValues;
for(auto conn: connections) {
auto dirConn = dynamic_cast<DirectConnectionInstance*>(conn);
auto index = dirConn->getSelected(ConnectionComponent{instance->name, pin});
selectedValues.insert(std::make_pair(index, dirConn->bus));
}
std::vector<Value> defaultWires = instance->component.getPin(pin).getWires().value();
for (int i=0; i<defaultWires.size(); i++) {
if(selectedValues.count(i) > 0) {
auto wireName = selectedValues[i]->name + "." + selectedValues[i]->bus.getWires()[0].getName();
buffer << wireNames[wireName] << ", ";
} else if(defaultWires[i].isType(Value::NIL)) {
buffer << "*, ";
} else {
buffer << defaultWires[i].stringify() << ", ";
}
}
}
void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames,
stringstream &buffer) {
std::vector<Value> wires; std::vector<Value> wires;
if (connection->instance->name == name && connection->connection.getComponent().pin == pin) { if (connection->instance->name == name && connection->connection.getComponent().pin == pin) {
wires = connection->connection.getWires(); wires = connection->connection.getWires();

View File

@ -7,9 +7,9 @@
namespace domain { namespace domain {
void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream &buffer); void generate_schema(std::string &librarySource, Schema *schema, std::ostream &buffer);
void generateComdelFile(Schema *schema, Library &library, std::ostream &buffer); void generate_comdel(Schema *schema, Library &library, std::ostream &buffer);
} // domain } // domain

View File

@ -0,0 +1,240 @@
#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;
}
}

View File

@ -0,0 +1,57 @@
#ifndef COMDEL_VALIDATOR_H
#define COMDEL_VALIDATOR_H
#include "instance.h"
#include "schema.h"
#include "library.h"
namespace domain {
struct ValidationError {
ComponentInstance *instance;
InstanceAttribute *attribute;
Action::ActionType type;
std::string message;
ValidationError(Action::ActionType type, std::string message): instance(nullptr), attribute(nullptr), type(type), message(message) {}
ValidationError(ComponentInstance* instance, InstanceAttribute* attribute, Action::ActionType type, std::string message): instance(instance), attribute(attribute), type(type), message(message) {}
};
struct ValidationContext {
ComponentInstance *instance;
InstanceAttribute *attribute;
std::map<std::string, AddressSpace> addressSpaces;
std::map<std::string, Value> attributes;
std::map<std::string, std::string> map();
};
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);
std::vector<ValidationError> validateMemoryReferences(Schema &schema, Library &library, ValidationContext context);
std::vector<ValidationError> validateInstanceNames(Schema &schema, Library &library, ValidationContext context);
std::vector<ValidationError> validateInstanceCount(Schema &schema, Library &library, ValidationContext context);
std::vector<ValidationError> validatePinConnections(Schema &schema, Library &library, ValidationContext context);
ComdelValidator(std::vector<FunctionValidator *> validators);
private:
std::map<std::string, FunctionValidator *> validators;
bool connectionExists(Schema &schema, shared_ptr<ComponentInstance> &component, Pin &pin);
};
}
#endif //COMDEL_VALIDATOR_H

View File

@ -1,187 +0,0 @@
#include "comdelvalidator.h"
#include "library.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.getName());
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 = populateMessage("Not enough instances of component '{componentName}' required at least {min}, found {count}", context);
errors.push_back(ValidationError{nullptr, nullptr, Action::ERROR, message});
} else if(count > comp.getCount().second) {
auto message = populateMessage("To many instances of component '{componentName}' allow at most {max}, found {count}", context);
errors.push_back(ValidationError{nullptr, nullptr, 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.getName());
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 = populateMessage("Not enough instances of bus '{busName}' required at least {min}, found {count}", context);
errors.push_back(ValidationError{nullptr, nullptr, Action::ERROR, message});
} else if(count > bus.getCount().second) {
auto message = populateMessage("To many instances of bus '{busName}' allow at most {max}, found {count}", context);
errors.push_back(ValidationError{nullptr, nullptr, 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().getType() == PinConnection::REQUIRED) {
if(!connectionExists(schema, inst, pin)) {
context.instance = inst.get();
context.attributes["instanceName"] = Value::fromString(inst->name);
auto message = populateMessage(pin.getConnection().getMessage(), context);
errors.push_back(ValidationError{nullptr, 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) {
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;
}
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 && busConnection->connection.getComponent().pin == pin.getName()) {
return true;
}
if(directConnection->secondInstance->name == component->name && busConnection->connection.getSecondComponent()->pin == pin.getName()) {
return true;
}
}
}
return false;
}
}

View File

@ -1,54 +0,0 @@
#ifndef COMDEL_VALIDATOR_H
#define COMDEL_VALIDATOR_H
#include "instance.h"
#include "schema.h"
#include "library.h"
namespace domain {
struct ValidationError
{
ComponentInstance *instance;
InstanceAttribute *attribute;
Action::ActionType type;
std::string message;
};
struct ValidationContext {
ComponentInstance *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);
std::vector<ValidationError> validateInstanceCount(Schema &schema, Library& library, ValidationContext context);
std::vector<ValidationError> validatePinConnections(Schema &schema, Library& library, ValidationContext context);
ComdelValidator(std::vector<FunctionValidator*> validators) {
for(auto* validator: validators) {
validator->clear();
this->validators.insert(std::make_pair(validator->getName(), validator));
}
}
private:
std::map<std::string, FunctionValidator*> validators;
std::string populateMessage(string message, ValidationContext context);
string replacePlaceholder(string message, const string name, Value value);
bool connectionExists(Schema &schema, shared_ptr <ComponentInstance> &component, Pin &pin);
};
}
#endif //COMDEL_VALIDATOR_H

View File

@ -1,34 +1,49 @@
#include "component.h" #include "component.h"
#include <stdexcept>
namespace domain { namespace domain {
Component::Component(string name, string tooltip, string source, ComponentType type, Component::Component(string name, optional<string> displayName, string tooltip, string source, ComponentType type,
vector<Rule> rules, string instanceName, pair<int, int> count, Display display, vector<Rule> rules, string instanceName, pair<int, int> count, Display display,
vector<Pin> pins, vector<Attribute> attributes) vector<Pin> pins, vector<Attribute> attributes)
: name(name), tooltip(tooltip), source(source), type(type), rules(rules), instanceName(instanceName), count(count), display(display), pins(pins), attributes(attributes) : name(name), displayName(displayName), tooltip(tooltip), source(source), type(type), rules(rules), instanceName(instanceName),
{} count(count), display(display), pins(pins), attributes(attributes) {}
std::string Component::getName() { std::string Component::getName() {
return name; return name;
} }
std::string Component::getDisplayName() {
if(displayName.has_value()) {
return displayName.value();
}
return name;
}
std::string Component::getTooltip() { std::string Component::getTooltip() {
return tooltip; return tooltip;
} }
std::string Component::getSource() { std::string Component::getSource() {
return source; return source;
} }
Component::ComponentType Component::getType() { Component::ComponentType Component::getType() {
return type; return type;
} }
std::vector<Rule> Component::getRules() { std::vector<Rule> Component::getRules() {
return rules; return rules;
} }
std::string Component::getInstanceName() { std::string Component::getInstanceName() {
return instanceName; return instanceName;
} }
std::pair<int, int> Component::getCount() { std::pair<int, int> Component::getCount() {
return count; return count;
} }
Display Component::getDisplay() { Display Component::getDisplay() {
return display; return display;
} }
@ -36,13 +51,14 @@ Display Component::getDisplay() {
std::vector<Pin> Component::getPins() { std::vector<Pin> Component::getPins() {
return pins; return pins;
} }
Pin Component::getPin(std::string pin) { Pin Component::getPin(std::string pin) {
for(uint i=0; i<pins.size(); i++) { for (auto & p: pins) {
if(pins[i].getName() == pin) { if (p.getName() == pin) {
return pins[i]; return p;
} }
} }
throw std::exception(); throw std::runtime_error("no pin with name '" + pin + "'");
} }
bool Component::hasPin(std::string name) { bool Component::hasPin(std::string name) {
@ -54,32 +70,36 @@ bool Component::hasPin(std::string name) {
return false; return false;
} }
std::vector<Attribute> Component::getAttributes() { std::vector<Attribute>& Component::getAttributes() {
return attributes; return attributes;
} }
Attribute Component::getAttribute(std::string attribute) { Attribute Component::getAttribute(std::string attribute) {
for(uint i=0; i<attributes.size(); i++) { for (auto & attr : attributes) {
if(attributes[i].getName() == attribute) { if (attr.getName() == attribute) {
return attributes[i]; return attr;
} }
} }
throw std::exception(); throw std::runtime_error("no attribute with name '" + attribute + "'");
} }
bool Component::hasAttribute(std::string name, Value::ValueType type) { bool Component::hasAttribute(std::string name, Value::ValueType type) {
for(uint i=0; i<attributes.size(); i++) { for (auto & attribute : attributes) {
if(attributes[i].getName() == name && attributes[i].getDefault().getType() == type) { if (attribute.getName() == name && attribute.getDefault().getType() == type) {
return true; return true;
} }
if(attributes[i].getName() == name && (type == Value::NIL && (attributes[i].getDefault().getType() == Value::MEMORY_REFERENCE || attributes[i].getDefault().getType() == Value::WIRE_REFERENCE))) { if (attribute.getName() == name && (type == Value::NIL &&
(attribute.getDefault().getType() == Value::MEMORY_REFERENCE ||
attribute.getDefault().getType() == Value::WIRE_REFERENCE))) {
return true; return true;
} }
if(attributes[i].getName() == name && (type == Value::UNDEFINED && (attributes[i].getDefault().getType() == Value::MEMORY_REFERENCE || attributes[i].getDefault().getType() == Value::WIRE_REFERENCE))) { if (attribute.getName() == name && (type == Value::UNDEFINED &&
(attribute.getDefault().getType() == Value::MEMORY_REFERENCE ||
attribute.getDefault().getType() == Value::WIRE_REFERENCE))) {
return true; return true;
} }
} }
return false; return false;
} }
} // namespace domain } // namespace domain

View File

@ -13,8 +13,7 @@ namespace domain {
using namespace std; using namespace std;
class Component class Component {
{
public: public:
enum ComponentType { enum ComponentType {
OTHER, OTHER,
@ -24,6 +23,7 @@ public:
private: private:
std::string name; std::string name;
std::optional<std::string> displayName;
std::string tooltip; std::string tooltip;
std::string source; std::string source;
ComponentType type; ComponentType type;
@ -37,24 +37,36 @@ private:
public: public:
Component(string name, string tooltip, string source, ComponentType type, Component(string name, optional<string> displayName, string tooltip, string source, ComponentType type,
vector<Rule> rules, string instanceName, pair<int, int> count, Display display, vector<Rule> rules, string instanceName, pair<int, int> count, Display display,
vector<Pin> pins, vector<Attribute> attributes); vector<Pin> pins, vector<Attribute> attributes);
std::string getName(); std::string getName();
std::string getDisplayName();
std::string getTooltip(); std::string getTooltip();
std::string getSource(); std::string getSource();
ComponentType getType(); ComponentType getType();
std::vector<Rule> getRules(); std::vector<Rule> getRules();
std::string getInstanceName(); std::string getInstanceName();
std::pair<int, int> getCount(); std::pair<int, int> getCount();
Display getDisplay(); Display getDisplay();
std::vector<Pin> getPins(); std::vector<Pin> getPins();
Pin getPin(std::string pin); Pin getPin(std::string pin);
std::vector<Attribute> getAttributes(); std::vector<Attribute>& getAttributes();
Attribute getAttribute(std::string attribute); Attribute getAttribute(std::string attribute);
bool hasAttribute(std::string name, Value::ValueType type); bool hasAttribute(std::string name, Value::ValueType type);
bool hasPin(std::string name); bool hasPin(std::string name);

View File

@ -1,30 +1,34 @@
#include "connection.h" #include "connection.h"
#include <stdexcept>
namespace domain { namespace domain {
Connection::Connection(ConnectionComponent first, std::optional<ConnectionComponent> second, Connection::Connection(ConnectionComponent first, std::optional<ConnectionComponent> second,
std::string bus, std::vector<Attribute> attributes, std::string bus, std::vector<Attribute> attributes,
std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires) std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires)
: first(first), second(second), bus(bus), attributes(attributes), firstWires(firstWires), secondWires(secondWires) : first(first), second(second), bus(bus), attributes(attributes), firstWires(firstWires),
{} secondWires(secondWires) {}
ConnectionComponent Connection::getComponent() { ConnectionComponent Connection::getComponent() {
return first; return first;
} }
std::optional<ConnectionComponent> Connection::getSecondComponent() { std::optional<ConnectionComponent> Connection::getSecondComponent() {
return second; return second;
} }
std::string Connection::getBus() { std::string &Connection::getBus() {
return bus; return bus;
} }
std::vector<Attribute> Connection::getAttributes() { std::vector<Attribute>& Connection::getAttributes() {
return attributes; return attributes;
} }
std::vector<Value> Connection::getWires() { std::vector<Value> Connection::getWires() {
return firstWires; return firstWires;
} }
std::optional<std::vector<Value>> Connection::getSecondWires() { std::optional<std::vector<Value>> Connection::getSecondWires() {
return secondWires; return secondWires;
} }
@ -35,7 +39,7 @@ Attribute Connection::getAttribute(std::string name) {
return attributes[i]; return attributes[i];
} }
} }
throw std::exception(); throw std::runtime_error("no attribute with name '" + name + "'");
} }
bool Connection::hasAttribute(std::string name) { bool Connection::hasAttribute(std::string name) {

View File

@ -8,21 +8,19 @@
namespace domain { namespace domain {
struct ConnectionComponent struct ConnectionComponent {
{
std::string component; std::string component;
std::string pin; std::string pin;
bool operator==(const ConnectionComponent& rhs) const bool operator==(const ConnectionComponent &rhs) const {
{
return (component == rhs.component) && (pin == rhs.pin); return (component == rhs.component) && (pin == rhs.pin);
} }
bool operator!=(const ConnectionComponent& rhs) const
{ bool operator!=(const ConnectionComponent &rhs) const {
return !operator==(rhs); return !operator==(rhs);
} }
bool operator<(const ConnectionComponent& rhs) const
{ bool operator<(const ConnectionComponent &rhs) const {
if (component < rhs.component) { if (component < rhs.component) {
return true; return true;
} else if (component == rhs.component) { } else if (component == rhs.component) {
@ -34,8 +32,7 @@ struct ConnectionComponent
} }
}; };
class Connection class Connection {
{
ConnectionComponent first; ConnectionComponent first;
std::optional<ConnectionComponent> second; std::optional<ConnectionComponent> second;
std::string bus; std::string bus;
@ -49,22 +46,31 @@ public:
std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires); std::vector<Value> firstWires, std::optional<std::vector<Value>> secondWires);
bool isConnecting(ConnectionComponent first); bool isConnecting(ConnectionComponent first);
bool isConnecting(ConnectionComponent first, std::string bus); bool isConnecting(ConnectionComponent first, std::string bus);
bool isConnecting(ConnectionComponent first, std::string bus, ConnectionComponent second); bool isConnecting(ConnectionComponent first, std::string bus, ConnectionComponent second);
bool isConnecting(ConnectionComponent first, ConnectionComponent second); bool isConnecting(ConnectionComponent first, ConnectionComponent second);
bool operator==(const Connection& connection) {
return (first == connection.first && bus == connection.bus && second == connection.second);
}
ConnectionComponent getComponent(); ConnectionComponent getComponent();
std::optional<ConnectionComponent> getSecondComponent(); std::optional<ConnectionComponent> getSecondComponent();
std::string getBus(); std::string &getBus();
std::vector<Attribute> getAttributes(); std::vector<Attribute>& getAttributes();
std::vector<Value> getWires(); std::vector<Value> getWires();
std::optional<std::vector<Value>> getSecondWires(); std::optional<std::vector<Value>> getSecondWires();
Attribute getAttribute(std::string name); Attribute getAttribute(std::string name);
bool hasAttribute(std::string name); bool hasAttribute(std::string name);
}; };

View File

@ -0,0 +1,49 @@
#include "connection_instance.h"
#include <stdexcept>
namespace domain {
ConnectionInstance::ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes,
Connection connection)
: instance(instance), attributes(attributes), connection(connection) {}
InstanceAttribute ConnectionInstance::getAttribute(string attribute) {
for (auto &attr: attributes) {
if (attr.name == attribute) {
return attr;
}
}
throw std::runtime_error("no attribute with name '" + attribute + "'");
}
BusConnectionInstance::BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes,
BusInstance *bus, Connection connection)
: ConnectionInstance(instance, attributes, connection), bus(bus) {}
DirectConnectionInstance::DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondInstance,
std::vector<InstanceAttribute> attributes, BusInstance *bus,
Connection connection)
: ConnectionInstance(instance, attributes, connection), secondInstance(secondInstance), bus(bus) {}
int DirectConnectionInstance::getSelected(ConnectionComponent conn) {
if(this->instance->name == conn.component) {
auto selected = attributes[0].value.asString();
for(int i=0; i<connection.getWires().size(); i++) {
if(connection.getWires()[i].isType(Value::STRING) && connection.getWires()[i].asString() == selected) {
return i;
}
}
} else {
auto selected = attributes[1].value.asString();
for(int i=0; i<connection.getSecondWires()->size(); i++) {
if(connection.getSecondWires().value()[i].isType(Value::STRING) && connection.getSecondWires().value()[i].asString() == selected) {
return i;
}
}
}
return -1;
}
} // namespace domain

View File

@ -0,0 +1,51 @@
#ifndef DOMAIN_CONNECTION_INSTANCE_H
#define DOMAIN_CONNECTION_INSTANCE_H
#include "connection.h"
#include "instance.h"
namespace domain {
class ConnectionInstance {
public:
ComponentInstance *instance;
Connection connection;
virtual ~ConnectionInstance() = default;
std::vector<InstanceAttribute> attributes;
std::pair<int, int> start;
std::pair<int, int> end;
ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes,
Connection connection);
InstanceAttribute getAttribute(string attribute);
};
class BusConnectionInstance : public ConnectionInstance {
public:
BusInstance *bus;
BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, BusInstance *bus,
Connection connection);
};
class DirectConnectionInstance : public ConnectionInstance {
public:
BusInstance *bus;
ComponentInstance *secondInstance;
DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance,
std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection);
int getSelected(ConnectionComponent connection);
};
} // namespace domain
#endif // DOMAIN_CONNECTIONINSTANCE_H

View File

@ -1,28 +0,0 @@
#include "connectioninstance.h"
namespace domain {
ConnectionInstance::ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, Connection connection)
: instance(instance), attributes(attributes), connection(connection)
{}
InstanceAttribute ConnectionInstance::getAttribute(string attribute) {
for(auto& attr: attributes) {
if(attr.name == attribute) {
return attr;
}
}
throw std::exception();
}
BusConnectionInstance::BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection)
: ConnectionInstance(instance, attributes, connection), bus(bus)
{}
DirectConnectionInstance::DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondInstance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection)
: ConnectionInstance(instance, attributes, connection), secondInstance(secondInstance), bus(bus)
{}
} // namespace domain

View File

@ -1,50 +0,0 @@
#ifndef DOMAIN_CONNECTION_INSTANCE_H
#define DOMAIN_CONNECTION_INSTANCE_H
#include "connection.h"
#include "instance.h"
#include "wireinstance.h"
namespace domain {
class ConnectionInstance
{
public:
ComponentInstance *instance;
Connection connection;
virtual ~ConnectionInstance() = default;
std::vector<InstanceAttribute> attributes;
std::pair<int, int> start;
std::pair<int, int> end;
ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, Connection connection);
InstanceAttribute getAttribute(string attribute);
};
class BusConnectionInstance: public ConnectionInstance
{
public:
BusInstance *bus;
BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection);
};
class DirectConnectionInstance: public ConnectionInstance
{
public:
BusInstance *bus;
ComponentInstance *secondInstance;
DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection);
};
} // namespace domain
#endif // DOMAIN_CONNECTIONINSTANCE_H

View File

@ -1,7 +1,265 @@
#include "display.h" #include "display.h"
#include <QBrush>
#include <QPen>
#include <QFont>
#include "comdel/domain/instance.h"
namespace domain { namespace domain {
Display::Display(std::vector<ui::Item> items) : items(items) {} Display::Display(std::vector<ui::Item> items) : items(items) {}
void Display::render(QGraphicsItemGroup *group, ui::DisplayContext context) {
for (auto &item: items) {
item.render(group, context);
}
}
void Display::comdel(std::ostream &buffer, int x, int y, int size) {
for (auto &item: items) {
item.comdel(buffer, x, y, size);
}
}
void ui::Text::render(QGraphicsItemGroup *group, ui::DisplayContext context) {
auto formattedText = context.populateMessage(text);
auto content = new QGraphicsTextItem(QString::fromStdString(formattedText));
content->setDefaultTextColor(color);
content->setPos(x, y);
content->setFont(QFont("arial", 8));
group->addToGroup(content);
}
void ui::Text::comdel(std::ostream &buffer, int x, int y) {
// TODO
}
void ui::Rect::render(QGraphicsItemGroup *group) {
auto rect = new QGraphicsRectItem(x, y, w, h);
rect->setPen(QPen(config.lineColor));
rect->setBrush(QBrush(config.fillColor));
group->addToGroup(rect);
}
void ui::Rect::comdel(std::ostream &buffer, int x, int y) {
buffer << "\t\trectangle {\n";
buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n";
buffer << "\t\t\twidth: " << w << "; height: " << h << ";\n";
buffer << "\t\t\tfill_color: " << this->config.fillColor.name().toStdString() << ";\n";
buffer << "\t\t\tline_color: " << this->config.lineColor.name().toStdString() << ";\n";
buffer << "\t\t}\n\n";
}
void ui::Ellipse::render(QGraphicsItemGroup *group) {
auto ellipse = new QGraphicsEllipseItem(x, y, w, h);
ellipse->setPen(QPen(config.lineColor));
ellipse->setBrush(QBrush(config.fillColor));
group->addToGroup(ellipse);
}
void ui::Ellipse::comdel(std::ostream &buffer, int x, int y) {
buffer << "\t\tellipse {\n";
buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n";
buffer << "\t\t\twidth: " << w << "; height: " << h << ";\n";
buffer << "\t\t}\n\n";
}
void ui::Line::render(QGraphicsItemGroup *group) {
auto line = new QGraphicsLineItem(x1, y1, x2, y2);
line->setPen(QPen(config.lineColor));
group->addToGroup(line);
}
void ui::Line::comdel(std::ostream &buffer, int x, int y) {
buffer << "\t\tpath {\n";
buffer << "\t\t\tx:0; y:0;\n";
buffer << "\t\t\tpoints: (";
buffer << "(" << (x1 + x) << ", " << (y1 + y) << "),";
buffer << "(" << (x2 - x1) << "," << (y2 - y1) << "));\n";
buffer << "\t\t}" << std::endl;
}
void ui::Bus::render(QGraphicsItemGroup *group, int size) {
int _w = w, _h = h;
if (orientation == HORIZONTAL) {
_w = size;
} else {
_h = size;
}
auto rect = new QGraphicsRectItem(x, y, _w, _h);
rect->setBrush(QBrush(config.fillColor));
rect->setPen(QPen(config.lineColor));
group->addToGroup(rect);
}
int ui::Bus::getDefaultSize() {
if (orientation == HORIZONTAL) {
return w;
} else {
return h;
}
}
void ui::Bus::comdel(std::ostream &buffer, int x, int y, int size) {
buffer << "\t\trectangle {\n";
buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n";
if (orientation == HORIZONTAL) {
buffer << "\t\t\twidth: " << size << "; height: " << h << ";\n";
} else {
buffer << "\t\t\twidth: " << w << "; height: " << size << ";\n";
}
buffer << "\t\t\tfill_color: " << this->config.fillColor.name().toStdString() << ";\n";
buffer << "\t\t\tline_color: " << this->config.lineColor.name().toStdString() << ";\n";
buffer << "\t\t}\n\n";
}
void ui::Pin::renderIn(QGraphicsItemGroup *group) {
QPolygon polygon;
switch (orientation) {
case PinOrientation::TOP:
polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w, y + h) << QPoint(x + w, y)
<< QPoint(x + w / 2, y + h / 2);
break;
case PinOrientation::BOTTOM:
polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w / 2, y + h / 2)
<< QPoint(x + w, y + h) << QPoint(x + w, y);
break;
case PinOrientation::LEFT:
polygon << QPoint(x, y) << QPoint(x + w / 2, y + h / 2) << QPoint(x, y + h)
<< QPoint(x + w, y + h) << QPoint(x + w, y);
break;
case PinOrientation::RIGHT:
polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w, y + h)
<< QPoint(x + w / 2, y + h / 2) << QPoint(x + w, y);
break;
}
auto item = new QGraphicsPolygonItem(polygon);
item->setFillRule(Qt::OddEvenFill);
item->setBrush(QBrush(config.fillColor));
item->setPen(QPen(config.lineColor));
group->addToGroup(item);
}
void ui::Pin::renderOut(QGraphicsItemGroup *group) {
QPolygon polygon;
switch (orientation) {
case PinOrientation::TOP:
polygon << QPoint(x, y + h / 2) << QPoint(x, y + h) << QPoint(x + w, y + h)
<< QPoint(x + w, y + h / 2) << QPoint(x + w / 2, y);
break;
case PinOrientation::BOTTOM:
polygon << QPoint(x, y) << QPoint(x, y + h / 2) << QPoint(x + w / 2, y + h)
<< QPoint(x + w, y + h / 2) << QPoint(x + w, y);
break;
case PinOrientation::LEFT:
polygon << QPoint(x + w, y) << QPoint(x + w / 2, y) << QPoint(x, y + h / 2)
<< QPoint(x + w / 2, y + h) << QPoint(x + w, y + w);
break;
case PinOrientation::RIGHT:
polygon << QPoint(x, y) << QPoint(x, y + h) << QPoint(x + w / 2, y + h)
<< QPoint(x + w, y + h / 2) << QPoint(x + w / 2, y);
break;
}
auto item = new QGraphicsPolygonItem(polygon);
item->setFillRule(Qt::OddEvenFill);
item->setBrush(QBrush(config.fillColor));
item->setPen(QPen(config.lineColor));
group->addToGroup(item);
}
void ui::Pin::renderInOut(QGraphicsItemGroup *group) {
auto rect = new QGraphicsRectItem(x, y, w, h);
rect->setBrush(QBrush(config.fillColor));
rect->setPen(QPen(config.lineColor));
group->addToGroup(rect);
}
void ui::Pin::render(QGraphicsItemGroup *group) {
switch (pinType) {
case PinType::IN:
renderIn(group);
break;
case PinType::OUT:
renderOut(group);
break;
case PinType::IN_OUT:
renderInOut(group);
break;
}
}
int ui::Pin::getConnectionX() {
switch (orientation) {
case ui::PinOrientation::TOP:
case ui::PinOrientation::BOTTOM:
return x + w / 2;
case ui::PinOrientation::LEFT:
return x;
case ui::PinOrientation::RIGHT:
return x + w;
}
return 0;
}
int ui::Pin::getConnectionY() {
switch (orientation) {
case ui::PinOrientation::LEFT:
case ui::PinOrientation::RIGHT:
return y + h / 2;
case ui::PinOrientation::TOP:
return y;
case ui::PinOrientation::BOTTOM:
return y + h;
}
return 0;
}
void ui::Item::render(QGraphicsItemGroup *group, ui::DisplayContext context, int size) {
if (rect) rect->render(group);
if (line) line->render(group);
if (pin) pin->render(group);
if (bus) bus->render(group, size);
if (text) text->render(group, context);
if (ellipse) ellipse->render(group);
}
void ui::Item::comdel(std::ostream &buffer, int x, int y, int size) {
if (rect) rect->comdel(buffer, x, y);
if (line) line->comdel(buffer, x, y);
// pins aren't exported
if (bus) bus->comdel(buffer, x, y, size);
// text currently isn't exported TODO
}
ui::DisplayContext::DisplayContext(ComponentInstance *instance) {
for(auto attr: instance->attributes) {
this->values[attr.name] = attr.value;
}
this->values["instanceName"] = Value::fromString(instance->name);
}
string 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;
}
std::string ui::DisplayContext::populateMessage(std::string source) {
for (auto &[key, value]: values) {
source = replacePlaceholder(source, key, value);
}
return source;
}
} // namespace domain } // namespace domain

View File

@ -5,48 +5,87 @@
#include <optional> #include <optional>
#include <ostream> #include <ostream>
#include "comdel/parser/color.h"
#include "value.h"
namespace domain { namespace domain {
namespace ui { namespace ui {
class DisplayContext {
std::map<std::string, domain::Value> values;
public:
explicit DisplayContext(ComponentInstance *instance);
std::string populateMessage(std::string message);
};
struct DisplayConfig {
QColor lineColor;
QColor fillColor;
DisplayConfig(Color lineColor, Color fillColor) {
this->lineColor = QColor::fromRgb(lineColor.r, lineColor.g, lineColor.b, lineColor.a);
this->fillColor = QColor::fromRgb(fillColor.r, fillColor.g, fillColor.b, fillColor.a);
}
};
class Text {
public:
int x, y, w, h;
QColor color;
std::string text;
Text(int x, int y, int w, int h, std::string text, Color color) : x(x), y(y), w(w), h(h), text(text),
color(QColor::fromRgb(color.r, color.g, color.b, color.a)) {}
void render(QGraphicsItemGroup *group, ui::DisplayContext context);
void comdel(std::ostream &buffer, int x, int y);
};
class Rect { class Rect {
public: public:
int x, y, w, h; int x, y, w, h;
DisplayConfig config;
Rect(int x, int y, int w, int h): x(x), y(y), w(w), h(h) {} Rect(int x, int y, int w, int h, DisplayConfig config) : x(x), y(y), w(w), h(h), config(config) {}
void render(QGraphicsItemGroup *group) { void render(QGraphicsItemGroup *group);
group->addToGroup(new QGraphicsRectItem(x,y,w,h));
}
void comdel(std::ostream &buffer, int x, int y) { void comdel(std::ostream &buffer, int x, int y);
buffer << "\t\trectangle {\n";
buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n"; };
buffer << "\t\t\tw: " << w << "; h: " << h << ";\n";
buffer << "\t\t}\n\n"; class Ellipse {
} public:
int x, y, w, h;
DisplayConfig config;
Ellipse(int x, int y, int w, int h, DisplayConfig config) : x(x), y(y), w(w), h(h), config(config) {}
void render(QGraphicsItemGroup *group);
void comdel(std::ostream &buffer, int x, int y);
}; };
class Line { class Line {
public: public:
int x1, y1, x2, y2; int x1, y1, x2, y2;
DisplayConfig config;
Line(int x1, int y1, int x2, int y2): x1(x1), y1(y1), x2(x2), y2(y2) {} Line(int x1, int y1, int x2, int y2, DisplayConfig config) : x1(x1), y1(y1), x2(x2), y2(y2), config(config) {}
void render(QGraphicsItemGroup *group) { void render(QGraphicsItemGroup *group);
group->addToGroup(new QGraphicsLineItem(x1, y1, x2, y2));
}
void comdel(std::ostream &buffer, int x, int y) { void comdel(std::ostream &buffer, int x, int y);
buffer << "\t\tline {\n";
buffer << "\t\t\tx1: " << (x1 + x) << "; y1: " << (y1 + y) << ";\n";
buffer << "\t\t\tx2: " << (x2 + x) << "; y2: " << (y2 + y) << ";\n";
buffer << "\t\t}\n\n";
}
}; };
enum PinType {
IN, OUT, IN_OUT
};
enum PinOrientation { enum PinOrientation {
LEFT, RIGHT, TOP, BOTTOM LEFT, RIGHT, TOP, BOTTOM
}; };
@ -54,139 +93,46 @@ enum BusOrientation {
VERTICAL, HORIZONTAL VERTICAL, HORIZONTAL
}; };
enum PinType {
IN, OUT, IN_OUT
};
class Bus { class Bus {
public: public:
int x, y, w, h; int x, y, w, h;
BusOrientation orientation; BusOrientation orientation;
DisplayConfig config;
Bus(int x, int y, int w, int h, BusOrientation orientation): x(x), y(y), w(w), h(h), orientation(orientation) {} Bus(int x, int y, int w, int h, BusOrientation orientation, DisplayConfig config) : x(x), y(y), w(w), h(h),
orientation(orientation),
config(config) {}
void render(QGraphicsItemGroup *group, int size) { void render(QGraphicsItemGroup *group, int size);
if(orientation == HORIZONTAL) {
group->addToGroup(new QGraphicsRectItem(x,y,size, h));
} else {
group->addToGroup(new QGraphicsRectItem(x,y,w,size));
}
}
int getDefaultSize() { int getDefaultSize();
if(orientation == HORIZONTAL) {
return w;
} else {
return h;
}
}
void comdel(std::ostream &buffer, int x, int y, int size) { void comdel(std::ostream &buffer, int x, int y, int size);
buffer << "\t\trectangle {\n";
buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n";
if(orientation == HORIZONTAL) {
buffer << "\t\t\tw: " << size << "; h: " << h << ";\n";
} else {
buffer << "\t\t\tw: " << w << "; h: " << size << ";\n";
}
buffer << "\t\t}\n\n";
}
}; };
class Pin { class Pin {
public: public:
PinOrientation orientation; PinOrientation orientation;
PinType pinType; PinType pinType;
int x, y, w, h; int x, y, w, h;
DisplayConfig config;
Pin(int x, int y, int w, int h, PinOrientation orientation, PinType pinType): x(x), y(y), w(w), h(h), orientation(orientation), pinType(pinType) {} Pin(int x, int y, int w, int h, PinOrientation orientation, PinType pinType, DisplayConfig config)
: x(x), y(y), w(w), h(h), orientation(orientation), pinType(pinType), config(config) {}
void renderIn(QGraphicsItemGroup *group) { Pin(): config(DisplayConfig(Color(), Color())) {};
QPolygon polygon;
switch (orientation) { public:
case PinOrientation::TOP: void render(QGraphicsItemGroup *group);
polygon << QPoint(x, y) << QPoint(x, y+h) << QPoint(x+w, y+h) << QPoint(x+w, y) << QPoint(x+w/2, y+h/2);
break;
case PinOrientation::BOTTOM:
polygon << QPoint(x, y) << QPoint(x, y+h) << QPoint(x+w/2, y+h/2) << QPoint(x+w, y+h) << QPoint(x+w, y);
break;
case PinOrientation::LEFT:
polygon << QPoint(x, y) << QPoint(x+w/2, y+h/2) << QPoint(x, y+h) << QPoint(x+w, y+h) << QPoint(x+w, y);
break;
case PinOrientation::RIGHT:
polygon << QPoint(x, y) << QPoint(x, y+h) << QPoint(x+w, y+h) << QPoint(x+w/2, y+h/2) << QPoint(x+w, y);
break;
}
group->addToGroup(new QGraphicsPolygonItem(polygon));
}
void renderOut(QGraphicsItemGroup *group) { int getConnectionX();
QPolygon polygon; int getConnectionY();
switch (orientation) { private:
case PinOrientation::TOP: void renderIn(QGraphicsItemGroup *group);
polygon << QPoint(x, y+h/2) << QPoint(x, y+h) << QPoint(x+w, y+h) << QPoint(x+w, y+h/2) << QPoint(x+w/2, y); void renderOut(QGraphicsItemGroup *group);
break; void renderInOut(QGraphicsItemGroup *group);
case PinOrientation::BOTTOM:
polygon << QPoint(x, y) << QPoint(x, y+h/2) << QPoint(x+w/2, y+h) << QPoint(x+w, y+h/2) << QPoint(x+w, y);
break;
case PinOrientation::LEFT:
polygon << QPoint(x+w, y) << QPoint(x+w/2, y) << QPoint(x, y+h/2) << QPoint(x+w/2, y+h) << QPoint(x+w, y+w);
break;
case PinOrientation::RIGHT:
polygon << QPoint(x, y) << QPoint(x, y+h) << QPoint(x+w/2, y+h) << QPoint(x+w, y+h/2) << QPoint(x+w/2, y);
break;
}
group->addToGroup(new QGraphicsPolygonItem(polygon));
}
void renderInOut(QGraphicsItemGroup *group) {
group->addToGroup(new QGraphicsRectItem(x, y ,w, h));
}
void render(QGraphicsItemGroup *group) {
switch (pinType) {
case PinType::IN:
renderIn(group);
break;
case PinType::OUT:
renderOut(group);
break;
case PinType::IN_OUT:
renderInOut(group);
break;
}
}
int getConnectionX() {
switch (orientation) {
case ui::PinOrientation::TOP:
case ui::PinOrientation::BOTTOM:
return x+w/2;
case ui::PinOrientation::LEFT:
return x;
case ui::PinOrientation::RIGHT:
return x+w;
}
return 0;
}
int getConnectionY() {
switch (orientation) {
case ui::PinOrientation::LEFT:
case ui::PinOrientation::RIGHT:
return y+h/2;
case ui::PinOrientation::TOP:
return y;
case ui::PinOrientation::BOTTOM:
return y+h;
}
return 0;
}
}; };
@ -194,45 +140,27 @@ class Item {
public: public:
Item() : rect(std::nullopt), line(std::nullopt), pin(std::nullopt), bus(std::nullopt) {} Item() : rect(std::nullopt), line(std::nullopt), pin(std::nullopt), bus(std::nullopt) {}
void render(QGraphicsItemGroup *group, int size = 0) {
if(rect) rect->render(group);
if(line) line->render(group);
if(pin) pin->render(group);
if(bus) bus->render(group, size);
}
std::optional<Rect> rect = std::nullopt; std::optional<Rect> rect = std::nullopt;
std::optional<Line> line = std::nullopt; std::optional<Line> line = std::nullopt;
std::optional<Pin> pin = std::nullopt; std::optional<Pin> pin = std::nullopt;
std::optional<Bus> bus = std::nullopt; std::optional<Bus> bus = std::nullopt;
std::optional<Text> text = std::nullopt;
std::optional<Ellipse> ellipse = std::nullopt;
void comdel(std::ostream &buffer, int x, int y, int size = 0) { void render(QGraphicsItemGroup *group, ui::DisplayContext context, int size = 0);
if(rect) rect->comdel(buffer, x, y); void comdel(std::ostream &buffer, int x, int y, int size = 0);
if(line) line->comdel(buffer, x, y);
// pins aren't exported
if(bus) bus->comdel(buffer, x, y, size);
}
}; };
} }
class Display class Display {
{
public: public:
Display(std::vector<ui::Item> items); Display(std::vector<ui::Item> items);
void render(QGraphicsItemGroup *group) { void render(QGraphicsItemGroup *group, ui::DisplayContext context);
for(auto &item: items) {
item.render(group);
}
}
void comdel(std::ostream &buffer, int x, int y, int size = 0) { void comdel(std::ostream &buffer, int x, int y, int size = 0);
for(auto &item: items) {
item.comdel(buffer, x, y, size);
}
}
std::vector<ui::Item> &getItems() { return items; } std::vector<ui::Item> &getItems() { return items; }

View File

@ -0,0 +1,166 @@
#include <map>
#include <utility>
#include "function_signature.h"
namespace domain {
class DivisibleValidator : public FunctionValidator {
public:
DivisibleValidator() : FunctionValidator("divisible", {Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if (validateSignature(values)) {
long long first = values[0].asInt();
long long second = values[1].asInt();
return (first % second) == 0;
}
return false;
}
void clear() override {}
};
class LessThenValidator : public FunctionValidator {
public:
LessThenValidator() : FunctionValidator("less_then", {Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if (validateSignature(values)) {
long long first = values[0].asInt();
long long second = values[1].asInt();
return first < second;
}
return false;
}
void clear() override {}
};
class GreaterThenValidator : public FunctionValidator {
public:
GreaterThenValidator() : FunctionValidator("greater_then", {Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if (validateSignature(values)) {
long long first = values[0].asInt();
long long second = values[1].asInt();
return first > second;
}
return false;
}
void clear() override {}
};
class ContainsAddressValidator : public FunctionValidator {
public:
ContainsAddressValidator() : FunctionValidator("contains_address", {Value::ADDRESS_SPACE, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if (validateSignature(values)) {
AddressSpace space = values[0].asAddressSpace();
long long address = values[1].asInt();
return space.contains(address);
}
return false;
}
void clear() override {}
};
class ContainsValidator : public FunctionValidator {
public:
ContainsValidator() : FunctionValidator("contains", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if (validateSignature(values)) {
AddressSpace space = values[0].asAddressSpace();
long long start = values[1].asInt();
long long size = values[1].asInt();
return space.contains(start, start + size);
}
return false;
}
void clear() override {}
};
class UniqueValidator : public FunctionValidator {
private:
std::map<std::string, std::vector<std::pair<long long int, long long int>>> spaces;
bool overlaps(long long int start1, long long int end1, long long int start2, long long int end2) {
return std::max((long long int) 0, std::min(end1, end2) - std::max(start1, start2)) > 0;
}
public:
UniqueValidator() : FunctionValidator("unique", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if (validateSignature(values)) {
std::string space = values[0].asAddressSpace().getName();
long long int start = values[1].asInt();
long long int end = start + values[2].asInt();
if (spaces.count(space) == 0) {
spaces.insert(std::make_pair(space, std::vector<std::pair<long long int, long long int>>{}));
}
for (auto &s: spaces[space]) {
if (overlaps(s.first, s.second, start, end)) {
return false;
}
}
spaces[space].push_back(std::make_pair(start, end));
return true;
}
return false;
}
void clear() override {
spaces.clear();
}
};
std::vector<FunctionValidator *> getSupportedValidators() {
std::vector<FunctionValidator *> validators;
validators.push_back(new DivisibleValidator());
validators.push_back(new LessThenValidator());
validators.push_back(new GreaterThenValidator());
validators.push_back(new ContainsAddressValidator());
validators.push_back(new ContainsValidator());
validators.push_back(new UniqueValidator());
return validators;
}
FunctionValidator::FunctionValidator(std::string name, std::vector<Value::ValueType> signature)
: name(std::move(name)), signature(std::move(signature)) {}
std::string FunctionValidator::getName() {
return name;
}
std::vector<Value::ValueType> FunctionValidator::getSignature() {
return signature;
}
bool FunctionValidator::validateSignature(std::vector<Value> _signature) {
if (this->signature.size() != _signature.size()) {
return false;
}
for (int i = 0; i < this->signature.size(); i++) {
if (this->signature[i] != _signature[i].getType()) {
return false;
}
}
return true;
}
} // namespace domain

View File

@ -0,0 +1,36 @@
#ifndef DOMAIN_FUNCTION_VALIDATOR_H
#define DOMAIN_FUNCTION_VALIDATOR_H
#include<functional>
#include<vector>
#include "value.h"
namespace domain {
class FunctionValidator {
private:
std::string name;
std::vector<Value::ValueType> signature;
protected:
FunctionValidator(std::string name, std::vector<Value::ValueType> signature);
public:
std::string getName();
std::vector<Value::ValueType> getSignature();
bool validateSignature(std::vector<Value> signature);
virtual bool validate(std::vector<Value> values) = 0;
virtual void clear() = 0;
};
std::vector<FunctionValidator *> getSupportedValidators();
} // namespace domain
#endif // DOMAIN_FUNCTION_VALIDATOR_H

View File

@ -1,138 +0,0 @@
#include <map>
#include "functionsignature.h"
namespace domain {
class DivisibleValidator: public FunctionValidator {
public:
DivisibleValidator(): FunctionValidator("divisible", {Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if(validateSignature(values)) {
long long first = values[0].asInt();
long long second = values[1].asInt();
return (first % second) == 0;
}
return false;
}
void clear() override {}
};
class LessThenValidator: public FunctionValidator {
public:
LessThenValidator(): FunctionValidator("less_then", {Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if(validateSignature(values)) {
long long first = values[0].asInt();
long long second = values[1].asInt();
return first < second;
}
return false;
}
void clear() override {}
};
class GreaterThenValidator: public FunctionValidator {
public:
GreaterThenValidator(): FunctionValidator("greater_then", {Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if(validateSignature(values)) {
long long first = values[0].asInt();
long long second = values[1].asInt();
return first > second;
}
return false;
}
void clear() override {}
};
class ContainsAddressValidator: public FunctionValidator {
public:
ContainsAddressValidator(): FunctionValidator("contains_address", {Value::ADDRESS_SPACE, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if(validateSignature(values)) {
AddressSpace space = values[0].asAddressSpace();
long long address = values[1].asInt();
return space.contains(address);
}
return false;
}
void clear() override {}
};
class ContainsValidator: public FunctionValidator {
public:
ContainsValidator(): FunctionValidator("contains", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if(validateSignature(values)) {
AddressSpace space = values[0].asAddressSpace();
long long start = values[1].asInt();
long long size = values[1].asInt();
return space.contains(start, start + size);
}
return false;
}
void clear() override {}
};
class UniqueValidator: public FunctionValidator {
private:
std::map<std::string, std::vector<std::pair<long long int, long long int>>> spaces;
bool overlaps(long long int start1, long long int end1, long long int start2, long long int end2) {
return std::max((long long int)0, std::min(end1, end2) - std::max(start1, start2)) > 0;
}
public:
UniqueValidator(): FunctionValidator("unique", {Value::ADDRESS_SPACE, Value::INT, Value::INT}) {}
bool validate(std::vector<Value> values) override {
if(validateSignature(values)) {
std::string space = values[0].asAddressSpace().getName();
long long int start = values[1].asInt();
long long int end = start + values[2].asInt();
if(spaces.count(space) == 0) {
spaces.insert(std::make_pair(space, std::vector<std::pair<long long int, long long int>>{}));
}
for(auto& s: spaces[space]) {
if(overlaps(s.first, s.second, start, end)) {
return false;
}
}
spaces[space].push_back(std::make_pair(start, end));
return true;
}
return false;
}
void clear() override {
spaces.clear();
}
};
std::vector<FunctionValidator*> getSupportedValidators() {
std::vector<FunctionValidator*> validators;
validators.push_back(new DivisibleValidator());
validators.push_back(new LessThenValidator());
validators.push_back(new GreaterThenValidator());
validators.push_back(new ContainsAddressValidator());
validators.push_back(new ContainsValidator());
validators.push_back(new UniqueValidator());
return validators;
}
} // namespace domain

View File

@ -1,53 +0,0 @@
#ifndef DOMAIN_FUNCTION_VALIDATOR_H
#define DOMAIN_FUNCTION_VALIDATOR_H
#include<functional>
#include<vector>
#include "value.h"
namespace domain {
class FunctionValidator {
private:
std::string name;
std::vector<Value::ValueType> signature;
protected:
FunctionValidator(std::string name, std::vector<Value::ValueType> signature) {
this->name = name;
this->signature = signature;
}
public:
std::string getName() {
return name;
}
std::vector<Value::ValueType> getSignature() {
return signature;
}
bool validateSignature(std::vector<Value> signature) {
if(this->signature.size() != signature.size()) {
return false;
}
for(int i=0; i<this->signature.size(); i++) {
if(this->signature[i] != signature[i].getType()) {
return false;
}
}
return true;
}
virtual bool validate(std::vector<Value> values) = 0;
virtual void clear() = 0;
};
std::vector<FunctionValidator*> getSupportedValidators();
} // namespace domain
#endif // DOMAIN_FUNCTION_VALIDATOR_H

View File

@ -3,8 +3,7 @@
namespace domain { namespace domain {
BusInstance::BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size) BusInstance::BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size)
: name(name), position(position), bus(bus), size(size) : name(name), position(position), bus(bus), size(size) {
{
if (size < 0 && bus.getDisplayBus().has_value()) { if (size < 0 && bus.getDisplayBus().has_value()) {
this->size = bus.getDisplayBus()->getDefaultSize(); this->size = bus.getDisplayBus()->getDefaultSize();
} }
@ -12,9 +11,9 @@ BusInstance::BusInstance(std::string name, std::pair<int, int> position, Bus bus
BusInstance::BusInstance(std::string name, Bus bus) : name(name), bus(bus), position(0, 0), size(0) {} BusInstance::BusInstance(std::string name, Bus bus) : name(name), bus(bus), position(0, 0), size(0) {}
ComponentInstance::ComponentInstance(std::string name, std::vector<InstanceAttribute> attributes, std::pair<int, int> position, Component component) ComponentInstance::ComponentInstance(std::string name, std::vector<InstanceAttribute> attributes,
: name(name), attributes(std::move(attributes)), position(position), component(component) std::pair<int, int> position, Component component)
{} : name(name), attributes(std::move(attributes)), position(position), component(component) {}
} // namespace domain } // namespace domain

View File

@ -3,17 +3,15 @@
#include "bus.h" #include "bus.h"
#include "component.h" #include "component.h"
#include "instanceattribute.h" #include "instance_attribute.h"
#include <string> #include <string>
#include <vector> #include <vector>
namespace domain { namespace domain {
class BusInstance class BusInstance {
{
public: public:
std::string name; std::string name;
std::pair<int, int> position; std::pair<int, int> position;
@ -28,8 +26,7 @@ public:
virtual ~BusInstance() = default; virtual ~BusInstance() = default;
}; };
class ComponentInstance class ComponentInstance {
{
public: public:
std::string name; std::string name;
std::vector<InstanceAttribute> attributes; std::vector<InstanceAttribute> attributes;

View File

@ -0,0 +1,8 @@
#include "instance_attribute.h"
namespace domain {
InstanceAttribute::InstanceAttribute(std::string name, Value value, Attribute attribute)
: name(name), value(value), attribute(attribute) {}
} // namespace domain

View File

@ -0,0 +1,25 @@
#ifndef DOMAIN_INSTANCE_ATTRIBUTE_H
#define DOMAIN_INSTANCE_ATTRIBUTE_H
#include "attribute.h"
#include "value.h"
#include <string>
namespace domain {
class InstanceAttribute {
public:
InstanceAttribute(std::string name, Value value, Attribute attribute);
std::string name;
Value value;
Attribute attribute;
~InstanceAttribute() = default;
};
} // namespace domain
#endif // DOMAIN_INSTANCE_ATTRIBUTE_H

View File

@ -1,9 +0,0 @@
#include "instanceattribute.h"
namespace domain {
InstanceAttribute::InstanceAttribute(std::string name, Value value, Attribute attribute)
: name(name), value(value), attribute(attribute)
{}
} // namespace domain

View File

@ -1,27 +0,0 @@
#ifndef DOMAIN_INSTANCE_ATTRIBUTE_H
#define DOMAIN_INSTANCE_ATTRIBUTE_H
#include "attribute.h"
#include "value.h"
#include <string>
namespace domain {
class InstanceAttribute
{
public:
InstanceAttribute(std::string name, Value value, Attribute attribute);
std::string name = "";
Value value;
Attribute attribute;
~InstanceAttribute() = default;
};
} // namespace domain
#endif // DOMAIN_INSTANCE_ATTRIBUTE_H

View File

@ -1,25 +1,32 @@
#include "library.h" #include "library.h"
#include <stdexcept>
namespace domain { namespace domain {
Library::Library(string name, string libraryInfo, string header, string componentDirectory, std::optional<std::string> componentHeader, Library::Library(string name, string libraryInfo, string header, string componentDirectory,
vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses, vector<Connection> connections, map<string, string> messages) std::optional<std::string> componentHeader,
: name(name), libraryInfo(libraryInfo), header(header), componentDirectory(componentDirectory), componentHeader(componentHeader), addressSpaces(addressSpaces), vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses,
components(components), buses(buses), connections(connections), messages(messages) vector<Connection> connections, map<string, string> messages)
{} : name(name), libraryInfo(libraryInfo), header(header), componentDirectory(componentDirectory),
componentHeader(componentHeader), addressSpaces(addressSpaces),
components(components), buses(buses), connections(connections), messages(messages) {}
std::string Library::getName() { std::string Library::getName() {
return name; return name;
} }
std::string Library::getLibraryInfo() { std::string Library::getLibraryInfo() {
return libraryInfo; return libraryInfo;
} }
std::string Library::getHeader() { std::string Library::getHeader() {
return header; return header;
} }
std::string Library::getComponentDirectory() { std::string Library::getComponentDirectory() {
return componentDirectory; return componentDirectory;
} }
std::optional<std::string> Library::getComponentHeader() { std::optional<std::string> Library::getComponentHeader() {
return componentHeader; return componentHeader;
} }
@ -27,12 +34,15 @@ std::optional<std::string> Library::getComponentHeader() {
std::vector<AddressSpace> Library::getAddressSpaces() { std::vector<AddressSpace> Library::getAddressSpaces() {
return addressSpaces; return addressSpaces;
} }
std::vector<Component> Library::getComponents() { std::vector<Component> Library::getComponents() {
return components; return components;
} }
std::vector<Bus> Library::getBuses() { std::vector<Bus> Library::getBuses() {
return buses; return buses;
} }
std::vector<Connection> Library::getConnections() { std::vector<Connection> Library::getConnections() {
return connections; return connections;
} }
@ -42,15 +52,16 @@ std::map<std::string, std::string> Library::getMessages() {
} }
bool Library::hasComponent(std::string name) { bool Library::hasComponent(std::string name) {
for(uint i=0; i<components.size(); i++) { for (unsigned int i = 0; i < components.size(); i++) {
if (components[i].getName() == name) { if (components[i].getName() == name) {
return true; return true;
} }
} }
return false; return false;
} }
bool Library::hasBus(std::string name) { bool Library::hasBus(std::string name) {
for(uint i=0; i<buses.size(); i++) { for (unsigned int i = 0; i < buses.size(); i++) {
if (buses[i].getName() == name) { if (buses[i].getName() == name) {
return true; return true;
} }
@ -60,36 +71,39 @@ bool Library::hasBus(std::string name) {
AddressSpace &Library::getAddressSpace(std::string addressSpace) { AddressSpace &Library::getAddressSpace(std::string addressSpace) {
for(uint i=0; i<addressSpaces.size(); i++) { for (unsigned int i = 0; i < addressSpaces.size(); i++) {
if (addressSpaces[i].getName() == addressSpace) { if (addressSpaces[i].getName() == addressSpace) {
return addressSpaces[i]; return addressSpaces[i];
} }
} }
throw std::exception(); throw std::runtime_error("no address space with name '" + addressSpace + "'");
} }
Component &Library::getComponent(std::string component) { Component &Library::getComponent(std::string component) {
for(uint i=0; i<components.size(); i++) { for (unsigned int i = 0; i < components.size(); i++) {
if (components[i].getName() == component) { if (components[i].getName() == component) {
return components[i]; return components[i];
} }
} }
throw std::exception(); throw std::runtime_error("no component with name '" + component + "'");
} }
Bus &Library::getBus(std::string bus) { Bus &Library::getBus(std::string bus) {
for(uint i=0; i<buses.size(); i++) { for (unsigned int i = 0; i < buses.size(); i++) {
if (buses[i].getName() == bus) { if (buses[i].getName() == bus) {
return buses[i]; return buses[i];
} }
} }
throw std::exception(); throw std::runtime_error("no bus with name '" + bus + "'");
} }
bool Library::hasConnection(ConnectionComponent component, std::string bus) { bool Library::hasConnection(ConnectionComponent component, std::string bus) {
return getConnection(component, bus).has_value(); return getConnection(component, bus).has_value();
} }
std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus) { std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus) {
for(uint i=0; i<connections.size(); i++) { for (unsigned int i = 0; i < connections.size(); i++) {
if (connections[i].isConnecting(component, bus)) { if (connections[i].isConnecting(component, bus)) {
return connections[i]; return connections[i];
} }
@ -100,8 +114,10 @@ std::optional<Connection> Library::getConnection(ConnectionComponent component,
bool Library::hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { bool Library::hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) {
return getConnection(component, bus, secondComponent).has_value(); return getConnection(component, bus, secondComponent).has_value();
} }
std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) {
for(uint i=0; i<connections.size(); i++) { std::optional<Connection>
Library::getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) {
for (unsigned int i = 0; i < connections.size(); i++) {
if (connections[i].isConnecting(component, bus, secondComponent)) { if (connections[i].isConnecting(component, bus, secondComponent)) {
return connections[i]; return connections[i];
} }

View File

@ -1,7 +1,7 @@
#ifndef DOMAIN_LIBRARY_H #ifndef DOMAIN_LIBRARY_H
#define DOMAIN_LIBRARY_H #define DOMAIN_LIBRARY_H
#include "addressspace.h" #include "address_space.h"
#include "bus.h" #include "bus.h"
#include "component.h" #include "component.h"
#include "connection.h" #include "connection.h"
@ -10,13 +10,11 @@
#include <vector> #include <vector>
namespace domain { namespace domain {
using namespace std; using namespace std;
class Library class Library {
{
std::string name; std::string name;
std::string libraryInfo; std::string libraryInfo;
std::string header; std::string header;
@ -31,37 +29,53 @@ class Library
std::map<std::string, std::string> messages; std::map<std::string, std::string> messages;
public: public:
Library(string name, string libraryInfo, string header, string componentDirectory, std::optional<string> componentHeader, Library(string name, string libraryInfo, string header, string componentDirectory,
vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses, vector<Connection> connection, map<string, string> messages); std::optional<string> componentHeader,
vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses,
vector<Connection> connection, map<string, string> messages);
std::string getName(); std::string getName();
std::string getLibraryInfo(); std::string getLibraryInfo();
std::string getHeader(); std::string getHeader();
std::string getComponentDirectory(); std::string getComponentDirectory();
std::optional<std::string> getComponentHeader(); std::optional<std::string> getComponentHeader();
std::vector<AddressSpace> getAddressSpaces(); std::vector<AddressSpace> getAddressSpaces();
std::vector<Component> getComponents(); std::vector<Component> getComponents();
std::vector<Bus> getBuses(); std::vector<Bus> getBuses();
std::vector<Connection> getConnections(); std::vector<Connection> getConnections();
bool hasComponent(std::string name); bool hasComponent(std::string name);
bool hasBus(std::string name); bool hasBus(std::string name);
std::map<std::string, std::string> getMessages(); std::map<std::string, std::string> getMessages();
AddressSpace &getAddressSpace(std::string name); AddressSpace &getAddressSpace(std::string name);
Component &getComponent(std::string name); Component &getComponent(std::string name);
Bus &getBus(std::string bus); Bus &getBus(std::string bus);
std::string getMessage(std::string key); std::string getMessage(std::string key);
bool hasConnection(ConnectionComponent component, std::string bus); bool hasConnection(ConnectionComponent component, std::string bus);
std::optional<Connection> getConnection(ConnectionComponent component, std::string bus); std::optional<Connection> getConnection(ConnectionComponent component, std::string bus);
bool hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent); bool hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent);
std::optional<Connection> getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent); std::optional<Connection> getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent);
bool hasConnection(ConnectionComponent component, ConnectionComponent secondComponent); bool hasConnection(ConnectionComponent component, ConnectionComponent secondComponent);
std::optional<Connection> getConnection(ConnectionComponent component, ConnectionComponent secondComponent); std::optional<Connection> getConnection(ConnectionComponent component, ConnectionComponent secondComponent);
}; };

View File

@ -2,37 +2,30 @@
namespace domain { namespace domain {
PinConnection::PinConnection(std::string message, ConnectionType type) Pin::Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin,
: message(message), type(type) std::optional<std::vector<Value>> wires)
{} : name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires) {}
PinConnection::ConnectionType PinConnection::getType() {
return type;
}
std::string PinConnection::getMessage() {
return message;
}
Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin, std::optional<std::vector<Value>> wires)
: name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires)
{}
std::string &Pin::getName() { std::string &Pin::getName() {
return name; return name;
} }
Pin::PinType Pin::getType() { Pin::PinType Pin::getType() {
return type; return type;
} }
std::string Pin::getTooltip() { std::string Pin::getTooltip() {
return tooltip; return tooltip;
} }
ui::Pin &Pin::getDisplayPin() { ui::Pin &Pin::getDisplayPin() {
return displayPin; return displayPin;
} }
PinConnection &Pin::getConnection() {
std::optional<std::string> Pin::getConnection() {
return connection; return connection;
} }
std::optional<std::vector<Value>> &Pin::getWires() { std::optional<std::vector<Value>> &Pin::getWires() {
return wires; return wires;
} }

View File

@ -7,30 +7,9 @@
#include <string> #include <string>
namespace domain { namespace domain {
class PinConnection class Pin {
{
public:
enum ConnectionType {
REQUIRED,
OPTIONAL
};
private:
std::string message;
ConnectionType type;
public:
PinConnection(std::string message, ConnectionType type);
ConnectionType getType();
std::string getMessage();
};
class Pin
{
public: public:
enum PinType { enum PinType {
IN_OUT, IN_OUT,
@ -42,19 +21,25 @@ private:
std::string name; std::string name;
PinType type; PinType type;
std::string tooltip; std::string tooltip;
PinConnection connection; std::optional<std::string> connection;
domain::ui::Pin displayPin; domain::ui::Pin displayPin;
std::optional<std::vector<Value>> wires; std::optional<std::vector<Value>> wires;
public: public:
Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin, std::optional<std::vector<Value>> wires); Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin,
std::optional<std::vector<Value>> wires);
std::string &getName(); std::string &getName();
PinType getType(); PinType getType();
std::string getTooltip(); std::string getTooltip();
ui::Pin &getDisplayPin(); ui::Pin &getDisplayPin();
PinConnection &getConnection();
std::optional<std::string> getConnection();
std::optional<std::vector<Value>> &getWires(); std::optional<std::vector<Value>> &getWires();
}; };

View File

@ -1,20 +1,21 @@
#include "rule.h" #include "rule.h"
#include <utility>
namespace domain { namespace domain {
Condition::Condition(std::string function, std::vector<Value> params, bool negated) Condition::Condition(std::string function, std::vector<Value> params, bool negated)
: negated(negated), function(function), params(params) : negated(negated), function(std::move(function)), params(std::move(params)) {}
{}
bool Condition::evaluate(RuleContext &context) { bool Condition::evaluate(RuleContext &context) {
std::vector<Value> request; std::vector<Value> request;
for(unsigned int i=0; i<params.size(); i++) { for (auto & param : params) {
if(params[i].isType(Value::ADDRESS_SPACE_REFERENCE)) { if (param.isType(Value::ADDRESS_SPACE_REFERENCE)) {
request.push_back(Value::fromAddressSpace(context.addressSpaces.at(params[i].asReference()))); request.push_back(Value::fromAddressSpace(context.addressSpaces.at(param.asReference())));
} else if(params[i].isType(Value::ATTRIBUTE_REFERENCE)) { } else if (param.isType(Value::ATTRIBUTE_REFERENCE)) {
request.push_back(context.attributes[params[i].asReference()]); request.push_back(context.attributes[param.asReference()]);
} else { } else {
request.push_back(params[i]); request.push_back(param);
} }
} }
bool result = context.function[function]->validate(request); bool result = context.function[function]->validate(request);
@ -23,20 +24,19 @@ bool Condition::evaluate(RuleContext &context) {
Action::Action(ActionType type, std::string message) Action::Action(ActionType type, std::string message)
: type(type), message(message) : type(type), message(std::move(message)) {}
{}
Action::ActionType Action::getType() { Action::ActionType Action::getType() {
return type; return type;
} }
std::string Action::getMessage() { std::string Action::getMessage() {
return message; return message;
} }
IfStatement::IfStatement(Condition condition, Action action) IfStatement::IfStatement(Condition condition, Action action)
: condition(condition), action(action) : condition(std::move(condition)), action(std::move(action)) {}
{}
std::optional<Action> IfStatement::evaluate(RuleContext &context) { std::optional<Action> IfStatement::evaluate(RuleContext &context) {
if (condition.evaluate(context)) { if (condition.evaluate(context)) {
@ -46,12 +46,11 @@ std::optional<Action> IfStatement::evaluate(RuleContext &context) {
} }
Rule::Rule(std::vector<IfStatement> statements) Rule::Rule(std::vector<IfStatement> statements)
: statements(statements) : statements(std::move(statements)) {}
{}
std::optional<Action> Rule::evaluate(RuleContext &context) { std::optional<Action> Rule::evaluate(RuleContext &context) {
for(unsigned int i=0; i<statements.size(); i++) { for (auto & statement : statements) {
auto response = statements[i].evaluate(context); auto response = statement.evaluate(context);
if (response) { if (response) {
return response; return response;
} }

View File

@ -1,9 +1,9 @@
#ifndef DOMAIN_RULE_H #ifndef DOMAIN_RULE_H
#define DOMAIN_RULE_H #define DOMAIN_RULE_H
#include "addressspace.h" #include "address_space.h"
#include "value.h" #include "value.h"
#include "functionsignature.h" #include "function_signature.h"
#include <map> #include <map>
#include <string> #include <string>
@ -44,6 +44,7 @@ public:
Action(ActionType type, std::string message); Action(ActionType type, std::string message);
ActionType getType(); ActionType getType();
std::string getMessage(); std::string getMessage();
}; };
@ -56,11 +57,10 @@ public:
std::optional<Action> evaluate(RuleContext &context); std::optional<Action> evaluate(RuleContext &context);
}; };
class Rule class Rule {
{
std::vector<IfStatement> statements; std::vector<IfStatement> statements;
public: public:
Rule(std::vector<IfStatement> statements); explicit Rule(std::vector<IfStatement> statements);
std::optional<Action> evaluate(RuleContext &context); std::optional<Action> evaluate(RuleContext &context);
}; };

View File

@ -2,27 +2,114 @@
namespace domain { namespace domain {
Schema::Schema()
{
}
bool Schema::hasConnection(string &component, string &pin) { bool Schema::hasConnection(string &component, string &pin) {
return getConnection(component, pin) != nullptr; return getConnection(component, pin) != nullptr;
} }
ConnectionInstance *Schema::getConnection(string &component, string &pin) { ConnectionInstance *Schema::getConnection(string &component, string &pin) {
auto pinConnections = getConnections(component, pin);
if(pinConnections.empty()) {
return nullptr;
} else {
return pinConnections[0];
}
}
std::vector<ConnectionInstance*> Schema::getConnections(string &component, string &pin) {
std::vector<ConnectionInstance*> pinConnections;
for (auto &conn: connections) { for (auto &conn: connections) {
if (conn->instance->name == component && conn->connection.getComponent().pin == pin) { if (conn->instance->name == component && conn->connection.getComponent().pin == pin) {
return conn.get(); pinConnections.push_back(conn.get());
} }
auto dirConn = dynamic_cast<DirectConnectionInstance *>(conn.get()); auto dirConn = dynamic_cast<DirectConnectionInstance *>(conn.get());
if (dirConn != nullptr) { if (dirConn != nullptr) {
if (dirConn->secondInstance->name == component && conn->connection.getSecondComponent()->pin == pin) { if (dirConn->secondInstance->name == component && conn->connection.getSecondComponent()->pin == pin) {
return dirConn; pinConnections.push_back(conn.get());
} }
} }
} }
return pinConnections;
}
BusInstance *Schema::getBusInstance(string &name) {
for (auto &instance: busInstances) {
if (instance->name == name) {
return instance.get();
}
}
return nullptr; return nullptr;
} }
ComponentInstance *Schema::getComponentInstance(string &name) {
for (auto &instance: componentInstances) {
if (instance->name == name) {
return instance.get();
}
}
return nullptr;
}
std::vector<ConnectionEntry> Schema::availableConnections(std::string instanceName, std::string pinName, bool onlyConnectable) {
std::vector<ConnectionEntry> entries;
auto instance = getComponentInstance(instanceName);
ConnectionComponent connectionComponent{instance->component.getName(), pinName};
for(auto &conn: library.getConnections()) {
if(conn.isConnecting(connectionComponent)) {
if(library.getBus(conn.getBus()).getType() == Bus::REGULAR) {
for(auto& bus: busInstances) {
if(bus->bus.getName() == conn.getBus()) {
entries.push_back({ConnectionEntry::BUS, bus.get(), nullopt, nullopt, conn});
}
}
} else {
for(auto& component: componentInstances) {
for(auto& pin: component->component.getPins()) {
if(conn.isConnecting(connectionComponent, {component->component.getName(), pin.getName()})) {
ConnectionEntry entry{ConnectionEntry::COMPONENT, nullopt, component.get(), pin, conn};
entries.emplace_back(entry);
}
}
}
}
}
}
if(onlyConnectable) {
entries.erase(
std::remove_if(
entries.begin(),
entries.end(),
[this, instance](ConnectionEntry &entry) {
auto& bus = this->library.getBus(entry.connection.getBus());
// we allow duplicates of single automatic connections
if(bus.getType() == Bus::SINGLE_AUTOMATIC) {
return false;
}
for(auto& conn: this->connections) {
if(conn->connection == entry.connection) {
if(bus.getType() == Bus::REGULAR) {
auto busConnection = dynamic_cast<BusConnectionInstance*>(conn.get());
if(busConnection->instance == instance && busConnection->bus == entry.busInstance.value()) {
return true;
}
} else {
auto directConnection = dynamic_cast<DirectConnectionInstance*>(conn.get());
if(directConnection->instance == instance && directConnection->secondInstance == entry.componentInstance.value() ||
directConnection->secondInstance == instance && directConnection->instance == entry.componentInstance.value()) {
return true;
}
}
}
}
return false;
}),
entries.end()
);
}
return entries;
}
} // namespace domain } // namespace domain

View File

@ -1,44 +1,49 @@
#ifndef DOMAIN_SCHEMA_H #ifndef DOMAIN_SCHEMA_H
#define DOMAIN_SCHEMA_H #define DOMAIN_SCHEMA_H
#include "connectioninstance.h" #include "connection_instance.h"
#include "instance.h" #include "instance.h"
#include "wireinstance.h" #include "library.h"
#include <utility>
#include <vector> #include <vector>
namespace domain { namespace domain {
struct ConnectionEntry {
enum Type {
BUS,
COMPONENT
};
Type type;
std::optional<BusInstance*> busInstance;
std::optional<ComponentInstance*> componentInstance;
std::optional<Pin> pin;
Connection connection;
};
class Schema { class Schema {
private:
Library library;
public: public:
Schema(); Schema(Library library): library(std::move(library)) {}
std::vector<shared_ptr<BusInstance>> busInstances; std::vector<shared_ptr<BusInstance>> busInstances;
std::vector<shared_ptr<ComponentInstance>> componentInstances; std::vector<shared_ptr<ComponentInstance>> componentInstances;
std::vector<shared_ptr<ConnectionInstance>> connections; std::vector<shared_ptr<ConnectionInstance>> connections;
BusInstance *getBusInstance(std::string &name) { BusInstance *getBusInstance(std::string &name);
for (auto &instance: busInstances) { ComponentInstance *getComponentInstance(std::string &name);
if (instance->name == name) {
return instance.get();
}
}
return nullptr;
}
ComponentInstance *getComponentInstance(std::string &name) {
for (auto &instance: componentInstances) {
if (instance->name == name) {
return instance.get();
}
}
return nullptr;
}
bool hasConnection(string &component, string &pin); bool hasConnection(string &component, string &pin);
ConnectionInstance *getConnection(string &component, string &pin); ConnectionInstance *getConnection(string &component, string &pin);
std::vector<ConnectionEntry> availableConnections(std::string instance, std::string pin, bool onlyConnectable);
vector<ConnectionInstance *> getConnections(string &component, string &pin);
}; };
} // namespace domain } // namespace domain

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,92 @@
#ifndef DOMAIN_COMDEL_GENERATOR_H
#define DOMAIN_COMDEL_GENERATOR_H
#include "library.h"
#include "schema.h"
#include <set>
#include <utility>
#include <comdel/parser/ast_nodes.h>
#include <comdel/parser/parse_context.h>
#include <comdel/parser/presult.h>
namespace domain {
/** Context used for loading model */
struct ComdelContext {
std::vector<Attribute> attributes;
std::vector<std::string> wires;
std::string name;
bool inComponent;
bool inConnection;
bool inSingleAutomaticConnection;
ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection);
bool doesAttributeExists(std::string name, Value::ValueType type);
bool doesWireExists(std::string name);
};
class SchemaCreator {
public:
explicit SchemaCreator(std::vector<FunctionValidator *> validators);
std::vector<SourceError> getErrors();
std::optional<Library> loadLibrary(LibraryNode node);
Schema *loadSchema(SchemaNode node, Library &library);
private:
std::vector<ComdelContext> context;
std::string name;
std::string libraryInfo;
std::string header;
std::string componentDirectory;
std::optional<std::string> componentHeader = nullopt;
std::vector<AddressSpace> addressSpaces;
std::vector<Component> components;
std::vector<Bus> buses;
std::vector<Connection> connections;
std::map<std::string, std::string> messages;
std::vector<SourceError> errors;
std::vector<FunctionValidator *> validators;
std::optional<AddressSpace> loadAddressSpace(AddressSpaceNode node);
std::optional<Component> loadComponent(ComponentNode node);
std::optional<Attribute> loadAttribute(AttributeNode node);
std::optional<Rule> loadRule(RuleNode node);
std::optional<Condition> loadCondition(ConditionNode node);
std::optional<Popup> loadPopup(PopupNode node, std::string name, Value::ValueType type);
std::optional<Display> loadDisplay(DisplayNode node);
std::optional<Wire> loadWire(WireNode node);
std::optional<Pin> loadPin(PinNode pins);
std::optional<Connection> loadConnection(ConnectionNode node);
std::optional<Bus> loadBus(BusNode node);
std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library);
std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library);
/** Utility classes */
std::optional<Bus> getBus(std::string name);
std::optional<Pin> getComponentPin(std::string name, std::string pin);
bool hasAddressSpace(std::string name);
std::optional<Attribute> createMemoryAttribute();
vector<Enumeration> createWireEnumeration(vector<Value> enumeration);
std::optional<Popup> createMemoryPopup();
/** Context stack operations */
void push(ComdelContext context);
void pushAdditional(std::string name);
ComdelContext &current();
void pop();
};
} // namespace domain
#endif // DOMAIN_COMDEL_GENERATOR_H

File diff suppressed because it is too large Load Diff

View File

@ -1,153 +0,0 @@
#ifndef DOMAIN_COMDEL_GENERATOR_H
#define DOMAIN_COMDEL_GENERATOR_H
#include "library.h"
#include "schema.h"
#include <set>
#include <comdel/parser/astnode.h>
#include <comdel/parser/parsecontext.h>
#include <comdel/parser/presult.h>
namespace domain {
struct ComdelContext {
std::vector<Attribute> attributes;
std::vector<std::string> wires;
std::string name;
bool inComponent;
bool inConnection;
bool inSingleAutomaticConnection;
bool inBus;
ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus)
: name(name), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection), inBus(inBus)
{}
bool doesAttributeExists(std::string name, Value::ValueType type) {
for(auto &attribute: attributes) {
if(attribute.getDefault().getType() == type && attribute.getName() == name) {
return true;
}
}
return false;
}
bool doesWireExists(std::string name) {
for(auto &w: wires) {
if(w == name) {
return true;
}
}
return false;
}
};
class SchemaCreator
{
std::vector<ComdelContext> context;
std::string name;
std::string libraryInfo;
std::string header;
std::string componentDirectory;
std::optional<std::string> componentHeader = nullopt;
std::vector<AddressSpace> addressSpaces;
std::vector<Component> components;
std::vector<Bus> buses;
std::vector<Connection> connections;
std::map<std::string, std::string> messages;
std::vector<SourceError> errors;
std::vector<FunctionValidator*> validators;
std::optional<AddressSpace> loadAddressSpace(AddressSpaceNode node);
std::optional<Component> loadComponent(ComponentNode node);
std::optional<Attribute> loadAttribute(AttributeNode node);
std::optional<Rule> loadRule(RuleNode node);
std::optional<Condition> loadCondition(ConditionNode node);
std::optional<Popup> loadPopup(PopupNode node, std::string name, Value::ValueType type);
std::optional<Display> loadDisplay(DisplayNode node);
std::optional<Wire> loadWire(WireNode node);
std::optional<Pin> loadPin(PinNode pins);
PinConnection loadPinConnection(PinConnectionNode node);
std::optional<Connection> loadConnection(ConnectionNode node);
std::optional<Bus> loadBus(BusNode node);
std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library);
std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library);
std::optional<Attribute> createMemoryAttribute();
std::optional<Bus> getBus(std::string name) {
for(auto &bus: buses) {
if(bus.getName() == name) {
return bus;
}
}
return std::nullopt;
}
std::optional<Pin> getComponentPin(std::string name, std::string pin) {
for(auto &c: components) {
if(c.getName() == name) {
for(auto &p: c.getPins()) {
if(p.getName() == pin) {
return p;
}
}
}
}
return nullopt;
}
bool hasAddressSpace(std::string name) {
for(auto &as: addressSpaces) {
if(as.getName() == name) {
return true;
}
}
return false;
}
void push(ComdelContext context) {
this->context.push_back(context);
}
void pushAdditional(std::string name) {
if(!this->context.empty()) {
this->context.push_back(current());
current().name = name;
} else {
ComdelContext con(name, false, false, false, false);
push(con);
}
}
ComdelContext &current() {
return this->context[this->context.size() - 1];
}
void pop() {
this->context.pop_back();
}
public:
SchemaCreator(std::vector<FunctionValidator*> validators);
std::vector<SourceError> getErrors() {
return errors;
}
std::optional<Library> loadLibrary(LibraryNode node);
Schema* loadSchema(SchemaNode node, Library &library);
vector <Enumeration> createWireEnumeration(vector<Value> vector1);
std::optional<Popup> createMemoryPopup();
};
} // namespace domain
#endif // DOMAIN_COMDEL_GENERATOR_H

View File

@ -1,6 +1,7 @@
#include "value.h" #include "value.h"
#include <string> #include <string>
#include <stdexcept>
namespace domain { namespace domain {
@ -24,6 +25,12 @@ std::string Value::string() {
return "AddressSpace::" + reference; return "AddressSpace::" + reference;
case ATTRIBUTE_REFERENCE: case ATTRIBUTE_REFERENCE:
return "Attribute::" + reference; return "Attribute::" + reference;
case MEMORY_REFERENCE:
if (memoryReference.has_value()) {
return "Memory::" + *memoryReference;
} else {
return "Memory::null";
}
default: default:
return "unknown"; return "unknown";
} }
@ -33,41 +40,72 @@ std::string Value::string() {
Value::ValueType Value::getType() { Value::ValueType Value::getType() {
return type; return type;
} }
bool Value::isType(Value::ValueType type) {
return this->type == type; bool Value::isType(Value::ValueType _type) {
return type == _type;
}
std::string Value::getTypename() {
switch (type) {
case Value::BOOL:
return "bool";
case Value::INT:
return "int";
case Value::STRING:
return "string";
case Value::ADDRESS_SPACE:
case Value::ADDRESS_SPACE_REFERENCE:
return "address space";
case Value::WIRE_REFERENCE:
return "wire reference";
case Value::ATTRIBUTE_REFERENCE:
return "attribute";
case Value::NIL:
return "null";
case Value::MEMORY:
case Value::MEMORY_REFERENCE:
return "memory";
case Value::UNDEFINED:
return "undefined";
}
return "unknown";
} }
long long Value::asInt() { long long Value::asInt() {
if (isType(Value::INT)) { if (isType(Value::INT)) {
return intValue; return intValue;
} }
throw std::exception(); throw std::runtime_error("expected 'int' but value contains '" + getTypename() + "'");
} }
std::string Value::asString() { std::string Value::asString() {
if (isType(Value::STRING)) { if (isType(Value::STRING)) {
return stringValue; return stringValue;
} }
throw std::exception(); throw std::runtime_error("expected 'string' but value contains '" + getTypename() + "'");
} }
bool Value::asBool() { bool Value::asBool() {
if (isType(Value::BOOL)) { if (isType(Value::BOOL)) {
return boolValue; return boolValue;
} }
throw std::exception(); throw std::runtime_error("expected 'bool' but value contains '" + getTypename() + "'");
} }
AddressSpace Value::asAddressSpace() { AddressSpace Value::asAddressSpace() {
if (isType(Value::ADDRESS_SPACE)) { if (isType(Value::ADDRESS_SPACE)) {
return *addressSpace; return *addressSpace;
} }
throw std::exception(); throw std::runtime_error("expected 'address space' but value contains '" + getTypename() + "'");
}
std::string Value::asReference() {
if(isType(Value::WIRE_REFERENCE) || isType(Value::ADDRESS_SPACE_REFERENCE) || isType(Value::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) {
return reference;
}
throw std::exception();
} }
std::string Value::asReference() {
if (isType(Value::WIRE_REFERENCE) || isType(Value::ADDRESS_SPACE_REFERENCE) ||
isType(Value::ATTRIBUTE_REFERENCE) || isType(Value::UNDEFINED)) {
return reference;
}
throw std::runtime_error("expected 'reference' but value contains '" + getTypename() + "'");
}
std::optional<std::string> Value::asMemoryReference() { std::optional<std::string> Value::asMemoryReference() {
return memoryReference; return memoryReference;
@ -81,26 +119,33 @@ std::optional<std::string> Value::asMemoryReference() {
void Value::setInt(long long value) { void Value::setInt(long long value) {
if (isType(Value::INT)) { if (isType(Value::INT)) {
this->intValue = value; this->intValue = value;
} else {
throw std::runtime_error("expected to set 'int' but value contains '" + getTypename() + "'");
} }
throw std::exception();
} }
void Value::setString(std::string value) { void Value::setString(std::string value) {
if (isType(Value::STRING)) { if (isType(Value::STRING)) {
this->stringValue = value; this->stringValue = value;
} else {
throw std::runtime_error("expected to set 'string' but value contains '" + getTypename() + "'");
} }
throw std::exception();
} }
void Value::setBool(bool value) { void Value::setBool(bool value) {
if (isType(Value::BOOL)) { if (isType(Value::BOOL)) {
this->boolValue = value; this->boolValue = value;
} else {
throw std::runtime_error("expected to set 'bool' but value contains '" + getTypename() + "'");
} }
throw std::exception();
} }
void Value::setReference(std::string value) { void Value::setReference(std::string value) {
if (isType(Value::WIRE_REFERENCE)) { if (isType(Value::WIRE_REFERENCE)) {
this->reference = value; this->reference = value;
} else {
throw std::runtime_error("expected to set 'wire' but value contains '" + getTypename() + "'");
} }
throw std::exception();
} }
@ -110,24 +155,28 @@ Value Value::fromInt(long long value) {
val.intValue = value; val.intValue = value;
return val; return val;
} }
Value Value::fromString(std::string value) { Value Value::fromString(std::string value) {
Value val; Value val;
val.type = Value::STRING; val.type = Value::STRING;
val.stringValue = value; val.stringValue = value;
return val; return val;
} }
Value Value::fromBool(bool value) { Value Value::fromBool(bool value) {
Value val; Value val;
val.type = Value::BOOL; val.type = Value::BOOL;
val.boolValue = value; val.boolValue = value;
return val; return val;
} }
Value Value::fromAddressSpace(AddressSpace addressSpace) { Value Value::fromAddressSpace(AddressSpace addressSpace) {
Value val; Value val;
val.type = Value::ADDRESS_SPACE; val.type = Value::ADDRESS_SPACE;
val.addressSpace = addressSpace; val.addressSpace = addressSpace;
return val; return val;
} }
Value Value::fromReference(std::string value, Value::ValueType type) { Value Value::fromReference(std::string value, Value::ValueType type) {
Value val; Value val;
val.type = type; val.type = type;
@ -135,18 +184,19 @@ Value Value::fromReference(std::string value, Value::ValueType type) {
return val; return val;
} }
Value Value::ofType(Value::ValueType type) {
Value val;
val.type = type;
return val;
}
Value Value::fromNull() { Value Value::fromNull() {
Value val; Value val;
val.type = Value::NIL; val.type = Value::NIL;
return val; return val;
} }
Value Value::fromMemoryReference(std::optional<std::string> value) {
Value val;
val.type = MEMORY_REFERENCE;
val.memoryReference = value;
return val;
}
std::string Value::stringify() { std::string Value::stringify() {
switch (type) { switch (type) {
case INT: case INT:
@ -168,22 +218,41 @@ std::string Value::stringify() {
return "null"; return "null";
} }
default: default:
throw std::exception(); throw std::runtime_error("unknown type couldn't stringify '" + getTypename() + "'");
} }
} }
Value Value::fromMemoryReference(std::optional<std::string> value) { Value Value::ofType(Value::ValueType type) {
Value val; Value val;
val.type = MEMORY_REFERENCE; val.type = type;
val.memoryReference = value;
return val; return val;
} }
Value Value::fromMemory(domain::ComponentInstance *memory) { bool Value::equals(Value value) {
Value val; if (value.getType() == type) {
val.type = MEMORY; switch (type) {
val.memory = memory; case INT:
return val; return value.asInt() == intValue;
case STRING:
return value.asString() == stringValue;
case NIL:
case UNDEFINED:
return true;
case WIRE_REFERENCE:
case ATTRIBUTE_REFERENCE:
case ADDRESS_SPACE_REFERENCE:
return value.asReference() == reference;
case MEMORY_REFERENCE:
return value.asMemoryReference() == memoryReference;
case MEMORY:
return value.asMemory() == memory;
case BOOL:
return value.asBool() == boolValue;
default:
return false;
}
}
return false;
} }
} // namespace domain } // namespace domain

View File

@ -1,7 +1,7 @@
#ifndef DOMAIN_VALUE_H #ifndef DOMAIN_VALUE_H
#define DOMAIN_VALUE_H #define DOMAIN_VALUE_H
#include "addressspace.h" #include "address_space.h"
#include <string> #include <string>
#include <optional> #include <optional>
@ -11,8 +11,7 @@ namespace domain {
class ComponentInstance; class ComponentInstance;
class Value class Value {
{
public: public:
enum ValueType { enum ValueType {
INT, INT,
@ -42,64 +41,56 @@ private:
public: public:
Value() {} Value() = default;
bool equals(Value value) { bool equals(Value value);
if(value.getType() == type) {
switch (type) {
case INT:
return value.asInt() == intValue;
case STRING:
return value.asString() == stringValue;
case NIL:
case UNDEFINED:
return true;
case WIRE_REFERENCE:
case ATTRIBUTE_REFERENCE:
case ADDRESS_SPACE_REFERENCE:
return value.asReference() == reference;
case MEMORY_REFERENCE:
return value.asMemoryReference() == memoryReference;
case MEMORY:
return value.asMemory() == memory;
case BOOL:
return value.asBool() == boolValue;
default:
return false;
}
}
return false;
}
std::string string(); std::string string();
std::string getTypename();
ValueType getType(); ValueType getType();
bool isType(ValueType type); bool isType(ValueType type);
long long asInt(); long long asInt();
std::string asString(); std::string asString();
bool asBool(); bool asBool();
std::string asReference(); std::string asReference();
std::optional<std::string> asMemoryReference(); std::optional<std::string> asMemoryReference();
domain::ComponentInstance *asMemory(); domain::ComponentInstance *asMemory();
AddressSpace asAddressSpace(); AddressSpace asAddressSpace();
void setInt(long long intValue); void setInt(long long intValue);
void setString(std::string value); void setString(std::string value);
void setBool(bool value); void setBool(bool value);
void setReference(std::string value); void setReference(std::string value);
std::string stringify(); std::string stringify();
static Value fromInt(long long value); static Value fromInt(long long value);
static Value fromString(std::string value); static Value fromString(std::string value);
static Value fromBool(bool value); static Value fromBool(bool value);
static Value fromNull(); static Value fromNull();
static Value fromAddressSpace(AddressSpace addressSpace); static Value fromAddressSpace(AddressSpace addressSpace);
static Value fromReference(std::string value, ValueType type); static Value fromReference(std::string value, ValueType type);
static Value ofType(ValueType type);
static Value fromMemoryReference(std::optional<std::string> memoryReference); static Value fromMemoryReference(std::optional<std::string> memoryReference);
static Value fromMemory(domain::ComponentInstance *memory);
static Value ofType(ValueType type);
}; };
} // namespace domain } // namespace domain

View File

@ -1,10 +0,0 @@
#include "wireinstance.h"
namespace domain {
WireInstance::WireInstance(std::string name, Display display, std::pair<int, int> position)
: name(name), display(display), position(position)
{}
} // namespace domain

View File

@ -1,24 +0,0 @@
#ifndef DOMAIN_WIRE_INSTANCE_H
#define DOMAIN_WIRE_INSTANCE_H
#include "display.h"
#include <string>
namespace domain {
class WireInstance
{
public:
std::string name;
Display display;
std::pair<int, int> position;
WireInstance(std::string name, Display display, std::pair<int, int> position);
};
} // namespace domain
#endif // DOMAIN_WIREINSTANCE_H

172
comdel/parser/ast_nodes.cpp Normal file
View File

@ -0,0 +1,172 @@
#include "ast_nodes.h"
/*************************** NUMBER NODE ********************************/
NumberNode::NumberNode(const std::string &expression) {
if (expression.size() > 2) {
if (expression.substr(0, 2) == "0x") {
this->value = std::stoll(expression, nullptr, 16);
} else if (expression.substr(0, 2) == "0b") {
this->value = std::stoll(expression, nullptr, 2);
} else {
this->value = std::stoll(expression, nullptr, 10);
}
} else {
this->value = std::stoll(expression, nullptr, 10);
}
}
/*************************** COLOR NODE *********************************/
ColorNode::ColorNode(const std::string &expression) {
auto value = expression.substr(1);
color.r = std::stoul(value.substr(0, 2), nullptr, 16);
color.g = std::stoul(value.substr(2, 4), nullptr, 16);
color.b = std::stoul(value.substr(4, 6), nullptr, 16);
color.a = 255;
if(value.length() == 8) {
color.a = std::stoul(value.substr(6,8), nullptr, 16);
}
}
/*************************** STRING NODE ********************************/
std::string StringNode::asString() {
return value.substr(1, value.length() - 2);
}
/*************************** VALUE NODE ********************************/
ValueNode::ValueType ValueNode::getType() const {
return type.value;
}
long long int ValueNode::asInt() {
if (is(INT)) {
return intValue.value();
}
return 0;
}
std::string ValueNode::asString() {
if (is(STRING)) {
return stringValue.value();
}
return "";
}
std::string ValueNode::asIdentifier() {
if (is(IDENTIFIER) || is(WIRE)) {
return identifierValue.value();
}
return "";
}
Color ValueNode::asColor() {
if (is(COLOR)) {
return colorValue.value();
}
return {};
}
bool ValueNode::asBool() {
if (is(BOOL)) {
return boolValue.value();
}
return false;
}
bool ValueNode::is(ValueNode::ValueType valueType) {
return type.value == valueType;
}
ValueNode ValueNode::ofBool(bool _value) {
ValueNode value;
value.type = EnumNode(BOOL);
value.boolValue = std::optional<bool>(_value);
return value;
}
ValueNode ValueNode::ofInt(long long int _value) {
ValueNode value;
value.type = EnumNode(INT);
value.intValue = std::optional<long long>(_value);
return value;
}
ValueNode ValueNode::ofString(std::string _value) {
ValueNode value;
value.type = EnumNode(STRING);
value.stringValue = std::optional<std::string>(_value);
return value;
}
ValueNode ValueNode::ofIdentifier(std::string _value) {
ValueNode value;
value.type = EnumNode(IDENTIFIER);
value.identifierValue = std::optional<std::string>(_value);
return value;
}
ValueNode ValueNode::ofNull() {
ValueNode value;
value.type = EnumNode(NIL);
return value;
}
ValueNode ValueNode::ofColor(Color color) {
ValueNode value;
value.type = EnumNode(COLOR);
value.colorValue = color;
return value;
}
ValueNode ValueNode::ofWire(std::optional<std::string> _value) {
ValueNode value;
value.type = EnumNode(WIRE);
value.identifierValue = _value;
return value;
}
ValueNode ValueNode::ofMemory(std::optional<std::string> _value) {
ValueNode value;
value.type = EnumNode(MEMORY);
value.identifierValue = _value;
return value;
}
/*************************** DisplayItem NODE ********************************/
std::optional<long long int> DisplayItemNode::asInt(const std::string &property, long long int _default) {
auto prop = getProperty(property);
if(prop.has_value()) {
return prop->value.is(ValueNode::INT) ? std::optional(prop->value.asInt()) : std::nullopt;
}
return _default;
}
std::optional<Color> DisplayItemNode::asColor(const std::string &property, Color _default) {
auto prop = getProperty(property);
if(prop.has_value()) {
return prop->value.is(ValueNode::COLOR) ? std::optional(prop->value.asColor()) : std::nullopt;
}
return _default;
}
std::optional<std::string> DisplayItemNode::asString(const std::string &property, std::string _default) {
auto prop = getProperty(property);
if(prop.has_value()) {
return prop->value.is(ValueNode::STRING) ? std::optional(prop->value.asString()) : std::nullopt;
}
return _default;
}
std::optional<PropertyNode> DisplayItemNode::getProperty(const std::string &property) {
for(auto &prop: values) {
if(prop.key.value == property) {
return prop;
}
}
return std::nullopt;
}

553
comdel/parser/ast_nodes.h Normal file
View File

@ -0,0 +1,553 @@
#ifndef AST_NODE_H
#define AST_NODE_H
#include "token.h"
#include "color.h"
#include "source_error.h"
#include <optional>
#include <utility>
#include <vector>
/*****************************************************************************
* BASE TYPES *
*****************************************************************************/
/**
* AST base class, all AST node classes extend this class. Class contains basic
* information about nodes location in file.
*/
class AstNode {
public:
/** Contains information about where in source file given node is located */
Span span;
AstNode() = default;
AstNode(AstNode &&) = default;
AstNode &operator=(AstNode &&) = default;
AstNode(const AstNode &) = default;
AstNode &operator=(const AstNode &) = default;
};
/**
* AST base enum class,
* Used to represent AST enums
* */
template<typename T>
struct EnumNode : public AstNode {
EnumNode() = default;
explicit EnumNode(T value) : value(value) {}
T value;
};
/** Represents string
* value contains quote-marks ("" or '' depending on string type)
* */
struct StringNode : public AstNode {
/** String including quote-marks*/
std::string value;
/** Returns string without quote-marks */
std::string asString();
};
/** Represents identifiers */
struct IdentifierNode : public AstNode {
std::string value;
};
/** Represents all numbers used
* All numbers must fit into long long int
* */
struct NumberNode : public AstNode {
long long int value = 0;
explicit NumberNode(const std::string &expression);
NumberNode() = default;
};
/** Represents color
* color comes in two formats #RRGGBB or #RRGGBBAA (AA representing opacity)
* */
struct ColorNode : public AstNode {
Color color;
explicit ColorNode(const std::string &expression);
ColorNode() = default;
};
/** Represents ordered number pair */
struct NumberPairNode : public AstNode {
NumberNode first;
NumberNode second;
NumberPairNode(NumberNode first, NumberNode second) : first(first), second(second) {}
NumberPairNode() = default;
};
/** Represents generic value
* Because attributes can contain different value types,
* this allows us to use one generic type for all attributes
* */
class ValueNode : public AstNode {
public:
enum ValueType {
/** Stores same content as NumberNode */
INT,
/** Stores same content as StringNode */
STRING,
/** Stores true or false */
BOOL,
/** Stores wire nam or null */
WIRE,
/** Default type assigned when node value is of type IdentifierNode and more correct type is assigned later */
IDENTIFIER,
/** Stores memory name or null */
MEMORY,
/** Stores null */
NIL,
/** Store same content as ColorNode */
COLOR,
};
private:
/** Type determines what is stored inside ValueNode */
EnumNode<ValueType> type = EnumNode(NIL);
/** All possible values for ValueNode are stored inside optionals */
std::optional<long long> intValue = std::nullopt;
std::optional<std::string> stringValue = std::nullopt;
std::optional<bool> boolValue = std::nullopt;
std::optional<std::string> identifierValue = std::nullopt;
std::optional<Color> colorValue = std::nullopt;
public:
ValueNode() = default;
ValueType getType() const;
/** Checks ValueNode is of requested type and returns it or returns default value for given type*/
long long int asInt();
std::string asString();
std::string asIdentifier();
Color asColor();
bool asBool();
/** Returns true if ValueNode is of given valueType */
bool is(ValueType valueType);
/** Static methods used to generate ValueNodes of requested type */
static ValueNode ofBool(bool _value);
static ValueNode ofInt(long long _value);
static ValueNode ofString(std::string _value);
static ValueNode ofIdentifier(std::string _value);
static ValueNode ofMemory(std::optional<std::string> _value);
static ValueNode ofNull();
static ValueNode ofColor(Color color);
static ValueNode ofWire(std::optional<std::string> _value);
};
/** Represents an identifier-value pair*/
struct PropertyNode : public AstNode {
IdentifierNode key;
ValueNode value;
PropertyNode() = default;
PropertyNode(IdentifierNode key, ValueNode value): key(key), value(value) {}
};
/** Represents a string-value pair */
struct StringPropertyNode : public AstNode {
StringNode key;
ValueNode value;
StringPropertyNode() = default;
StringPropertyNode(StringNode key, ValueNode value): key(key), value(value) {}
};
/*****************************************************************************
* RULE TYPES *
*****************************************************************************/
struct IfStatementNode;
/** Represents validation rule
* Rules are made from a list of
* if - else if statements
* */
struct RuleNode : public AstNode {
std::vector<IfStatementNode> statements;
};
/** Represents condition inside if statement
* Every condition is made from optional negation operator !
* Function called and list of function parameters
* */
struct ConditionNode {
bool negated;
IdentifierNode functionName;
std::vector<ValueNode> params;
};
/** Represents action executed inside if statement
* */
struct ActionNode : public AstNode {
/** There are two types of action determined by action type */
enum ActionType {
/** Error actions represent invalid state and cause validation to fail */
ERROR,
/** Warning actions represent states that can cause issue when simulating
* model but models created with it are still valid
* */
WARNING
};
EnumNode<ActionType> type;
/** Message used if condition is fulfilled */
StringNode message;
};
/** If statements represents one validation check inside rule */
struct IfStatementNode : public AstNode {
ConditionNode condition;
ActionNode action;
};
/*****************************************************************************
* ATTRIBUTE TYPES *
*****************************************************************************/
/** Represents popup dialog used to modified attribute inside which it is defined
* */
struct PopupNode : public AstNode {
/** Determines type of popup*/
enum PopupType {
/** Automatic popup is opened when component or connection containing it is defined */
AUTOMATIC,
/** On demand popups are opened on user request usually from context menus*/
ON_DEMAND
};
std::optional<EnumNode<PopupType>> type;
/** Title of popup */
std::optional<StringNode> title;
/** Text of popup */
std::optional<StringNode> text;
/** If popup contains an enumeration*/
bool enumerated;
std::vector<StringPropertyNode> enumeration;
/** Validation rules for given popup */
std::vector<RuleNode> rules;
};
/** Represents component or connection attribute
* Attributes are values that can programmatically be changed
* if popup is defined
* */
struct AttributeNode : public AstNode {
/** Type of attribute */
ValueNode::ValueType type;
/** Name of attribute */
IdentifierNode name;
/** Display name */
std::optional<StringNode> displayName;
/** Default type of attribute */
std::optional<ValueNode> defaultValue;
/** Popup used to change attribute value */
std::optional<PopupNode> popup;
};
/*****************************************************************************
* DISPLAY TYPES *
*****************************************************************************/
struct DisplayItemNode;
/** Represents how a component or bus is rendered
* Display is made from an list of display items
* */
struct DisplayNode : public AstNode {
std::vector<DisplayItemNode> items;
};
/** DisplayItem represents one rendered item
* in source code items are defined similar to json objects
* eg.
* @code rect {
* x: 100;
* y: 100;
* w: 100;
* h: 100;
* fillColor: #123456
* }
* */
struct DisplayItemNode : public AstNode {
/** Contains type of display item */
IdentifierNode type;
/** Contains all property nodes */
std::vector<PropertyNode> values;
/** Returns value of requested property
* If requested property doesn't exists default value is returned (eg. asInt is called but PropertyNode contains string)
* If value of requested property is different than expected nullopt is retured
* */
std::optional<long long int> asInt(const std::string &property, long long int _default = 0);
std::optional<Color> asColor(const std::string &property, Color _default = Color(0, 0, 0));
std::optional<std::string> asString(const std::string &property, std::string _default = "");
private:
std::optional<PropertyNode> getProperty(const std::string &property);
};
/*****************************************************************************
* LIBRARY TYPES *
*****************************************************************************/
/** Represents AddressSpaces
* Address spaces are defined with their name and address range
* */
struct AddressSpaceNode : public AstNode {
IdentifierNode name;
/** Range represent which addresses are available for components that use memory space [first, second> */
NumberPairNode range;
};
/** Pins are used to create component-component or component-bus connections */
struct PinNode : public AstNode {
/** Determines pin type, pin types currently only affect how pins are rendered */
enum PinType {
IN_OUT,
IN,
OUT
};
/** Name of pin */
IdentifierNode name;
/** Type of pin */
EnumNode<PinType> type;
/** Tooltip content displayed on hover over pin */
std::optional<StringNode> tooltip;
/** If present this means pin must be connected to another component or bus to create connection
* Connection contains error message shown
* */
std::optional<StringNode> connection;
/** Determines how the pin is displayed */
std::optional<DisplayNode> display;
/** If pin connection is optional it requires list of wires used to populate comdel model */
std::optional<std::vector<ValueNode>> wires;
};
/**
* Represents COMDEL component
* */
struct ComponentNode : public AstNode {
/** Determines type of component */
enum ComponentType {
/** Generic component */
OTHER,
/** Represents processor, all processors have implicit attribute _memory if type memory
* used when generating COMDEL model to connect memories and processors
*/
PROCESSOR,
/** Represents memory, all components of type memory can be selected in _memory attribute of processor */
MEMORY
};
/** Component name */
IdentifierNode name;
/** Component name */
std::optional<StringNode> displayName;
/** Tooltip displayed on hover */
std::optional<StringNode> tooltip;
/** Contains path to COMDEL source containing current component */
std::optional<StringNode> source;
/** Type of component */
EnumNode<ComponentType> type;
/** List of component level rules */
std::vector<RuleNode> rules;
/** Default used to name instances */
std::optional<IdentifierNode> instanceName;
/** Count determines number of instances allowed in a schema */
std::optional<NumberPairNode> count;
/** Display determines how component is rendered */
std::optional<DisplayNode> display;
/** List of all pins */
std::vector<PinNode> pins;
/** List of all attributes */
std::vector<AttributeNode> attributes;
};
/** WireNode represents COMDEL wire
* */
struct WireNode : public AstNode {
/** Determines type of wires */
enum WireType {
/** Generic wire */
WIRE,
/** wired_and can have multiple sources, that are ANDed together */
WIRED_AND,
/** wired_and can have multiple sources, that are ORed together */
WIRED_OR,
/** r_wire can remain unconnected */
R_WIRE
};
EnumNode<WireType> type;
/** Name of wire */
IdentifierNode name;
/** Number of bits inside of a wire */
NumberNode size;
/** If wire is visible or hidden, this determines how wires are generated in COMDEL */
bool hidden = false;
/** If wire isn't connected to anything it is replaced with terminate with terminateWith value */
bool hasTerminateWith = false;
ValueNode terminateWith;
};
/** Buses dont exist in COMDEL but they are useful
* as they allow us to connect multiple COMDEL wires together
* */
struct BusNode : public AstNode {
enum BusType {
/** This busses connect two components */
AUTOMATIC,
/**
* This busses allow us to connect multiple component together using one bus
* */
REGULAR,
/** This busses connect two components,
* they differ from automatic as they allow us to connect same pins multiple times */
SINGLE_AUTOMATIC
};
EnumNode<BusType> type;
/** Bus name */
IdentifierNode name;
/** Display name */
std::optional<StringNode> displayName;
/** Default used to name instances */
std::optional<IdentifierNode> instanceName;
/** Tooltip displayed on hover */
std::optional<StringNode> tooltip;
/** Count determines number of instances allowed in a schema */
std::optional<NumberPairNode> count;
/** Display determines how component is rendered */
std::optional<DisplayNode> display;
/** List of all COMDEL wires contained in bus */
std::vector<WireNode> wires;
};
/** Represents ComponentConnection key in Connection node
* (eg. componentName.pinName)
* */
struct ConnectionComponentNode : public AstNode {
IdentifierNode component;
IdentifierNode pin;
};
/** Represents Connection node
* Connection can be between component and bus in which second is null,
* or between two components
* */
struct ConnectionNode : public AstNode {
ConnectionComponentNode first;
std::optional<ConnectionComponentNode> second;
IdentifierNode bus;
std::vector<AttributeNode> attributes;
/** If connection is of type component-component it contains two pairs of wires */
std::vector<ValueNode> firstWires;
std::optional<std::vector<ValueNode>> secondWires;
};
/** LibraryNode represent library instance */
struct LibraryNode : public AstNode {
/** Name of library */
std::optional<StringNode> name;
/** Library info contains generic information about library */
std::optional<StringNode> libraryInfo;
/** Contains text that is added to top of COMDEL file */
std::optional<StringNode> header;
/** Contains path to component directory */
std::optional<StringNode> componentDirectory;
/** Contains text that is added to top of System component in COMDEL file */
std::optional<StringNode> componentHeader;
std::vector<AddressSpaceNode> addressSpaces;
std::vector<ComponentNode> components;
std::vector<BusNode> buses;
std::vector<ConnectionNode> connections;
/** Contains properties used to translate dialog and error messages */
std::vector<PropertyNode> messages;
};
/*****************************************************************************
* LIBRARY TYPES *
*****************************************************************************/
/** Represents instance of attribute in component or connection instance */
struct InstanceAttributeNode : public AstNode {
IdentifierNode name;
ValueNode value;
};
/** Represents instance of a component or a bus */
struct InstanceNode : public AstNode {
/** Contains instance name */
IdentifierNode name;
/** Contains component name */
IdentifierNode component;
/** Contains position of component instance */
std::optional<NumberPairNode> position;
std::vector<InstanceAttributeNode> attributes;
/** Contains size of bus instances */
std::optional<NumberNode> size;
};
/** Represents ComponentConnection of a selected instance */
struct ConnectionComponentInstanceNode : public AstNode {
/** Name of component instance */
IdentifierNode instance;
/** Name of pin */
IdentifierNode pin;
};
/** Represents Connection instance */
struct ConnectionInstanceNode : public AstNode {
ConnectionComponentInstanceNode first;
std::optional<ConnectionComponentInstanceNode> second;
IdentifierNode bus;
std::vector<InstanceAttributeNode> attributes;
};
/** Represent schema instance */
struct SchemaNode : public AstNode {
/** Contains path to library source */
std::optional<StringNode> source;
/** Contains list of instances */
std::vector<InstanceNode> instances;
/** Contains list of connection */
std::vector<ConnectionInstanceNode> connections;
/** Contains library */
std::optional<LibraryNode> library;
};
#endif // AST_NODE_H

View File

@ -1,109 +0,0 @@
#include "astnode.h"
/*************************** AST NODE ********************************/
AstNode::~AstNode() = default;
/*************************** NUMBER NODE ********************************/
NumberNode::NumberNode(const std::string& expression) {
if(expression.size() > 2) {
if(expression.substr(0, 2) == "0x") {
this->value = std::stoll(expression, 0, 16);
} else if(expression.substr(0, 2) == "0b") {
this->value = std::stoll(expression, 0, 2);
} else {
this->value = std::stoll(expression, 0, 10);
}
} else {
this->value = std::stoll(expression, 0, 10);
}
}
/*************************** STRING NODE ********************************/
std::string StringNode::asString() {
return value.substr(1, value.length() - 2);
}
/*************************** VALUE NODE ********************************/
long long ValueNode::asInt() {
if(is(INT)) {
return intValue.value();
}
return 0;
}
std::string ValueNode::asString() {
if(is(STRING)) {
return stringValue.value();
}
return "";
}
std::string ValueNode::asIdentifier() {
if(is(IDENTIFIER) || is(WIRE)) {
return identifierValue.value();
}
return "";
}
bool ValueNode::asBool() {
if(is(BOOL)) {
return boolValue.value();
}
return false;
}
bool ValueNode::is(ValueNode::ValueType valueType) {
return type.value == valueType;
}
ValueNode ValueNode::ofBool(bool _value) {
ValueNode value;
value.type = EnumNode(BOOL);
value.boolValue = std::optional<bool>(_value);
return value;
}
ValueNode ValueNode::ofInt(long long int _value) {
ValueNode value;
value.type = EnumNode(INT);
value.intValue = std::optional<long long>(_value);
return value;
}
ValueNode ValueNode::ofString(std::string _value) {
ValueNode value;
value.type = EnumNode(STRING);
value.stringValue = std::optional<std::string>(_value);
return value;
}
ValueNode ValueNode::ofIdentifier(std::string _value) {
ValueNode value;
value.type = EnumNode(IDENTIFIER);
value.identifierValue = std::optional<std::string>(_value);
return value;
}
ValueNode ValueNode::ofNull() {
ValueNode value;
value.type = EnumNode(NIL);
return value;
}
ValueNode ValueNode::ofWire(std::optional<std::string> _value) {
ValueNode value;
value.type = EnumNode(WIRE);
value.identifierValue = _value;
return value;
}
ValueNode ValueNode::ofMemory(std::optional<std::string> _value) {
ValueNode value;
value.type = EnumNode(MEMORY);
value.identifierValue = _value;
return value;
}

View File

@ -1,400 +0,0 @@
#ifndef AST_NODE_H
#define AST_NODE_H
#include "token.h"
#include "sourceerror.h"
#include <optional>
#include <vector>
/**
* AST base class, all AST node classes extend this class. Class contains basic
* information about nodes location in file.
*/
class AstNode {
public:
Span span;
AstNode() = default;
virtual ~AstNode();
AstNode(AstNode&&) = default;
AstNode& operator=(AstNode&&) = default;
AstNode(const AstNode&) = default;
AstNode& operator=(const AstNode&) = default;
};
template <typename T>
struct EnumNode: public AstNode
{
EnumNode() = default;
explicit EnumNode(T value): value(value) {}
T value;
};
struct StringNode: public AstNode
{
std::string value;
std::string asString();
};
struct IdentifierNode: public AstNode
{
std::string value;
};
struct NumberNode: public AstNode {
long long int value;
explicit NumberNode(const std::string& expression);
NumberNode(): value(0) {}
};
struct CountNode: public AstNode
{
NumberNode first;
NumberNode second;
CountNode(NumberNode first, NumberNode second): first(first), second(second) {}
CountNode() = default;
};
struct AddressSpaceNode: public AstNode
{
IdentifierNode name;
NumberNode start;
NumberNode end;
};
class ValueNode: public AstNode
{
public:
enum ValueType {
INT,
STRING,
BOOL,
WIRE,
IDENTIFIER,
MEMORY,
NIL,
};
private:
EnumNode<ValueType> type;
std::optional<long long> intValue;
std::optional<std::string> stringValue;
std::optional<bool> boolValue;
std::optional<std::string> identifierValue;
public:
ValueNode() = default;
ValueType getType() {
return type.value;
}
long long asInt();
std::string asString();
std::string asIdentifier();
bool asBool();
bool is(ValueType valueType);
static ValueNode ofBool(bool _value);
static ValueNode ofInt(long long _value);
static ValueNode ofString(std::string _value);
static ValueNode ofIdentifier(std::string _value);
static ValueNode ofMemory(std::optional<std::string> _value);
static ValueNode ofNull();
static ValueNode ofWire(std::optional<std::string> _value);
};
struct ConditionNode
{
bool negated;
IdentifierNode functionName;
std::vector<ValueNode> params;
};
class ActionNode: public AstNode {
public:
enum ActionType {
ERROR,
WARNING
};
EnumNode<ActionType> type;
StringNode message;
};
struct IfStatementNode: public AstNode
{
ConditionNode condition;
ActionNode action;
};
struct RuleNode: public AstNode
{
std::vector<IfStatementNode> statements;
};
struct EnumerationNode: public AstNode
{
StringNode key;
ValueNode value;
};
struct PopupNode: public AstNode
{
enum PopupType {
AUTOMATIC,
ON_DEMAND
};
std::optional<EnumNode<PopupType>> type;
std::optional<StringNode> title;
std::optional<StringNode> text;
bool enumerated;
std::vector<EnumerationNode> enumeration;
std::vector<RuleNode> rules;
};
struct PropertyNode: public AstNode
{
IdentifierNode key;
ValueNode value;
};
struct DisplayItemNode: public AstNode
{
IdentifierNode type;
std::vector<PropertyNode> values;
long long int asInt(std::vector<SourceError>* errors, const std::string& property, long long int _default = 0) {
for(auto& prop: values) {
if(prop.key.value == property) {
if(prop.value.is(ValueNode::INT)) {
return prop.value.asInt();
} else {
if(errors != nullptr) {
errors->emplace_back(prop.value.span, "expected number");
}
}
}
}
return _default;
}
std::string asIdentifier(std::vector<SourceError>* errors, const std::string& property, std::string _default = "") {
for(auto& prop: values) {
if(prop.key.value == property) {
if(prop.value.is(ValueNode::IDENTIFIER)) {
return prop.value.asIdentifier();
} else {
if(errors != nullptr) {
errors->emplace_back(prop.value.span, "expected identifier");
}
}
}
}
return _default;
}
std::string asString(std::vector<SourceError>* errors, const std::string& property, std::string _default = "") {
for(auto& prop: values) {
if(prop.key.value == property) {
if(prop.value.is(ValueNode::STRING)) {
return prop.value.asString();
} else {
if(errors != nullptr) {
errors->emplace_back(prop.value.span, "expected string");
}
}
}
}
return _default;
}
};
struct DisplayNode: public AstNode
{
std::vector<DisplayItemNode> items;
};
struct PinConnectionNode: public AstNode
{
enum ConnectionType {
REQUIRED,
OPTIONAL
};
StringNode message;
EnumNode<ConnectionType> type;
};
struct PinNode: public AstNode
{
enum PinType {
IN_OUT,
IN,
OUT
};
IdentifierNode name;
EnumNode<PinType> type;
std::optional<StringNode> tooltip;
std::optional<PinConnectionNode> connection;
std::optional<DisplayNode> display;
std::optional<std::vector<ValueNode>> wires;
};
struct WireNode: public AstNode
{
enum WireType {
WIRE,
WIRED_AND,
WIRED_OR,
R_WIRE
};
EnumNode<WireType> type;
IdentifierNode name;
NumberNode size;
bool hidden = false;
bool hasTerminateWith;
ValueNode terminateWith;
};
struct AttributeNode: public AstNode
{
ValueNode::ValueType type;
IdentifierNode name;
std::optional<ValueNode> defaultValue;
std::optional<PopupNode> popup;
};
struct ConnectionComponentNode: public AstNode
{
IdentifierNode component;
IdentifierNode pin;
};
struct ConnectionNode: public AstNode
{
ConnectionComponentNode first;
std::optional<ConnectionComponentNode> second;
IdentifierNode bus;
std::vector<AttributeNode> attributes;
std::vector<ValueNode> firstWires;
std::optional<std::vector<ValueNode>> secondWires;
};
struct ComponentNode: public AstNode
{
enum ComponentType {
OTHER,
PROCESSOR,
MEMORY
};
IdentifierNode name;
std::optional<StringNode> tooltip;
std::optional<StringNode> source;
EnumNode<ComponentType> type;
std::vector<RuleNode> rules;
std::optional<StringNode> instanceName;
std::optional<CountNode> count;
std::optional<DisplayNode> display;
std::vector<PinNode> pins;
std::vector<AttributeNode> attributes;
};
struct BusNode: public AstNode
{
enum BusType {
AUTOMATIC,
REGULAR,
SINGLE_AUTOMATIC
};
EnumNode<BusType> type;
IdentifierNode name;
std::optional<StringNode> tooltip;
std::optional<CountNode> count;
std::optional<DisplayNode> display;
std::vector<WireNode> wires;
};
struct LibraryNode: public AstNode
{
std::optional<StringNode> name;
std::optional<StringNode> libraryInfo;
std::optional<StringNode> header;
std::optional<StringNode> componentDirectory;
std::optional<StringNode> componentHeader;
std::vector<AddressSpaceNode> addressSpaces;
std::vector<ComponentNode> components;
std::vector<BusNode> buses;
std::vector<ConnectionNode> connections;
std::vector<PropertyNode> messages;
};
// SCHEMA models
struct InstanceAttributeNode: public AstNode
{
IdentifierNode name;
ValueNode value;
};
struct InstanceNode: public AstNode
{
IdentifierNode name;
IdentifierNode component;
std::optional<CountNode> position;
std::vector<InstanceAttributeNode> attributes;
std::optional<NumberNode> size;
};
struct ConnectionComponentInstance: public AstNode
{
IdentifierNode instance;
IdentifierNode pin;
};
struct ConnectionInstanceNode: public AstNode
{
ConnectionComponentInstance first;
std::optional<ConnectionComponentInstance> second;
IdentifierNode bus;
std::vector<InstanceAttributeNode> attributes;
};
struct SchemaNode: public AstNode
{
std::optional<StringNode> source;
std::vector<InstanceNode> instances;
std::vector<ConnectionInstanceNode> connections;
std::optional<LibraryNode> library;
};
#endif // AST_NODE_H

21
comdel/parser/color.h Normal file
View File

@ -0,0 +1,21 @@
//
// Created by bbr on 12.06.22..
//
#ifndef SCHEMEEDITOR_COLOR_H
#define SCHEMEEDITOR_COLOR_H
struct Color {
unsigned char r = 0;
unsigned char g = 0;
unsigned char b = 0;
unsigned char a = 255;
Color() = default;
Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0): r(r), g(g), b(b), a(a) {}
};
#endif //SCHEMEEDITOR_COLOR_H

View File

@ -1,6 +1,6 @@
#include "comdellexer.h" #include "comdel_lexer.h"
#include "token.h" #include "token.h"
#include "tokenstype.h" #include "tokens_type.h"
#include <fstream> #include <fstream>
#include <cctype> #include <cctype>
@ -42,8 +42,7 @@ ComdelLexer::ComdelLexer(std::string fileName, std::string source,
// TODO Update this // TODO Update this
fileId(this->parseContext->addFile(fileName, this->source)), fileId(this->parseContext->addFile(fileName, this->source)),
position(this->fileId, 1, 1, 0), position(this->fileId, 1, 1, 0),
ch(this->source[0]) ch(this->source[0]) {}
{}
LexerResult ComdelLexer::tokenize() { LexerResult ComdelLexer::tokenize() {
@ -181,8 +180,7 @@ PResult<TokenType> ComdelLexer::takeString() {
} }
PResult<TokenType> ComdelLexer::takeRawString() PResult<TokenType> ComdelLexer::takeRawString() {
{
Position lo = position; Position lo = position;
if (ch != '`') if (ch != '`')
@ -237,20 +235,15 @@ bool ComdelLexer::skipMultilineComment() {
PResult<TokenType> ComdelLexer::nextTokenType() { PResult<TokenType> ComdelLexer::nextTokenType() {
if (isWhitespace(ch)) if (isWhitespace(ch)) {
{
skipWhitespace(); skipWhitespace();
return TokenType::WHITESPACE; return TokenType::WHITESPACE;
} } else if (identifierStart(ch)) {
else if (identifierStart(ch))
{
bump(); bump();
while (identifierContinue(ch)) while (identifierContinue(ch))
bump(); bump();
return TokenType::IDENTIFIER; return TokenType::IDENTIFIER;
} } else if (numberStart(ch)) {
else if (numberStart(ch))
{
if (ch == '-') { if (ch == '-') {
bump(); bump();
} }
@ -266,27 +259,16 @@ PResult<TokenType> ComdelLexer::nextTokenType() {
"illegal digit or letter found at the end of number"}); "illegal digit or letter found at the end of number"});
} }
return TokenType::NUMBER; return TokenType::NUMBER;
} } else if (ch == '!') {
else if (ch == '!')
{
bump(); bump();
return TokenType::NOT; return TokenType::NOT;
} } else if (ch == '<') {
else if (ch == '<')
{
bump(); bump();
return TokenType::LT; return TokenType::LT;
} } else if (ch == '>') {
else if (ch == '>')
{
bump(); bump();
return TokenType::GT; return TokenType::GT;
} } else if (ch == '#') {
else if (ch == '#')
{
bump(); bump();
if (digitIsValid(ch, Radix::HEX_NUMBER)) { if (digitIsValid(ch, Radix::HEX_NUMBER)) {
@ -304,65 +286,42 @@ PResult<TokenType> ComdelLexer::nextTokenType() {
return PError({Span(tokenBegin, position), return PError({Span(tokenBegin, position),
"unexpected #"}); "unexpected #"});
} }
} } else if (ch == '@') {
else if (ch == '@')
{
bump(); bump();
while (identifierContinue(ch)) while (identifierContinue(ch))
bump(); bump();
return TokenType::KEYWORD; return TokenType::KEYWORD;
} } else if (ch == '"') {
else if (ch == '"')
{
return takeString(); return takeString();
} } else if (ch == '`') {
else if (ch == '`')
{
return takeRawString(); return takeRawString();
} } else if (ch == '(') {
else if (ch == '(')
{
bump(); bump();
return TokenType::LPAREN; return TokenType::LPAREN;
} } else if (ch == ')') {
else if (ch == ')')
{
bump(); bump();
return TokenType::RPAREN; return TokenType::RPAREN;
} } else if (ch == '[') {
else if (ch == '[')
{
bump(); bump();
return TokenType::LBRACKET; return TokenType::LBRACKET;
} } else if (ch == ']') {
else if (ch == ']')
{
bump(); bump();
return TokenType::RBRACKET; return TokenType::RBRACKET;
} } else if (ch == '{') {
else if (ch == '{')
{
bump(); bump();
return TokenType::LBRACE; return TokenType::LBRACE;
} } else if (ch == '}') {
else if (ch == '}')
{
bump(); bump();
return TokenType::RBRACE; return TokenType::RBRACE;
} } else if (ch == '/') {
else if (ch == '/')
{
bump(); bump();
if (ch == '/') if (ch == '/') {
{
bump(); bump();
skipComment(); skipComment();
return TokenType::COMMENT; return TokenType::COMMENT;
} else if (ch == '*') } else if (ch == '*') {
{
bump(); bump();
if (!skipMultilineComment()) if (!skipMultilineComment()) {
{
return PError({Span(tokenBegin, position), return PError({Span(tokenBegin, position),
"unterminated multiline comment"}); "unterminated multiline comment"});
} }
@ -370,34 +329,22 @@ PResult<TokenType> ComdelLexer::nextTokenType() {
} }
return PError({Span(tokenBegin, position), return PError({Span(tokenBegin, position),
"unexpected /"}); "unexpected /"});
} } else if (ch == '.') {
else if (ch == '.')
{
bump(); bump();
return TokenType::DOT; return TokenType::DOT;
} } else if (ch == ':') {
else if (ch == ':')
{
bump(); bump();
return TokenType::COLON; return TokenType::COLON;
} } else if (ch == ';') {
else if (ch == ';')
{
bump(); bump();
return TokenType::SEMICOLON; return TokenType::SEMICOLON;
} } else if (ch == ',') {
else if (ch == ',')
{
bump(); bump();
return TokenType::COMMA; return TokenType::COMMA;
} } else if (ch == '=') {
else if (ch == '=')
{
bump(); bump();
return TokenType::EQUALS; return TokenType::EQUALS;
} } else {
else
{
std::stringstream message; std::stringstream message;
message << "unexpected character `" << ch << "`"; message << "unexpected character `" << ch << "`";
bump(); bump();

View File

@ -1,9 +1,9 @@
#ifndef COMDEL_LEXER_H #ifndef COMDEL_LEXER_H
#define COMDEL_LEXER_H #define COMDEL_LEXER_H
#include "parsecontext.h" #include "parse_context.h"
#include "presult.h" #include "presult.h"
#include "sourceerror.h" #include "source_error.h"
#include "token.h" #include "token.h"
@ -11,13 +11,15 @@
#include <string> #include <string>
#include <vector> #include <vector>
/** Contains results of tokenizing,
* if errors isn't empty tokenizing has failed */
struct LexerResult { struct LexerResult {
std::vector<Token> tokens; std::vector<Token> tokens;
std::vector<SourceError> errors; std::vector<SourceError> errors;
}; };
class ComdelLexer /** Used to tokenize input string */
{ class ComdelLexer {
enum Radix { enum Radix {
BIN_NUMBER = 2, BIN_NUMBER = 2,
@ -25,38 +27,46 @@ class ComdelLexer
HEX_NUMBER = 16 HEX_NUMBER = 16
}; };
/** Source file */
std::string source; std::string source;
std::vector<Token> tokens; std::vector<Token> tokens;
std::vector<SourceError> errors; std::vector<SourceError> errors;
/** Source file */
ParseContext *parseContext; ParseContext *parseContext;
unsigned fileId; unsigned fileId;
public: public:
ComdelLexer(std::string fileName, std::string source, ParseContext *parseContext); ComdelLexer(std::string fileName, std::string source, ParseContext *parseContext);
LexerResult tokenize(); LexerResult tokenize();
private: private:
void skipWhitespace(); /** Current parsing info */
unsigned takeNumberInRadix(Radix radix);
unsigned takeHexColor();
bool digitIsValid(char ch, Radix radix);
Radix takeRadix();
PResult<TokenType> nextTokenType();
Position tokenBegin; Position tokenBegin;
Position position; Position position;
char ch; char ch;
/** Methods used to skip unused content */
void skipWhitespace();
void skipComment(); void skipComment();
bool skipMultilineComment(); bool skipMultilineComment();
void bump(unsigned count = 1);
/** Metods used for number parsing */
unsigned takeNumberInRadix(Radix radix);
bool digitIsValid(char ch, Radix radix);
Radix takeRadix();
unsigned takeHexColor();
PResult<TokenType> nextTokenType();
PResult<TokenType> takeString(); PResult<TokenType> takeString();
PResult<TokenType> takeRawString(); PResult<TokenType> takeRawString();
void bump(unsigned count = 1);
char peek(); char peek();
/** Checks if we reached end of file */
bool eof(); bool eof();
}; };

View File

@ -1,10 +1,10 @@
#ifndef COMDEL_PARSER_H #ifndef COMDEL_PARSER_H
#define COMDEL_PARSER_H #define COMDEL_PARSER_H
#include "sourceerror.h" #include "source_error.h"
#include "presult.h" #include "presult.h"
#include "token.h" #include "token.h"
#include "astnode.h" #include "ast_nodes.h"
#include <optional> #include <optional>
#include <set> #include <set>
@ -23,18 +23,16 @@ class Spanner {
public: public:
const Span lo; // the low end of the span, beginning of the node const Span lo; // the low end of the span, beginning of the node
Spanner(Span lo, Span &prevSpan) : lo(lo), prevSpan(prevSpan) {} Spanner(Span lo, Span &prevSpan) : lo(lo), prevSpan(prevSpan) {}
template<typename T, typename = std::enable_if<std::is_base_of<AstNode, T>::value>> template<typename T, typename = std::enable_if<std::is_base_of<AstNode, T>::value>>
typename std::remove_reference_t<T> operator()(T &&astNode) const { typename std::remove_reference_t<T> operator()(T &&astNode) const {
astNode.span = lo.to(prevSpan); astNode.span = lo.to(prevSpan);
return std::move(astNode); return std::forward<T>(astNode);
} }
}; };
class ComdelParser class ComdelParser {
{
private: private:
std::vector<Token> tokens; std::vector<Token> tokens;
std::set<TokenType> expectedTokens; std::set<TokenType> expectedTokens;
@ -44,15 +42,20 @@ private:
Span &getPreviousSpan(); Span &getPreviousSpan();
/** Skips current token */
void bump(); void bump();
/** Checks if next token is of given type and if it is consumes it */
bool consume(TokenType tokenType); bool consume(TokenType tokenType);
/** Checks if next token is of given type */
bool check(TokenType tokenType); bool check(TokenType tokenType);
/** Skips until next keyword on same level
* Used to continue parsing on error
* */
void skipUntilNextKeyword(); void skipUntilNextKeyword();
/** Retuns current token */
Token &current(); Token &current();
/** Throws error of unexpected types */
[[nodiscard]] PError unexpected(); [[nodiscard]] PError unexpected();
template<typename T> template<typename T>
@ -64,46 +67,46 @@ private:
Spanner getSpanner(); Spanner getSpanner();
/** Base types */
PResult<StringNode> parseString(); PResult<StringNode> parseString();
PResult<ColorNode> parseColor();
PResult<IdentifierNode> parseIdentifier(); PResult<IdentifierNode> parseIdentifier();
PResult<NumberNode> parseNumber(); PResult<NumberNode> parseNumber();
PResult<CountNode> parseCount(); PResult<NumberPairNode> parseNumberPair();
PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType); PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType);
PResult<EnumerationNode> parseEnumeration(); PResult<StringPropertyNode> parseStringProperty();
PResult<ValueNode> parseValue();
/** Library types */
PResult<ValueNode> parseConnectionWire(); PResult<ValueNode> parseConnectionWire();
PResult<ComponentNode> parseComponent(); PResult<ComponentNode> parseComponent();
PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType();
PResult<AddressSpaceNode> parseAddress(); PResult<AddressSpaceNode> parseAddress();
PResult<PinNode> parsePin(); PResult<PinNode> parsePin();
PResult<DisplayNode> parseDisplay(); PResult<DisplayNode> parseDisplay();
PResult<PinConnectionNode> parsePinConnection();
PResult<AttributeNode> parseAttribute(); PResult<AttributeNode> parseAttribute();
PResult<PopupNode> parsePopup(); PResult<PopupNode> parsePopup();
PResult<RuleNode> parseRule(); PResult<RuleNode> parseRule();
PResult<BusNode> parseBus(); PResult<BusNode> parseBus();
PResult<WireNode> parseWire(); PResult<WireNode> parseWire();
PResult<ConnectionNode> parseConnection(); PResult<ConnectionNode> parseConnection();
PResult<ConnectionComponentNode> parseConnectionComponent();
PResult<DisplayItemNode> parseDisplayItem(); PResult<DisplayItemNode> parseDisplayItem();
PResult<IfStatementNode> parseIfStatement(); PResult<IfStatementNode> parseIfStatement();
PResult<ValueNode> parseValue(); PResult<EnumNode<BusNode::BusType>> parseBusType();
/** Schema types */
PResult<CountNode> parsePosition();
PResult<InstanceNode> parseInstance(); PResult<InstanceNode> parseInstance();
PResult<InstanceAttributeNode> parseInstanceAttribute(); PResult<InstanceAttributeNode> parseInstanceAttribute();
PResult<ConnectionInstanceNode> parseConnectionInstance(); PResult<ConnectionInstanceNode> parseConnectionInstance();
PResult<ConnectionComponentInstanceNode> parseConnectionComponentInstance();
public: public:
ComdelParser(std::vector<Token> tokens); explicit ComdelParser(std::vector<Token> tokens);
std::optional<SchemaNode> parseSchema(); std::optional<SchemaNode> parseSchema();
std::optional<LibraryNode> parse(); std::optional<LibraryNode> parseLibrary();
const std::vector<SourceError> &getErrors(); const std::vector<SourceError> &getErrors();
PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType();
PResult<EnumNode<BusNode::BusType>> parseBusType();
PResult<EnumNode<PinConnectionNode::ConnectionType>> parseConnectionType();
}; };
#endif // COMDEL_PARSER_H #endif // COMDEL_PARSER_H

View File

@ -128,27 +128,33 @@ namespace tl {
#endif #endif
namespace tl { namespace tl {
template <class T, class E> class expected; template<class T, class E>
class expected;
#ifndef TL_MONOSTATE_INPLACE_MUTEX #ifndef TL_MONOSTATE_INPLACE_MUTEX
#define TL_MONOSTATE_INPLACE_MUTEX #define TL_MONOSTATE_INPLACE_MUTEX
/// \brief Used to represent an expected with no data /// \brief Used to represent an expected with no data
class monostate {}; class monostate {
};
/// \brief A tag type to tell expected to construct its value in-place /// \brief A tag type to tell expected to construct its value in-place
struct in_place_t { struct in_place_t {
explicit in_place_t() = default; explicit in_place_t() = default;
}; };
/// \brief A tag to tell expected to construct its value in-place /// \brief A tag to tell expected to construct its value in-place
static constexpr in_place_t in_place{}; static constexpr in_place_t in_place{};
#endif #endif
/// Used as a wrapper to store the unexpected value /// Used as a wrapper to store the unexpected value
template <class E> class unexpected { template<class E>
class unexpected {
public: public:
static_assert(!std::is_same<E, void>::value, "E must not be void"); static_assert(!std::is_same<E, void>::value, "E must not be void");
unexpected() = delete; unexpected() = delete;
constexpr unexpected(const E &e) : m_val(e) {} constexpr unexpected(const E &e) : m_val(e) {}
constexpr unexpected(E &&e) : m_val(std::move(e)) {} constexpr unexpected(E &&e) : m_val(std::move(e)) {}
@ -160,6 +166,7 @@ public:
TL_EXPECTED_11_CONSTEXPR E &value() &{ return m_val; } TL_EXPECTED_11_CONSTEXPR E &value() &{ return m_val; }
/// \group unexpected_value /// \group unexpected_value
TL_EXPECTED_11_CONSTEXPR E &&value() &&{ return std::move(m_val); } TL_EXPECTED_11_CONSTEXPR E &&value() &&{ return std::move(m_val); }
/// \exclude /// \exclude
constexpr const E &&value() const &&{ return std::move(m_val); } constexpr const E &&value() const &&{ return std::move(m_val); }
@ -174,26 +181,31 @@ template <class E>
constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) { constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() == rhs.value(); return lhs.value() == rhs.value();
} }
/// \group unexpected_relop /// \group unexpected_relop
template<class E> template<class E>
constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) { constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() != rhs.value(); return lhs.value() != rhs.value();
} }
/// \group unexpected_relop /// \group unexpected_relop
template<class E> template<class E>
constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) { constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() < rhs.value(); return lhs.value() < rhs.value();
} }
/// \group unexpected_relop /// \group unexpected_relop
template<class E> template<class E>
constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) { constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() <= rhs.value(); return lhs.value() <= rhs.value();
} }
/// \group unexpected_relop /// \group unexpected_relop
template<class E> template<class E>
constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) { constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) {
return lhs.value() > rhs.value(); return lhs.value() > rhs.value();
} }
/// \group unexpected_relop /// \group unexpected_relop
template<class E> template<class E>
constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) { constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) {
@ -214,6 +226,7 @@ unexpected<typename std::decay<E>::type> make_unexpected(E &&e) {
struct unexpect_t { struct unexpect_t {
unexpect_t() = default; unexpect_t() = default;
}; };
/// \brief A tag to tell expected to construct the unexpected value /// \brief A tag to tell expected to construct the unexpected value
static constexpr unexpect_t unexpect{}; static constexpr unexpect_t unexpect{};
@ -246,11 +259,16 @@ template <bool B, class T, class F>
using conditional_t = typename std::conditional<B, T, F>::type; using conditional_t = typename std::conditional<B, T, F>::type;
// std::conjunction from C++17 // std::conjunction from C++17
template <class...> struct conjunction : std::true_type {}; template<class...>
template <class B> struct conjunction<B> : B {}; struct conjunction : std::true_type {
};
template<class B>
struct conjunction<B> : B {
};
template<class B, class... Bs> template<class B, class... Bs>
struct conjunction<B, Bs...> struct conjunction<B, Bs...>
: std::conditional<bool(B::value), conjunction<Bs...>, B>::type {}; : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {
};
// std::invoke from C++17 // std::invoke from C++17
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
@ -272,7 +290,8 @@ constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
} }
// std::invoke_result from C++17 // std::invoke_result from C++17
template <class F, class, class... Us> struct invoke_result_impl; template<class F, class, class... Us>
struct invoke_result_impl;
template<class F, class... Us> template<class F, class... Us>
struct invoke_result_impl< struct invoke_result_impl<
@ -289,9 +308,12 @@ using invoke_result_t = typename invoke_result<F, Us...>::type;
#endif #endif
// Trait for checking if a type is a tl::expected // Trait for checking if a type is a tl::expected
template <class T> struct is_expected_impl : std::false_type {}; template<class T>
struct is_expected_impl : std::false_type {
};
template<class T, class E> template<class T, class E>
struct is_expected_impl<expected<T, E>> : std::true_type {}; struct is_expected_impl<expected<T, E>> : std::true_type {
};
template<class T> using is_expected = is_expected_impl<decay_t<T>>; template<class T> using is_expected = is_expected_impl<decay_t<T>>;
template<class T, class E, class U> template<class T, class E, class U>
@ -339,7 +361,8 @@ using is_move_assignable_or_void =
/// \exclude /// \exclude
namespace detail { namespace detail {
struct no_init_t {}; struct no_init_t {
};
static constexpr no_init_t no_init{}; static constexpr no_init_t no_init{};
// Implements the storage of the values, and ensures that the destructor is // Implements the storage of the values, and ensures that the destructor is
@ -352,6 +375,7 @@ template <class T, class E, bool = std::is_trivially_destructible<T>::value,
bool = std::is_trivially_destructible<E>::value> bool = std::is_trivially_destructible<E>::value>
struct expected_storage_base { struct expected_storage_base {
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
template<class... Args, template<class... Args,
@ -366,6 +390,7 @@ struct expected_storage_base {
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
Args &&... args) Args &&... args)
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {} : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
template<class... Args, template<class... Args,
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
nullptr> nullptr>
@ -387,6 +412,7 @@ struct expected_storage_base {
m_unexpect.~unexpected<E>(); m_unexpect.~unexpected<E>();
} }
} }
union { union {
T m_val; T m_val;
unexpected<E> m_unexpect; unexpected<E> m_unexpect;
@ -397,8 +423,10 @@ struct expected_storage_base {
// This specialization is for when both `T` and `E` are trivially-destructible, // This specialization is for when both `T` and `E` are trivially-destructible,
// so the destructor of the `expected` can be trivial. // so the destructor of the `expected` can be trivial.
template <class T, class E> struct expected_storage_base<T, E, true, true> { template<class T, class E>
struct expected_storage_base<T, E, true, true> {
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
template<class... Args, template<class... Args,
@ -413,6 +441,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
Args &&... args) Args &&... args)
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {} : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
template<class... Args, template<class... Args,
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
nullptr> nullptr>
@ -428,6 +457,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
~expected_storage_base() = default; ~expected_storage_base() = default;
union { union {
T m_val; T m_val;
unexpected<E> m_unexpect; unexpected<E> m_unexpect;
@ -437,8 +467,10 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
}; };
// T is trivial, E is not. // T is trivial, E is not.
template <class T, class E> struct expected_storage_base<T, E, true, false> { template<class T, class E>
struct expected_storage_base<T, E, true, false> {
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t) TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t)
: m_no_init(), m_has_val(false) {} : m_no_init(), m_has_val(false) {}
@ -454,6 +486,7 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
Args &&... args) Args &&... args)
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {} : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
template<class... Args, template<class... Args,
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
nullptr> nullptr>
@ -483,8 +516,10 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
}; };
// E is trivial, T is not. // E is trivial, T is not.
template <class T, class E> struct expected_storage_base<T, E, false, true> { template<class T, class E>
struct expected_storage_base<T, E, false, true> {
constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {}
template<class... Args, template<class... Args,
@ -499,6 +534,7 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, constexpr expected_storage_base(in_place_t, std::initializer_list<U> il,
Args &&... args) Args &&... args)
: m_val(il, std::forward<Args>(args)...), m_has_val(true) {} : m_val(il, std::forward<Args>(args)...), m_has_val(true) {}
template<class... Args, template<class... Args,
detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * =
nullptr> nullptr>
@ -518,6 +554,7 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
m_val.~T(); m_val.~T();
} }
} }
union { union {
T m_val; T m_val;
unexpected<E> m_unexpect; unexpected<E> m_unexpect;
@ -527,8 +564,10 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
}; };
// `T` is `void`, `E` is trivially-destructible // `T` is `void`, `E` is trivially-destructible
template <class E> struct expected_storage_base<void, E, false, true> { template<class E>
struct expected_storage_base<void, E, false, true> {
TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base() : m_has_val(true) {} TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base() : m_has_val(true) {}
constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {} constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {}
constexpr expected_storage_base(in_place_t) : m_has_val(true) {} constexpr expected_storage_base(in_place_t) : m_has_val(true) {}
@ -548,7 +587,9 @@ template <class E> struct expected_storage_base<void, E, false, true> {
: m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {}
~expected_storage_base() = default; ~expected_storage_base() = default;
struct dummy {};
struct dummy {
};
union { union {
unexpected<E> m_unexpect; unexpected<E> m_unexpect;
dummy m_val; dummy m_val;
@ -557,8 +598,10 @@ template <class E> struct expected_storage_base<void, E, false, true> {
}; };
// `T` is `void`, `E` is not trivially-destructible // `T` is `void`, `E` is not trivially-destructible
template <class E> struct expected_storage_base<void, E, false, false> { template<class E>
struct expected_storage_base<void, E, false, false> {
constexpr expected_storage_base() : m_dummy(), m_has_val(true) {} constexpr expected_storage_base() : m_dummy(), m_has_val(true) {}
constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {} constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {}
constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {} constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {}
@ -596,17 +639,20 @@ template <class T, class E>
struct expected_operations_base : expected_storage_base<T, E> { struct expected_operations_base : expected_storage_base<T, E> {
using expected_storage_base<T, E>::expected_storage_base; using expected_storage_base<T, E>::expected_storage_base;
template <class... Args> void construct(Args &&... args) noexcept { template<class... Args>
void construct(Args &&... args) noexcept {
new(std::addressof(this->m_val)) T(std::forward<Args>(args)...); new(std::addressof(this->m_val)) T(std::forward<Args>(args)...);
this->m_has_val = true; this->m_has_val = true;
} }
template <class Rhs> void construct_with(Rhs &&rhs) noexcept { template<class Rhs>
void construct_with(Rhs &&rhs) noexcept {
new(std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get()); new(std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get());
this->m_has_val = true; this->m_has_val = true;
} }
template <class... Args> void construct_error(Args &&... args) noexcept { template<class... Args>
void construct_error(Args &&... args) noexcept {
new(std::addressof(this->m_unexpect)) new(std::addressof(this->m_unexpect))
unexpected<E>(std::forward<Args>(args)...); unexpected<E>(std::forward<Args>(args)...);
this->m_has_val = false; this->m_has_val = false;
@ -728,7 +774,8 @@ struct expected_operations_base : expected_storage_base<T, E> {
#endif #endif
// The common part of move/copy assigning // The common part of move/copy assigning
template <class Rhs> void assign_common(Rhs &&rhs) { template<class Rhs>
void assign_common(Rhs &&rhs) {
if (this->m_has_val) { if (this->m_has_val) {
if (rhs.m_has_val) { if (rhs.m_has_val) {
get() = std::forward<Rhs>(rhs).get(); get() = std::forward<Rhs>(rhs).get();
@ -746,23 +793,33 @@ struct expected_operations_base : expected_storage_base<T, E> {
bool has_value() const { return this->m_has_val; } bool has_value() const { return this->m_has_val; }
TL_EXPECTED_11_CONSTEXPR T &get() &{ return this->m_val; } TL_EXPECTED_11_CONSTEXPR T &get() &{ return this->m_val; }
constexpr const T &get() const &{ return this->m_val; } constexpr const T &get() const &{ return this->m_val; }
TL_EXPECTED_11_CONSTEXPR T &&get() &&{ return std::move(this->m_val); } TL_EXPECTED_11_CONSTEXPR T &&get() &&{ return std::move(this->m_val); }
#ifndef TL_EXPECTED_NO_CONSTRR #ifndef TL_EXPECTED_NO_CONSTRR
constexpr const T &&get() const &&{ return std::move(this->m_val); } constexpr const T &&get() const &&{ return std::move(this->m_val); }
#endif #endif
TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &{ TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &{
return this->m_unexpect; return this->m_unexpect;
} }
constexpr const unexpected<E> &geterr() const &{ return this->m_unexpect; } constexpr const unexpected<E> &geterr() const &{ return this->m_unexpect; }
TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&{ TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&{
return std::move(this->m_unexpect); return std::move(this->m_unexpect);
} }
#ifndef TL_EXPECTED_NO_CONSTRR #ifndef TL_EXPECTED_NO_CONSTRR
constexpr const unexpected<E> &&geterr() const &&{ constexpr const unexpected<E> &&geterr() const &&{
return std::move(this->m_unexpect); return std::move(this->m_unexpect);
} }
#endif #endif
TL_EXPECTED_11_CONSTEXPR void destroy_val() { TL_EXPECTED_11_CONSTEXPR void destroy_val() {
@ -776,21 +833,25 @@ template <class E>
struct expected_operations_base<void, E> : expected_storage_base<void, E> { struct expected_operations_base<void, E> : expected_storage_base<void, E> {
using expected_storage_base<void, E>::expected_storage_base; using expected_storage_base<void, E>::expected_storage_base;
template <class... Args> void construct() noexcept { this->m_has_val = true; } template<class... Args>
void construct() noexcept { this->m_has_val = true; }
// This function doesn't use its argument, but needs it so that code in // This function doesn't use its argument, but needs it so that code in
// levels above this can work independently of whether T is void // levels above this can work independently of whether T is void
template <class Rhs> void construct_with(Rhs &&) noexcept { template<class Rhs>
void construct_with(Rhs &&) noexcept {
this->m_has_val = true; this->m_has_val = true;
} }
template <class... Args> void construct_error(Args &&... args) noexcept { template<class... Args>
void construct_error(Args &&... args) noexcept {
new(std::addressof(this->m_unexpect)) new(std::addressof(this->m_unexpect))
unexpected<E>(std::forward<Args>(args)...); unexpected<E>(std::forward<Args>(args)...);
this->m_has_val = false; this->m_has_val = false;
} }
template <class Rhs> void assign(Rhs &&rhs) noexcept { template<class Rhs>
void assign(Rhs &&rhs) noexcept {
if (!this->m_has_val) { if (!this->m_has_val) {
if (rhs.m_has_val) { if (rhs.m_has_val) {
geterr().~unexpected<E>(); geterr().~unexpected<E>();
@ -810,14 +871,19 @@ struct expected_operations_base<void, E> : expected_storage_base<void, E> {
TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &{ TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() &{
return this->m_unexpect; return this->m_unexpect;
} }
constexpr const unexpected<E> &geterr() const &{ return this->m_unexpect; } constexpr const unexpected<E> &geterr() const &{ return this->m_unexpect; }
TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&{ TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() &&{
return std::move(this->m_unexpect); return std::move(this->m_unexpect);
} }
#ifndef TL_EXPECTED_NO_CONSTRR #ifndef TL_EXPECTED_NO_CONSTRR
constexpr const unexpected<E> &&geterr() const &&{ constexpr const unexpected<E> &&geterr() const &&{
return std::move(this->m_unexpect); return std::move(this->m_unexpect);
} }
#endif #endif
TL_EXPECTED_11_CONSTEXPR void destroy_val() { TL_EXPECTED_11_CONSTEXPR void destroy_val() {
@ -840,6 +906,7 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
using expected_operations_base<T, E>::expected_operations_base; using expected_operations_base<T, E>::expected_operations_base;
expected_copy_base() = default; expected_copy_base() = default;
expected_copy_base(const expected_copy_base &rhs) expected_copy_base(const expected_copy_base &rhs)
: expected_operations_base<T, E>(no_init) { : expected_operations_base<T, E>(no_init) {
if (rhs.has_value()) { if (rhs.has_value()) {
@ -850,7 +917,9 @@ struct expected_copy_base<T, E, false> : expected_operations_base<T, E> {
} }
expected_copy_base(expected_copy_base &&rhs) = default; expected_copy_base(expected_copy_base &&rhs) = default;
expected_copy_base &operator=(const expected_copy_base &rhs) = default; expected_copy_base &operator=(const expected_copy_base &rhs) = default;
expected_copy_base &operator=(expected_copy_base &&rhs) = default; expected_copy_base &operator=(expected_copy_base &&rhs) = default;
}; };
@ -869,11 +938,13 @@ struct expected_move_base : expected_copy_base<T, E> {
#else #else
template <class T, class E, bool = false> struct expected_move_base; template <class T, class E, bool = false> struct expected_move_base;
#endif #endif
template<class T, class E> template<class T, class E>
struct expected_move_base<T, E, false> : expected_copy_base<T, E> { struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
using expected_copy_base<T, E>::expected_copy_base; using expected_copy_base<T, E>::expected_copy_base;
expected_move_base() = default; expected_move_base() = default;
expected_move_base(const expected_move_base &rhs) = default; expected_move_base(const expected_move_base &rhs) = default;
expected_move_base(expected_move_base &&rhs) noexcept( expected_move_base(expected_move_base &&rhs) noexcept(
@ -885,7 +956,9 @@ struct expected_move_base<T, E, false> : expected_copy_base<T, E> {
this->construct_error(std::move(rhs.geterr())); this->construct_error(std::move(rhs.geterr()));
} }
} }
expected_move_base &operator=(const expected_move_base &rhs) = default; expected_move_base &operator=(const expected_move_base &rhs) = default;
expected_move_base &operator=(expected_move_base &&rhs) = default; expected_move_base &operator=(expected_move_base &&rhs) = default;
}; };
@ -907,13 +980,16 @@ struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> {
using expected_move_base<T, E>::expected_move_base; using expected_move_base<T, E>::expected_move_base;
expected_copy_assign_base() = default; expected_copy_assign_base() = default;
expected_copy_assign_base(const expected_copy_assign_base &rhs) = default; expected_copy_assign_base(const expected_copy_assign_base &rhs) = default;
expected_copy_assign_base(expected_copy_assign_base &&rhs) = default; expected_copy_assign_base(expected_copy_assign_base &&rhs) = default;
expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) { expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) {
this->assign(rhs); this->assign(rhs);
return *this; return *this;
} }
expected_copy_assign_base & expected_copy_assign_base &
operator=(expected_copy_assign_base &&rhs) = default; operator=(expected_copy_assign_base &&rhs) = default;
}; };
@ -945,6 +1021,7 @@ struct expected_move_assign_base<T, E, false>
using expected_copy_assign_base<T, E>::expected_copy_assign_base; using expected_copy_assign_base<T, E>::expected_copy_assign_base;
expected_move_assign_base() = default; expected_move_assign_base() = default;
expected_move_assign_base(const expected_move_assign_base &rhs) = default; expected_move_assign_base(const expected_move_assign_base &rhs) = default;
expected_move_assign_base(expected_move_assign_base &&rhs) = default; expected_move_assign_base(expected_move_assign_base &&rhs) = default;
@ -970,10 +1047,14 @@ template <class T, class E,
std::is_move_constructible<E>::value)> std::is_move_constructible<E>::value)>
struct expected_delete_ctor_base { struct expected_delete_ctor_base {
expected_delete_ctor_base() = default; expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base &) = default; expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
expected_delete_ctor_base & expected_delete_ctor_base &
operator=(const expected_delete_ctor_base &) = default; operator=(const expected_delete_ctor_base &) = default;
expected_delete_ctor_base & expected_delete_ctor_base &
operator=(expected_delete_ctor_base &&) noexcept = default; operator=(expected_delete_ctor_base &&) noexcept = default;
}; };
@ -981,10 +1062,14 @@ struct expected_delete_ctor_base {
template<class T, class E> template<class T, class E>
struct expected_delete_ctor_base<T, E, true, false> { struct expected_delete_ctor_base<T, E, true, false> {
expected_delete_ctor_base() = default; expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base &) = default; expected_delete_ctor_base(const expected_delete_ctor_base &) = default;
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
expected_delete_ctor_base & expected_delete_ctor_base &
operator=(const expected_delete_ctor_base &) = default; operator=(const expected_delete_ctor_base &) = default;
expected_delete_ctor_base & expected_delete_ctor_base &
operator=(expected_delete_ctor_base &&) noexcept = default; operator=(expected_delete_ctor_base &&) noexcept = default;
}; };
@ -992,10 +1077,14 @@ struct expected_delete_ctor_base<T, E, true, false> {
template<class T, class E> template<class T, class E>
struct expected_delete_ctor_base<T, E, false, true> { struct expected_delete_ctor_base<T, E, false, true> {
expected_delete_ctor_base() = default; expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default;
expected_delete_ctor_base & expected_delete_ctor_base &
operator=(const expected_delete_ctor_base &) = default; operator=(const expected_delete_ctor_base &) = default;
expected_delete_ctor_base & expected_delete_ctor_base &
operator=(expected_delete_ctor_base &&) noexcept = default; operator=(expected_delete_ctor_base &&) noexcept = default;
}; };
@ -1003,10 +1092,14 @@ struct expected_delete_ctor_base<T, E, false, true> {
template<class T, class E> template<class T, class E>
struct expected_delete_ctor_base<T, E, false, false> { struct expected_delete_ctor_base<T, E, false, false> {
expected_delete_ctor_base() = default; expected_delete_ctor_base() = default;
expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; expected_delete_ctor_base(const expected_delete_ctor_base &) = delete;
expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete;
expected_delete_ctor_base & expected_delete_ctor_base &
operator=(const expected_delete_ctor_base &) = default; operator=(const expected_delete_ctor_base &) = default;
expected_delete_ctor_base & expected_delete_ctor_base &
operator=(expected_delete_ctor_base &&) noexcept = default; operator=(expected_delete_ctor_base &&) noexcept = default;
}; };
@ -1025,11 +1118,15 @@ template <class T, class E,
std::is_move_assignable<E>::value)> std::is_move_assignable<E>::value)>
struct expected_delete_assign_base { struct expected_delete_assign_base {
expected_delete_assign_base() = default; expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base &) = default; expected_delete_assign_base(const expected_delete_assign_base &) = default;
expected_delete_assign_base(expected_delete_assign_base &&) noexcept = expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
default; default;
expected_delete_assign_base & expected_delete_assign_base &
operator=(const expected_delete_assign_base &) = default; operator=(const expected_delete_assign_base &) = default;
expected_delete_assign_base & expected_delete_assign_base &
operator=(expected_delete_assign_base &&) noexcept = default; operator=(expected_delete_assign_base &&) noexcept = default;
}; };
@ -1037,11 +1134,15 @@ struct expected_delete_assign_base {
template<class T, class E> template<class T, class E>
struct expected_delete_assign_base<T, E, true, false> { struct expected_delete_assign_base<T, E, true, false> {
expected_delete_assign_base() = default; expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base &) = default; expected_delete_assign_base(const expected_delete_assign_base &) = default;
expected_delete_assign_base(expected_delete_assign_base &&) noexcept = expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
default; default;
expected_delete_assign_base & expected_delete_assign_base &
operator=(const expected_delete_assign_base &) = default; operator=(const expected_delete_assign_base &) = default;
expected_delete_assign_base & expected_delete_assign_base &
operator=(expected_delete_assign_base &&) noexcept = delete; operator=(expected_delete_assign_base &&) noexcept = delete;
}; };
@ -1049,11 +1150,15 @@ struct expected_delete_assign_base<T, E, true, false> {
template<class T, class E> template<class T, class E>
struct expected_delete_assign_base<T, E, false, true> { struct expected_delete_assign_base<T, E, false, true> {
expected_delete_assign_base() = default; expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base &) = default; expected_delete_assign_base(const expected_delete_assign_base &) = default;
expected_delete_assign_base(expected_delete_assign_base &&) noexcept = expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
default; default;
expected_delete_assign_base & expected_delete_assign_base &
operator=(const expected_delete_assign_base &) = delete; operator=(const expected_delete_assign_base &) = delete;
expected_delete_assign_base & expected_delete_assign_base &
operator=(expected_delete_assign_base &&) noexcept = default; operator=(expected_delete_assign_base &&) noexcept = default;
}; };
@ -1061,11 +1166,15 @@ struct expected_delete_assign_base<T, E, false, true> {
template<class T, class E> template<class T, class E>
struct expected_delete_assign_base<T, E, false, false> { struct expected_delete_assign_base<T, E, false, false> {
expected_delete_assign_base() = default; expected_delete_assign_base() = default;
expected_delete_assign_base(const expected_delete_assign_base &) = default; expected_delete_assign_base(const expected_delete_assign_base &) = default;
expected_delete_assign_base(expected_delete_assign_base &&) noexcept = expected_delete_assign_base(expected_delete_assign_base &&) noexcept =
default; default;
expected_delete_assign_base & expected_delete_assign_base &
operator=(const expected_delete_assign_base &) = delete; operator=(const expected_delete_assign_base &) = delete;
expected_delete_assign_base & expected_delete_assign_base &
operator=(expected_delete_assign_base &&) noexcept = delete; operator=(expected_delete_assign_base &&) noexcept = delete;
}; };
@ -1084,12 +1193,16 @@ template <class T, class E,
std::is_default_constructible<T>::value || std::is_void<T>::value> std::is_default_constructible<T>::value || std::is_void<T>::value>
struct expected_default_ctor_base { struct expected_default_ctor_base {
constexpr expected_default_ctor_base() noexcept = default; constexpr expected_default_ctor_base() noexcept = default;
constexpr expected_default_ctor_base( constexpr expected_default_ctor_base(
expected_default_ctor_base const &) noexcept = default; expected_default_ctor_base const &) noexcept = default;
constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
default; default;
expected_default_ctor_base & expected_default_ctor_base &
operator=(expected_default_ctor_base const &) noexcept = default; operator=(expected_default_ctor_base const &) noexcept = default;
expected_default_ctor_base & expected_default_ctor_base &
operator=(expected_default_ctor_base &&) noexcept = default; operator=(expected_default_ctor_base &&) noexcept = default;
@ -1097,14 +1210,19 @@ struct expected_default_ctor_base {
}; };
// This specialization is for when T is not default constructible // This specialization is for when T is not default constructible
template <class T, class E> struct expected_default_ctor_base<T, E, false> { template<class T, class E>
struct expected_default_ctor_base<T, E, false> {
constexpr expected_default_ctor_base() noexcept = delete; constexpr expected_default_ctor_base() noexcept = delete;
constexpr expected_default_ctor_base( constexpr expected_default_ctor_base(
expected_default_ctor_base const &) noexcept = default; expected_default_ctor_base const &) noexcept = default;
constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept =
default; default;
expected_default_ctor_base & expected_default_ctor_base &
operator=(expected_default_ctor_base const &) noexcept = default; operator=(expected_default_ctor_base const &) noexcept = default;
expected_default_ctor_base & expected_default_ctor_base &
operator=(expected_default_ctor_base &&) noexcept = default; operator=(expected_default_ctor_base &&) noexcept = default;
@ -1112,7 +1230,8 @@ template <class T, class E> struct expected_default_ctor_base<T, E, false> {
}; };
} // namespace detail } // namespace detail
template <class E> class bad_expected_access : public std::exception { template<class E>
class bad_expected_access : public std::exception {
public: public:
explicit bad_expected_access(E e) : m_val(std::move(e)) {} explicit bad_expected_access(E e) : m_val(std::move(e)) {}
@ -1121,8 +1240,11 @@ public:
} }
const E &error() const &{ return m_val; } const E &error() const &{ return m_val; }
E &error() &{ return m_val; } E &error() &{ return m_val; }
const E &&error() const &&{ return std::move(m_val); } const E &&error() const &&{ return std::move(m_val); }
E &&error() &&{ return std::move(m_val); } E &&error() &&{ return std::move(m_val); }
private: private:
@ -1151,8 +1273,11 @@ class expected : private detail::expected_move_assign_base<T, E>,
static_assert(!std::is_reference<E>::value, "E must not be a reference"); static_assert(!std::is_reference<E>::value, "E must not be a reference");
T *valptr() { return std::addressof(this->m_val); } T *valptr() { return std::addressof(this->m_val); }
const T *valptr() const { return std::addressof(this->m_val); } const T *valptr() const { return std::addressof(this->m_val); }
unexpected<E> *errptr() { return std::addressof(this->m_unexpect); } unexpected<E> *errptr() { return std::addressof(this->m_unexpect); }
const unexpected<E> *errptr() const { return std::addressof(this->m_unexpect); } const unexpected<E> *errptr() const { return std::addressof(this->m_unexpect); }
template<class U = T, template<class U = T,
@ -1160,6 +1285,7 @@ class expected : private detail::expected_move_assign_base<T, E>,
U &val() { U &val() {
return this->m_val; return this->m_val;
} }
unexpected<E> &err() { return this->m_unexpect; } unexpected<E> &err() { return this->m_unexpect; }
template<class U = T, template<class U = T,
@ -1167,6 +1293,7 @@ class expected : private detail::expected_move_assign_base<T, E>,
const U &val() const { const U &val() const {
return this->m_val; return this->m_val;
} }
const unexpected<E> &err() const { return this->m_unexpect; } const unexpected<E> &err() const { return this->m_unexpect; }
using impl_base = detail::expected_move_assign_base<T, E>; using impl_base = detail::expected_move_assign_base<T, E>;
@ -1179,6 +1306,7 @@ public:
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
/// \group and_then /// \group and_then
/// Carries out some operation which returns an expected on the stored object /// Carries out some operation which returns an expected on the stored object
/// if there is one. \requires `std::invoke(std::forward<F>(f), value())` /// if there is one. \requires `std::invoke(std::forward<F>(f), value())`
@ -1188,28 +1316,34 @@ public:
/// otherwise the return value of `std::invoke(std::forward<F>(f), value())` /// otherwise the return value of `std::invoke(std::forward<F>(f), value())`
/// is returned. /// is returned.
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & { template<class F>
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &{
return and_then_impl(*this, std::forward<F>(f)); return and_then_impl(*this, std::forward<F>(f));
} }
/// \group and_then /// \group and_then
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && { template<class F>
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) &&{
return and_then_impl(std::move(*this), std::forward<F>(f)); return and_then_impl(std::move(*this), std::forward<F>(f));
} }
/// \group and_then /// \group and_then
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
template <class F> constexpr auto and_then(F &&f) const & { template<class F>
constexpr auto and_then(F &&f) const &{
return and_then_impl(*this, std::forward<F>(f)); return and_then_impl(*this, std::forward<F>(f));
} }
#ifndef TL_EXPECTED_NO_CONSTRR #ifndef TL_EXPECTED_NO_CONSTRR
/// \group and_then /// \group and_then
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
template <class F> constexpr auto and_then(F &&f) const && { template<class F>
constexpr auto and_then(F &&f) const &&{
return and_then_impl(std::move(*this), std::forward<F>(f)); return and_then_impl(std::move(*this), std::forward<F>(f));
} }
#endif #endif
#else #else
@ -1257,6 +1391,7 @@ public:
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
/// \brief Carries out some operation on the stored object if there is one. /// \brief Carries out some operation on the stored object if there is one.
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
/// value())`. If `U` is `void`, returns an `expected<monostate,E>, otherwise /// value())`. If `U` is `void`, returns an `expected<monostate,E>, otherwise
@ -1267,27 +1402,32 @@ public:
/// ///
/// \group map /// \group map
/// \synopsis template <class F> constexpr auto map(F &&f) &; /// \synopsis template <class F> constexpr auto map(F &&f) &;
template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & { template<class F>
TL_EXPECTED_11_CONSTEXPR auto map(F &&f) &{
return expected_map_impl(*this, std::forward<F>(f)); return expected_map_impl(*this, std::forward<F>(f));
} }
/// \group map /// \group map
/// \synopsis template <class F> constexpr auto map(F &&f) &&; /// \synopsis template <class F> constexpr auto map(F &&f) &&;
template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && { template<class F>
TL_EXPECTED_11_CONSTEXPR auto map(F &&f) &&{
return expected_map_impl(std::move(*this), std::forward<F>(f)); return expected_map_impl(std::move(*this), std::forward<F>(f));
} }
/// \group map /// \group map
/// \synopsis template <class F> constexpr auto map(F &&f) const &; /// \synopsis template <class F> constexpr auto map(F &&f) const &;
template <class F> constexpr auto map(F &&f) const & { template<class F>
constexpr auto map(F &&f) const &{
return expected_map_impl(*this, std::forward<F>(f)); return expected_map_impl(*this, std::forward<F>(f));
} }
/// \group map /// \group map
/// \synopsis template <class F> constexpr auto map(F &&f) const &&; /// \synopsis template <class F> constexpr auto map(F &&f) const &&;
template <class F> constexpr auto map(F &&f) const && { template<class F>
constexpr auto map(F &&f) const &&{
return expected_map_impl(std::move(*this), std::forward<F>(f)); return expected_map_impl(std::move(*this), std::forward<F>(f));
} }
#else #else
/// \brief Carries out some operation on the stored object if there is one. /// \brief Carries out some operation on the stored object if there is one.
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
@ -1338,6 +1478,7 @@ public:
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
/// \brief Carries out some operation on the stored unexpected object if there /// \brief Carries out some operation on the stored unexpected object if there
/// is one. /// is one.
/// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f),
@ -1349,27 +1490,32 @@ public:
/// ///
/// \group map_error /// \group map_error
/// \synopsis template <class F> constexpr auto map_error(F &&f) &; /// \synopsis template <class F> constexpr auto map_error(F &&f) &;
template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & { template<class F>
TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) &{
return map_error_impl(*this, std::forward<F>(f)); return map_error_impl(*this, std::forward<F>(f));
} }
/// \group map_error /// \group map_error
/// \synopsis template <class F> constexpr auto map_error(F &&f) &&; /// \synopsis template <class F> constexpr auto map_error(F &&f) &&;
template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && { template<class F>
TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) &&{
return map_error_impl(std::move(*this), std::forward<F>(f)); return map_error_impl(std::move(*this), std::forward<F>(f));
} }
/// \group map_error /// \group map_error
/// \synopsis template <class F> constexpr auto map_error(F &&f) const &; /// \synopsis template <class F> constexpr auto map_error(F &&f) const &;
template <class F> constexpr auto map_error(F &&f) const & { template<class F>
constexpr auto map_error(F &&f) const &{
return map_error_impl(*this, std::forward<F>(f)); return map_error_impl(*this, std::forward<F>(f));
} }
/// \group map_error /// \group map_error
/// \synopsis template <class F> constexpr auto map_error(F &&f) const &&; /// \synopsis template <class F> constexpr auto map_error(F &&f) const &&;
template <class F> constexpr auto map_error(F &&f) const && { template<class F>
constexpr auto map_error(F &&f) const &&{
return map_error_impl(std::move(*this), std::forward<F>(f)); return map_error_impl(std::move(*this), std::forward<F>(f));
} }
#else #else
/// \brief Carries out some operation on the stored unexpected object if there /// \brief Carries out some operation on the stored unexpected object if there
/// is one. /// is one.
@ -1426,27 +1572,38 @@ public:
/// `std::nullopt`. Otherwise, returns `std::forward<F>(f)(E)`. /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)(E)`.
/// ///
/// \group or_else /// \group or_else
template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & { template<class F>
expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &{
return or_else_impl(*this, std::forward<F>(f)); return or_else_impl(*this, std::forward<F>(f));
} }
template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && { template<class F>
expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) &&{
return or_else_impl(std::move(*this), std::forward<F>(f)); return or_else_impl(std::move(*this), std::forward<F>(f));
} }
template <class F> expected constexpr or_else(F &&f) const & { template<class F>
expected constexpr or_else(F &&f) const &{
return or_else_impl(*this, std::forward<F>(f)); return or_else_impl(*this, std::forward<F>(f));
} }
#ifndef TL_EXPECTED_NO_CONSTRR #ifndef TL_EXPECTED_NO_CONSTRR
template <class F> expected constexpr or_else(F &&f) const && {
template<class F>
expected constexpr or_else(F &&f) const &&{
return or_else_impl(std::move(*this), std::forward<F>(f)); return or_else_impl(std::move(*this), std::forward<F>(f));
} }
#endif #endif
constexpr expected() = default; constexpr expected() = default;
constexpr expected(const expected &rhs) = default; constexpr expected(const expected &rhs) = default;
constexpr expected(expected &&rhs) = default; constexpr expected(expected &&rhs) = default;
expected &operator=(const expected &rhs) = default; expected &operator=(const expected &rhs) = default;
expected &operator=(expected &&rhs) = default; expected &operator=(expected &&rhs) = default;
template<class... Args, template<class... Args,
@ -1805,18 +1962,21 @@ public:
constexpr const U &operator*() const &{ constexpr const U &operator*() const &{
return val(); return val();
} }
/// \group deref /// \group deref
template<class U = T, template<class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr> detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
TL_EXPECTED_11_CONSTEXPR U &operator*() &{ TL_EXPECTED_11_CONSTEXPR U &operator*() &{
return val(); return val();
} }
/// \group deref /// \group deref
template<class U = T, template<class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr> detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
constexpr const U &&operator*() const &&{ constexpr const U &&operator*() const &&{
return std::move(val()); return std::move(val());
} }
/// \group deref /// \group deref
template<class U = T, template<class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr> detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
@ -1827,6 +1987,7 @@ public:
/// \returns whether or not the optional has a value /// \returns whether or not the optional has a value
/// \group has_value /// \group has_value
constexpr bool has_value() const noexcept { return this->m_has_val; } constexpr bool has_value() const noexcept { return this->m_has_val; }
/// \group has_value /// \group has_value
constexpr explicit operator bool() const noexcept { return this->m_has_val; } constexpr explicit operator bool() const noexcept { return this->m_has_val; }
@ -1841,6 +2002,7 @@ public:
detail::throw_exception(bad_expected_access<E>(err().value())); detail::throw_exception(bad_expected_access<E>(err().value()));
return val(); return val();
} }
/// \group value /// \group value
template<class U = T, template<class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr> detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
@ -1849,6 +2011,7 @@ public:
detail::throw_exception(bad_expected_access<E>(err().value())); detail::throw_exception(bad_expected_access<E>(err().value()));
return val(); return val();
} }
/// \group value /// \group value
template<class U = T, template<class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr> detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
@ -1857,6 +2020,7 @@ public:
detail::throw_exception(bad_expected_access<E>(err().value())); detail::throw_exception(bad_expected_access<E>(err().value()));
return std::move(val()); return std::move(val());
} }
/// \group value /// \group value
template<class U = T, template<class U = T,
detail::enable_if_t<!std::is_void<U>::value> * = nullptr> detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
@ -1872,6 +2036,7 @@ public:
constexpr const E &error() const &{ return err().value(); } constexpr const E &error() const &{ return err().value(); }
/// \group error /// \group error
TL_EXPECTED_11_CONSTEXPR E &error() &{ return err().value(); } TL_EXPECTED_11_CONSTEXPR E &error() &{ return err().value(); }
/// \group error /// \group error
constexpr const E &&error() const &&{ return std::move(err().value()); } constexpr const E &&error() const &&{ return std::move(err().value()); }
/// \group error /// \group error
@ -1879,14 +2044,17 @@ public:
/// \returns the stored value if there is one, otherwise returns `u` /// \returns the stored value if there is one, otherwise returns `u`
/// \group value_or /// \group value_or
template <class U> constexpr T value_or(U &&v) const & { template<class U>
constexpr T value_or(U &&v) const &{
static_assert(std::is_copy_constructible<T>::value && static_assert(std::is_copy_constructible<T>::value &&
std::is_convertible<U &&, T>::value, std::is_convertible<U &&, T>::value,
"T must be copy-constructible and convertible to from U&&"); "T must be copy-constructible and convertible to from U&&");
return bool(*this) ? **this : static_cast<T>(std::forward<U>(v)); return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
} }
/// \group value_or /// \group value_or
template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && { template<class U>
TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) &&{
static_assert(std::is_move_constructible<T>::value && static_assert(std::is_move_constructible<T>::value &&
std::is_convertible<U &&, T>::value, std::is_convertible<U &&, T>::value,
"T must be move-constructible and convertible to from U&&"); "T must be move-constructible and convertible to from U&&");
@ -1901,6 +2069,7 @@ template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type;
template<class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>; template<class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>;
#ifdef TL_EXPECTED_CXX14 #ifdef TL_EXPECTED_CXX14
template<class Exp, class F, template<class Exp, class F,
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(), class Ret = decltype(detail::invoke(std::declval<F>(),
@ -1922,6 +2091,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) {
return exp.has_value() ? detail::invoke(std::forward<F>(f)) return exp.has_value() ? detail::invoke(std::forward<F>(f))
: Ret(unexpect, std::forward<Exp>(exp).error()); : Ret(unexpect, std::forward<Exp>(exp).error());
} }
#else #else
template <class> struct TC; template <class> struct TC;
template <class Exp, class F, template <class Exp, class F,
@ -1948,6 +2118,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
#endif #endif
#ifdef TL_EXPECTED_CXX14 #ifdef TL_EXPECTED_CXX14
template<class Exp, class F, template<class Exp, class F,
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(), class Ret = decltype(detail::invoke(std::declval<F>(),
@ -1998,6 +2169,7 @@ auto expected_map_impl(Exp &&exp, F &&f) {
return result(unexpect, std::forward<Exp>(exp).error()); return result(unexpect, std::forward<Exp>(exp).error());
} }
#else #else
template <class Exp, class F, template <class Exp, class F,
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
@ -2059,6 +2231,7 @@ auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> {
#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ #if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \
!defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55)
template<class Exp, class F, template<class Exp, class F,
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(), class Ret = decltype(detail::invoke(std::declval<F>(),
@ -2071,6 +2244,7 @@ constexpr auto map_error_impl(Exp &&exp, F &&f) {
: result(unexpect, detail::invoke(std::forward<F>(f), : result(unexpect, detail::invoke(std::forward<F>(f),
std::forward<Exp>(exp).error())); std::forward<Exp>(exp).error()));
} }
template<class Exp, class F, template<class Exp, class F,
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(), class Ret = decltype(detail::invoke(std::declval<F>(),
@ -2085,6 +2259,7 @@ auto map_error_impl(Exp &&exp, F &&f) {
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()); detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
return result(unexpect, monostate{}); return result(unexpect, monostate{});
} }
template<class Exp, class F, template<class Exp, class F,
detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(), class Ret = decltype(detail::invoke(std::declval<F>(),
@ -2097,6 +2272,7 @@ constexpr auto map_error_impl(Exp &&exp, F &&f) {
: result(unexpect, detail::invoke(std::forward<F>(f), : result(unexpect, detail::invoke(std::forward<F>(f),
std::forward<Exp>(exp).error())); std::forward<Exp>(exp).error()));
} }
template<class Exp, class F, template<class Exp, class F,
detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr,
class Ret = decltype(detail::invoke(std::declval<F>(), class Ret = decltype(detail::invoke(std::declval<F>(),
@ -2111,6 +2287,7 @@ auto map_error_impl(Exp &&exp, F &&f) {
detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()); detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error());
return result(unexpect, monostate{}); return result(unexpect, monostate{});
} }
#else #else
template <class Exp, class F, template <class Exp, class F,
detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr,
@ -2174,6 +2351,7 @@ auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> {
#endif #endif
#ifdef TL_EXPECTED_CXX14 #ifdef TL_EXPECTED_CXX14
template<class Exp, class F, template<class Exp, class F,
class Ret = decltype(detail::invoke(std::declval<F>(), class Ret = decltype(detail::invoke(std::declval<F>(),
std::declval<Exp>().error())), std::declval<Exp>().error())),
@ -2195,6 +2373,7 @@ detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) {
: (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()), : (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()),
std::forward<Exp>(exp)); std::forward<Exp>(exp));
} }
#else #else
template <class Exp, class F, template <class Exp, class F,
class Ret = decltype(detail::invoke(std::declval<F>(), class Ret = decltype(detail::invoke(std::declval<F>(),
@ -2227,6 +2406,7 @@ constexpr bool operator==(const expected<T, E> &lhs,
? false ? false
: (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs); : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs);
} }
template<class T, class E, class U, class F> template<class T, class E, class U, class F>
constexpr bool operator!=(const expected<T, E> &lhs, constexpr bool operator!=(const expected<T, E> &lhs,
const expected<U, F> &rhs) { const expected<U, F> &rhs) {
@ -2239,14 +2419,17 @@ template <class T, class E, class U>
constexpr bool operator==(const expected<T, E> &x, const U &v) { constexpr bool operator==(const expected<T, E> &x, const U &v) {
return x.has_value() ? *x == v : false; return x.has_value() ? *x == v : false;
} }
template<class T, class E, class U> template<class T, class E, class U>
constexpr bool operator==(const U &v, const expected<T, E> &x) { constexpr bool operator==(const U &v, const expected<T, E> &x) {
return x.has_value() ? *x == v : false; return x.has_value() ? *x == v : false;
} }
template<class T, class E, class U> template<class T, class E, class U>
constexpr bool operator!=(const expected<T, E> &x, const U &v) { constexpr bool operator!=(const expected<T, E> &x, const U &v) {
return x.has_value() ? *x != v : true; return x.has_value() ? *x != v : true;
} }
template<class T, class E, class U> template<class T, class E, class U>
constexpr bool operator!=(const U &v, const expected<T, E> &x) { constexpr bool operator!=(const U &v, const expected<T, E> &x) {
return x.has_value() ? *x != v : true; return x.has_value() ? *x != v : true;
@ -2256,14 +2439,17 @@ template <class T, class E>
constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) { constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) {
return x.has_value() ? false : x.error() == e.value(); return x.has_value() ? false : x.error() == e.value();
} }
template<class T, class E> template<class T, class E>
constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) { constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) {
return x.has_value() ? false : x.error() == e.value(); return x.has_value() ? false : x.error() == e.value();
} }
template<class T, class E> template<class T, class E>
constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) { constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) {
return x.has_value() ? true : x.error() != e.value(); return x.has_value() ? true : x.error() != e.value();
} }
template<class T, class E> template<class T, class E>
constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) { constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) {
return x.has_value() ? true : x.error() != e.value(); return x.has_value() ? true : x.error() != e.value();

View File

@ -1,4 +1,4 @@
#include "parsecontext.h" #include "parse_context.h"
#include "assert.h" #include "assert.h"
#include <iostream> #include <iostream>
@ -6,26 +6,24 @@
#include <cmath> #include <cmath>
ParseContext::ParseContext() ParseContext::ParseContext() {
{
applicationDir = std::string(); applicationDir = std::string();
} }
unsigned ParseContext::addFile(const std::string &fileName, unsigned ParseContext::addFile(const std::string &fileName,
const std::string& source) const std::string &source) {
{ fileMap.emplace_back(fileName, source);
fileMap.push_back(SourceFile(fileName, source));
return fileMap.size(); return fileMap.size();
} }
SourceFile& ParseContext::getFile(unsigned fileId) SourceFile &ParseContext::getFile(unsigned fileId) {
{
return fileMap[fileId - 1]; return fileMap[fileId - 1];
} }
struct pad { struct pad {
char ch; int count; char ch;
int count;
pad(char ch, int count) : ch(ch), count(count) {} pad(char ch, int count) : ch(ch), count(count) {}
}; };
@ -42,14 +40,11 @@ std::ostream& operator<<(std::ostream& stream, const pad& p) {
void ParseContext::formatError(const SourceError &sourceError, void ParseContext::formatError(const SourceError &sourceError,
std::ostream &stream, std::ostream &stream,
const std::string& ErrorOrWarning) const std::string &errorOrWarning) {
{
ATLAS_ASSERT(sourceError.span.lo.col != 0 ATLAS_ASSERT(sourceError.span.lo.col != 0
&& sourceError.span.hi.col != 0); && sourceError.span.hi.col != 0);
SourceFile sourceFile = getFile(sourceError.span.lo.fileId); stream << errorOrWarning << sourceError.message << std::endl;
stream << ErrorOrWarning << sourceError.message << std::endl;
Span span = sourceError.span; Span span = sourceError.span;
@ -100,20 +95,16 @@ void ParseContext::formatError(const SourceError& sourceError,
} }
SourceFile::SourceFile(std::string fileName, std::string source) SourceFile::SourceFile(std::string fileName, std::string source)
: fileName(std::move(fileName)), source(std::move(source)) : fileName(std::move(fileName)), source(std::move(source)) {
{
lineOffsets.push_back(0); lineOffsets.push_back(0);
} }
const std::string& SourceFile::getFileName() const const std::string &SourceFile::getFileName() const {
{
return fileName; return fileName;
} }
const std::string SourceFile::getLine(unsigned line) const std::string SourceFile::getLine(unsigned line) const {
{
auto lineOffset = lineOffsets[line - 1]; auto lineOffset = lineOffsets[line - 1];
auto nextLF = source.find('\n', lineOffset); auto nextLF = source.find('\n', lineOffset);
auto nextCR = source.find('\r', lineOffset); auto nextCR = source.find('\r', lineOffset);
@ -122,7 +113,6 @@ const std::string SourceFile::getLine(unsigned line) const
return source.substr(lineOffset, nl - lineOffset); return source.substr(lineOffset, nl - lineOffset);
} }
void SourceFile::addLineOffset(unsigned offset) void SourceFile::addLineOffset(unsigned offset) {
{
lineOffsets.push_back(offset); lineOffsets.push_back(offset);
} }

View File

@ -2,30 +2,29 @@
#define PARSE_CONTEXT_H #define PARSE_CONTEXT_H
#include "sourceerror.h" #include "source_error.h"
#include <string> #include <string>
#include <vector> #include <vector>
/*** Represent source file */
class SourceFile { class SourceFile {
std::string fileName; std::string fileName;
std::string source; std::string source;
std::vector<unsigned> lineOffsets; std::vector<unsigned> lineOffsets;
public: public:
// qqq source je CIJELI comdel fajl,
// za inicijalizaciju source se koristi std::move, a možda treba biti referenca???
SourceFile(std::string fileName, std::string source); SourceFile(std::string fileName, std::string source);
const std::string &getFileName() const; const std::string &getFileName() const;
const std::string getLine(unsigned line) const;
std::string getLine(unsigned line) const;
void addLineOffset(unsigned offset); void addLineOffset(unsigned offset);
}; };
/*** Represent parsing context */
class ParseContext class ParseContext {
{
std::string applicationDir; std::string applicationDir;
std::vector<SourceFile> fileMap; std::vector<SourceFile> fileMap;
@ -33,9 +32,10 @@ public:
ParseContext(); ParseContext();
unsigned addFile(const std::string &fileName, const std::string &source); unsigned addFile(const std::string &fileName, const std::string &source);
SourceFile &getFile(unsigned file); SourceFile &getFile(unsigned file);
void formatError(const SourceError &sourceError, std::ostream &stream, const std::string& ErrorOrWarning); void formatError(const SourceError &sourceError, std::ostream &stream, const std::string &errorOrWarning);
}; };

View File

@ -1,16 +1,15 @@
#include "comdellexer.h" #include "comdel_lexer.h"
#include "comdelparser.h" #include "comdel_parser.h"
#include "parserutil.h" #include "parser_util.h"
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <QDir> #include <QDir>
std::optional<LibraryNode> loadLibraryFromFile(ParseContext * parseContext, std::optional<LibraryNode> load_library_from_file(ParseContext *parseContext,
const char *name, const char *name,
std::ostream& stream) std::ostream &stream) {
{
std::ifstream in(name, std::ios::in | std::ios::binary); std::ifstream in(name, std::ios::in | std::ios::binary);
if (!in) { if (!in) {
stream << "ERROR: cannot open file '" << name stream << "ERROR: cannot open file '" << name
@ -23,15 +22,15 @@ std::optional<LibraryNode> loadLibraryFromFile(ParseContext * parseContext,
ComdelLexer lexer(name, source, parseContext); ComdelLexer lexer(name, source, parseContext);
LexerResult lexerResult = lexer.tokenize(); LexerResult lexerResult = lexer.tokenize();
if (lexerResult.errors.size()) { if (!lexerResult.errors.empty()) {
for (auto &error: lexerResult.errors) { for (auto &error: lexerResult.errors) {
parseContext->formatError(error, stream, "ERROR: "); parseContext->formatError(error, stream, "ERROR: ");
} }
return std::nullopt; // if lexer has found errors => don't parse return std::nullopt; // if lexer has found errors => don't parseLibrary
} }
ComdelParser parser(lexerResult.tokens); ComdelParser parser(lexerResult.tokens);
auto unit = parser.parse(); auto unit = parser.parseLibrary();
if (!unit) { if (!unit) {
for (auto &error: parser.getErrors()) { for (auto &error: parser.getErrors()) {
parseContext->formatError(error, stream, "ERROR: "); parseContext->formatError(error, stream, "ERROR: ");
@ -43,10 +42,9 @@ std::optional<LibraryNode> loadLibraryFromFile(ParseContext * parseContext,
} }
std::optional<SchemaNode> loadSchemaFromFile(ParseContext * parseContext, std::optional<SchemaNode> load_schema_from_file(ParseContext *parseContext,
const char *name, const char *name,
std::ostream& stream) std::ostream &stream) {
{
std::ifstream in(name, std::ios::in | std::ios::binary); std::ifstream in(name, std::ios::in | std::ios::binary);
if (!in) { if (!in) {
stream << "ERROR: cannot open file '" << name stream << "ERROR: cannot open file '" << name
@ -59,11 +57,11 @@ std::optional<SchemaNode> loadSchemaFromFile(ParseContext * parseContext,
ComdelLexer lexer(name, source, parseContext); ComdelLexer lexer(name, source, parseContext);
LexerResult lexerResult = lexer.tokenize(); LexerResult lexerResult = lexer.tokenize();
if (lexerResult.errors.size()) { if (!lexerResult.errors.empty()) {
for (auto &error: lexerResult.errors) { for (auto &error: lexerResult.errors) {
parseContext->formatError(error, stream, "ERROR: "); parseContext->formatError(error, stream, "ERROR: ");
} }
return std::nullopt; // if lexer has found errors => don't parse return std::nullopt; // if lexer has found errors => don't parseLibrary
} }
ComdelParser parser(lexerResult.tokens); ComdelParser parser(lexerResult.tokens);
@ -78,12 +76,12 @@ std::optional<SchemaNode> loadSchemaFromFile(ParseContext * parseContext,
if (unit->source) { if (unit->source) {
QFileInfo info(name); QFileInfo info(name);
auto filepath = info.absolutePath(); auto filepath = info.absolutePath();
QDir dir; QDir::setCurrent(filepath);
dir.setCurrent(filepath);
QDir dir;
auto libraryPath = dir.absoluteFilePath(QString::fromStdString(unit->source->asString())); auto libraryPath = dir.absoluteFilePath(QString::fromStdString(unit->source->asString()));
unit->library = loadLibraryFromFile(parseContext, libraryPath.toUtf8().data(), stream); unit->library = load_library_from_file(parseContext, libraryPath.toUtf8().data(), stream);
if (unit->library == std::nullopt) { if (unit->library == std::nullopt) {
return std::nullopt; return std::nullopt;
} }

View File

@ -0,0 +1,15 @@
#ifndef PARSER_UTIL_H
#define PARSER_UTIL_H
#include "ast_nodes.h"
#include "parse_context.h"
std::optional<LibraryNode> load_library_from_file(ParseContext *parseContext,
const char *name,
std::ostream &stream);
std::optional<SchemaNode> load_schema_from_file(ParseContext *parseContext,
const char *name,
std::ostream &stream);
#endif // PARSER_UTIL_H

View File

@ -1,15 +0,0 @@
#ifndef PARSER_UTIL_H
#define PARSER_UTIL_H
#include "astnode.h"
#include "parsecontext.h"
std::optional<LibraryNode> loadLibraryFromFile(ParseContext * parseContext,
const char* name,
std::ostream& stream);
std::optional<SchemaNode> loadSchemaFromFile(ParseContext * parseContext,
const char* name,
std::ostream& stream);
#endif // PARSERUTIL_H

View File

@ -30,34 +30,28 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <type_traits> #include <type_traits>
#include <typeinfo> #include <typeinfo>
namespace detail namespace detail {
{
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Implementation detail classes // Implementation detail classes
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
template<class T> template<class T>
struct default_copy struct default_copy {
{ T *operator()(const T &t) const {
T* operator()(const T& t) const
{
return new T(t); return new T(t);
} }
}; };
template<class T> template<class T>
struct default_delete struct default_delete {
{ void operator()(const T *t) const {
void operator()(const T* t) const
{
delete t; delete t;
} }
}; };
template<class T> template<class T>
struct control_block struct control_block {
{
virtual ~control_block() = default; virtual ~control_block() = default;
virtual std::unique_ptr<control_block> clone() const = 0; virtual std::unique_ptr<control_block> clone() const = 0;
@ -66,76 +60,63 @@ namespace detail
}; };
template<class T, class U = T> template<class T, class U = T>
class direct_control_block : public control_block<T> class direct_control_block : public control_block<T> {
{
static_assert(!std::is_reference<U>::value, ""); static_assert(!std::is_reference<U>::value, "");
U u_; U u_;
public: public:
template<class... Ts> template<class... Ts>
explicit direct_control_block(Ts&&... ts) : u_(U(std::forward<Ts>(ts)...)) explicit direct_control_block(Ts &&... ts) : u_(U(std::forward<Ts>(ts)...)) {
{
} }
std::unique_ptr<control_block<T>> clone() const override std::unique_ptr<control_block<T>> clone() const override {
{
return std::make_unique<direct_control_block>(*this); return std::make_unique<direct_control_block>(*this);
} }
T* ptr() override T *ptr() override {
{
return std::addressof(u_); return std::addressof(u_);
} }
}; };
template<class T, class U, class C = default_copy<U>, template<class T, class U, class C = default_copy<U>,
class D = default_delete<U>> class D = default_delete<U>>
class pointer_control_block : public control_block<T>, public C class pointer_control_block : public control_block<T>, public C {
{
std::unique_ptr<U, D> p_; std::unique_ptr<U, D> p_;
public: public:
explicit pointer_control_block(U *u, C c = C{}, D d = D{}) explicit pointer_control_block(U *u, C c = C{}, D d = D{})
: C(std::move(c)), p_(u, std::move(d)) : C(std::move(c)), p_(u, std::move(d)) {
{
} }
explicit pointer_control_block(std::unique_ptr<U, D> p, C c = C{}) explicit pointer_control_block(std::unique_ptr<U, D> p, C c = C{})
: C(std::move(c)), p_(std::move(p)) : C(std::move(c)), p_(std::move(p)) {
{
} }
std::unique_ptr<control_block<T>> clone() const override std::unique_ptr<control_block<T>> clone() const override {
{
assert(p_); assert(p_);
return std::make_unique<pointer_control_block>( return std::make_unique<pointer_control_block>(
C::operator()(*p_), static_cast<const C &>(*this), p_.get_deleter()); C::operator()(*p_), static_cast<const C &>(*this), p_.get_deleter());
} }
T* ptr() override T *ptr() override {
{
return p_.get(); return p_.get();
} }
}; };
template<class T, class U> template<class T, class U>
class delegating_control_block : public control_block<T> class delegating_control_block : public control_block<T> {
{
std::unique_ptr<control_block<U>> delegate_; std::unique_ptr<control_block<U>> delegate_;
public: public:
explicit delegating_control_block(std::unique_ptr<control_block<U>> b) explicit delegating_control_block(std::unique_ptr<control_block<U>> b)
: delegate_(std::move(b)) : delegate_(std::move(b)) {
{
} }
std::unique_ptr<control_block<T>> clone() const override std::unique_ptr<control_block<T>> clone() const override {
{
return std::make_unique<delegating_control_block>(delegate_->clone()); return std::make_unique<delegating_control_block>(delegate_->clone());
} }
T* ptr() override T *ptr() override {
{
return static_cast<T *>(delegate_->ptr()); return static_cast<T *>(delegate_->ptr());
} }
}; };
@ -143,13 +124,11 @@ namespace detail
} // end namespace detail } // end namespace detail
class bad_poly_construction : std::exception class bad_poly_construction : std::exception {
{
public: public:
bad_poly_construction() noexcept = default; bad_poly_construction() noexcept = default;
const char* what() const noexcept override const char *what() const noexcept override {
{
return "Dynamic and static type mismatch in poly " return "Dynamic and static type mismatch in poly "
"construction"; "construction";
} }
@ -159,13 +138,11 @@ template <class T>
class poly; class poly;
template<class T> template<class T>
struct is_poly : std::false_type struct is_poly : std::false_type {
{
}; };
template<class T> template<class T>
struct is_poly<poly<T>> : std::true_type struct is_poly<poly<T>> : std::true_type {
{
}; };
@ -174,18 +151,20 @@ struct is_poly<poly<T>> : std::true_type
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template<class T> template<class T>
class poly class poly {
{
static_assert(!std::is_union<T>::value, ""); static_assert(!std::is_union<T>::value, "");
static_assert(std::is_class<T>::value, ""); static_assert(std::is_class<T>::value, "");
template<class U> template<class U>
friend class poly; friend
class poly;
template<class T_, class U, class... Ts> template<class T_, class U, class... Ts>
friend poly<T_> make_poly(Ts &&... ts); friend poly<T_> make_poly(Ts &&... ts);
template<class T_, class... Ts> template<class T_, class... Ts>
friend poly<T_> make_poly(Ts &&... ts); friend poly<T_> make_poly(Ts &&... ts);
template<class T_, class U> template<class T_, class U>
friend poly<T_> poly_cast(poly<U> p); friend poly<T_> poly_cast(poly<U> p);
@ -204,17 +183,14 @@ public:
// Constructors // Constructors
// //
poly() poly() {
{
} }
template<class U, class C = detail::default_copy<U>, template<class U, class C = detail::default_copy<U>,
class D = detail::default_delete<U>, class D = detail::default_delete<U>,
class V = std::enable_if_t<std::is_convertible<U *, T *>::value>> class V = std::enable_if_t<std::is_convertible<U *, T *>::value>>
explicit poly(U* u, C copier = C{}, D deleter = D{}) explicit poly(U *u, C copier = C{}, D deleter = D{}) {
{ if (!u) {
if (!u)
{
return; return;
} }
@ -236,10 +212,8 @@ public:
// Copy-constructors // Copy-constructors
// //
poly(const poly& p) poly(const poly &p) {
{ if (!p) {
if (!p)
{
return; return;
} }
auto tmp_cb = p.cb_->clone(); auto tmp_cb = p.cb_->clone();
@ -251,8 +225,7 @@ public:
// Move-constructors // Move-constructors
// //
poly(poly&& p) noexcept poly(poly &&p) noexcept {
{
ptr_ = p.ptr_; ptr_ = p.ptr_;
cb_ = std::move(p.cb_); cb_ = std::move(p.cb_);
p.ptr_ = nullptr; p.ptr_ = nullptr;
@ -265,8 +238,7 @@ public:
template<class U, template<class U,
class V = std::enable_if_t<!std::is_same<T, U>::value && class V = std::enable_if_t<!std::is_same<T, U>::value &&
std::is_convertible<U *, T *>::value>> std::is_convertible<U *, T *>::value>>
poly(const poly<U>& p) poly(const poly<U> &p) {
{
poly<U> tmp(p); poly<U> tmp(p);
ptr_ = tmp.ptr_; ptr_ = tmp.ptr_;
cb_ = std::make_unique<detail::delegating_control_block<T, U>>( cb_ = std::make_unique<detail::delegating_control_block<T, U>>(
@ -276,8 +248,7 @@ public:
template<class U, template<class U,
class V = std::enable_if_t<!std::is_same<T, U>::value && class V = std::enable_if_t<!std::is_same<T, U>::value &&
std::is_convertible<U *, T *>::value>> std::is_convertible<U *, T *>::value>>
poly(poly<U>&& p) poly(poly<U> &&p) {
{
ptr_ = p.ptr_; ptr_ = p.ptr_;
cb_ = std::make_unique<detail::delegating_control_block<T, U>>( cb_ = std::make_unique<detail::delegating_control_block<T, U>>(
std::move(p.cb_)); std::move(p.cb_));
@ -294,8 +265,7 @@ public:
poly(U &&u) poly(U &&u)
: cb_(std::make_unique< : cb_(std::make_unique<
detail::direct_control_block<T, std::decay_t<U>>>( detail::direct_control_block<T, std::decay_t<U>>>(
std::forward<U>(u))) std::forward<U>(u))) {
{
ptr_ = cb_->ptr(); ptr_ = cb_->ptr();
} }
@ -303,15 +273,12 @@ public:
// Assignment // Assignment
// //
poly& operator=(const poly& p) poly &operator=(const poly &p) {
{ if (std::addressof(p) == this) {
if (std::addressof(p) == this)
{
return *this; return *this;
} }
if (!p) if (!p) {
{
cb_.reset(); cb_.reset();
ptr_ = nullptr; ptr_ = nullptr;
return *this; return *this;
@ -328,10 +295,8 @@ public:
// Move-assignment // Move-assignment
// //
poly& operator=(poly&& p) noexcept poly &operator=(poly &&p) noexcept {
{ if (std::addressof(p) == this) {
if (std::addressof(p) == this)
{
return *this; return *this;
} }
@ -346,8 +311,7 @@ public:
// Modifiers // Modifiers
// //
void swap(poly& p) noexcept void swap(poly &p) noexcept {
{
using std::swap; using std::swap;
swap(ptr_, p.ptr_); swap(ptr_, p.ptr_);
swap(cb_, p.cb_); swap(cb_, p.cb_);
@ -358,31 +322,26 @@ public:
// Observers // Observers
// //
explicit operator bool() const explicit operator bool() const {
{
return (bool) cb_; return (bool) cb_;
} }
const T* operator->() const const T *operator->() const {
{
assert(ptr_); assert(ptr_);
return ptr_; return ptr_;
} }
const T& operator*() const const T &operator*() const {
{
assert(*this); assert(*this);
return *ptr_; return *ptr_;
} }
T* operator->() T *operator->() {
{
assert(*this); assert(*this);
return ptr_; return ptr_;
} }
T& operator*() T &operator*() {
{
assert(*this); assert(*this);
return *ptr_; return *ptr_;
} }
@ -392,17 +351,16 @@ public:
// poly creation // poly creation
// //
template<class T, class... Ts> template<class T, class... Ts>
poly<T> make_poly(Ts&&... ts) poly<T> make_poly(Ts &&... ts) {
{
poly<T> p; poly<T> p;
p.cb_ = std::make_unique<detail::direct_control_block<T, T>>( p.cb_ = std::make_unique<detail::direct_control_block<T, T>>(
std::forward<Ts>(ts)...); std::forward<Ts>(ts)...);
p.ptr_ = p.cb_->ptr(); p.ptr_ = p.cb_->ptr();
return std::move(p); return std::move(p);
} }
template<class T, class U, class... Ts> template<class T, class U, class... Ts>
poly<T> make_poly(Ts&&... ts) poly<T> make_poly(Ts &&... ts) {
{
poly<T> p; poly<T> p;
p.cb_ = std::make_unique<detail::direct_control_block<T, U>>( p.cb_ = std::make_unique<detail::direct_control_block<T, U>>(
std::forward<Ts>(ts)...); std::forward<Ts>(ts)...);
@ -414,8 +372,7 @@ template <class T, class U>
const T *poly_view(const poly<U> &p) { const T *poly_view(const poly<U> &p) {
if (p) { if (p) {
return dynamic_cast<const T *>(&*p); return dynamic_cast<const T *>(&*p);
} } else {
else {
return nullptr; return nullptr;
} }
} }
@ -424,8 +381,7 @@ template <class T, class U>
T *poly_view(poly<U> &p) { T *poly_view(poly<U> &p) {
if (p) { if (p) {
return dynamic_cast<T *>(&*p); return dynamic_cast<T *>(&*p);
} } else {
else {
return nullptr; return nullptr;
} }
} }

View File

@ -2,7 +2,7 @@
#define PRESULT_H #define PRESULT_H
#include "expected.h" #include "expected.h"
#include "sourceerror.h" #include "source_error.h"
#include <optional> #include <optional>
@ -40,11 +40,10 @@ struct PResult : tl::expected<T, SourceError> {
/// if U is convertible to T /// if U is convertible to T
template<typename U, class V = std::enable_if_t<std::is_convertible<std::decay_t<U>, T>::value>> template<typename U, class V = std::enable_if_t<std::is_convertible<std::decay_t<U>, T>::value>>
PResult(PResult<U> presult) : PResult(PResult<U> presult) :
tl::expected<T, SourceError>(presult ? PResult<T>(*presult) : PError(presult.error())) tl::expected<T, SourceError>(presult ? PResult<T>(*presult) : PError(presult.error())) {}
{}
}; };
/// Alternative to PResult that is returned from parse* functions /// Alternative to PResult that is returned from parseLibrary* functions
/// that only consume one token so they can fail without affecting /// that only consume one token so they can fail without affecting
/// the parser state /// the parser state
template<typename T> template<typename T>

View File

@ -0,0 +1,5 @@
#include "source_error.h"
SourceError::SourceError(Span span, std::string message)
: span(span), message(std::move(message)) {}

Some files were not shown because too many files have changed in this diff Show More