Compare commits

..

No commits in common. "7be3a1b5bc0076cc003962eceba7862ca52bbc89" and "ae2a3c64ef800b53f6492caf89166a8105963859" have entirely different histories.

44 changed files with 1244 additions and 1473 deletions

View File

@ -37,5 +37,5 @@ add_executable(SchemeEditor
comdel/parser/comdel_lexer.cpp comdel/parser/comdel_lexer.cpp
main.cpp main.cpp
mainwindow.ui mainwindow.ui
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) comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.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 application.cpp application.h comdel/display/single_automatic_dialog.cpp comdel/display/single_automatic_dialog.h comdel/parser/color.cpp comdel/parser/color.h)
target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets) target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets)

View File

@ -90,7 +90,7 @@ std::pair<bool, std::vector<domain::ValidationError>> Application::loadSchema(st
} }
} else { } else {
errorOutput << "Failed schema library" << std::endl; errorOutput << "Failed parsing library" << std::endl;
return {false, errors}; return {false, errors};
} }

View File

@ -0,0 +1,283 @@
//
// Created by bbr on 18. 04. 2022..
//
#include "attribute_dialog.h"
#include "mainwindow.h"
#include "application.h"
namespace display {
AttributeDialog::AttributeDialog(domain::InstanceAttribute *attribute, bool updating) {
setAttribute(Qt::WA_DeleteOnClose);
attributeValue = attribute;
auto actionType = updating ? "Izmjeni " : "Postavi ";
this->setWindowTitle(QString::fromStdString(actionType + 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;
default:
throw std::exception();
}
} else if (type == domain::Value::ValueType::BOOL) {
auto *group = new QGroupBox(this);
auto *radioLayout = new QHBoxLayout(group);
group->setLayout(radioLayout);
auto isTrue = new QRadioButton("da", group);
connect(isTrue, &QRadioButton::clicked, [this]() {
this->value = domain::Value::fromBool(true);
});
auto isFalse = new QRadioButton("ne", 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 buttonLayout = new QHBoxLayout(this);
auto okButton = new QPushButton(updating ? "Ažuriraj" : "Postavi", this);
auto cancelButton = new QPushButton("Odustani", this);
connect(okButton, &QPushButton::clicked, this, &AttributeDialog::onUpdate);
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
layout->addLayout(buttonLayout);
}
void AttributeDialog::onUpdate() {
auto oldValue = attributeValue->value;
attributeValue->value = value;
domain::ComdelValidator validator(domain::getSupportedValidators());
domain::ValidationContext context;
for (auto &addressSpace: Application::instance()->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 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::exception();
}
}
void AttributeDialog::onEnumerationChanged(int index) {
value = attributeValue->attribute.getPopup()->getEnumeration()[index].getValue();
}
MemoryDialog::MemoryDialog(domain::InstanceAttribute *attribute,
std::vector<std::shared_ptr<domain::ComponentInstance>> instances, bool updating) {
memoryInstances = std::vector<std::string>();
setAttribute(Qt::WA_DeleteOnClose);
attributeValue = attribute;
auto actionType = updating ? "Izmjeni memoriju" : "Postavi memoriju";
this->setWindowTitle(QString::fromStdString(actionType));
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 buttonLayout = new QHBoxLayout(this);
auto okButton = new QPushButton(updating ? "Ažuriraj" : "Postavi");
auto cancelButton = new QPushButton("Odustani", this);
connect(okButton, &QPushButton::clicked, this, &MemoryDialog::onUpdate);
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
layout->addLayout(buttonLayout);
}
void MemoryDialog::onUpdate() {
attributeValue->value = value;
accept();
}
void MemoryDialog::onMemoryChanged(int index) {
if (index == memoryInstances.size()) {
value = domain::Value::fromMemoryReference(std::nullopt);
} else {
value = domain::Value::fromMemoryReference(memoryInstances[index]);
}
}
ErrorDialog::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));
}
}
WarningDialog::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->addLayout(buttonLayout);
}
}

View File

@ -0,0 +1,89 @@
#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"
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, 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;
}
}
domain::InstanceAttribute *attributeValue;
public:
AttributeDialog(domain::InstanceAttribute *attribute, bool updating = true);
public slots:
void onTextChanged(const QString &string);
void onEnumerationChanged(int index);
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, bool updating = true);
public slots:
void onMemoryChanged(int index);
void onUpdate();
};
class ErrorDialog : public QDialog {
public:
ErrorDialog(std::vector<domain::ValidationError> errors);
};
class WarningDialog : public QDialog {
public:
WarningDialog(domain::ValidationError error);
};
}
#endif //ATTRIBUTE_DIALOG_H

View File

@ -1,10 +1,9 @@
#include "component_display.h" #include "component_display.h"
#include "comdel/display/dialog/attribute_dialog.h" #include "attribute_dialog.h"
#include "comdel/display/dialog/name_dialog.h" #include "name_dialog.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "application.h" #include "application.h"
#include "comdel/display/dialog/single_automatic_dialog.h" #include "single_automatic_dialog.h"
#include "comdel/display/dialog/memory_dialog.h"
#include <QMenu> #include <QMenu>
#include <QLine> #include <QLine>
@ -46,14 +45,14 @@ namespace display {
if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) { if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) {
menu.addAction("Izmjeni memoriju", [attr]() { menu.addAction("Izmjeni memoriju", [attr]() {
auto dialog = new MemoryDialog("Izmjeni memoriju", "Izmjeni", attr, auto dialog = new MemoryDialog(attr,
Application::instance()->getSchema()->componentInstances); Application::instance()->getSchema()->componentInstances);
dialog->exec(); dialog->exec();
}); });
} else { } else {
auto action = menu.addAction(QString::fromStdString("Izmjeni '" + attr->name + "'"), auto action = menu.addAction(QString::fromStdString("Izmjeni '" + attr->name + "'"),
[attr]() { [attr]() {
auto dialog = new AttributeDialog("Izmjeni " + attr->name, "Izmjeni", attr); auto dialog = new AttributeDialog(attr);
dialog->exec(); dialog->exec();
}); });
action->setEnabled(enabled); action->setEnabled(enabled);
@ -84,7 +83,7 @@ namespace display {
auto connectionName = directConnection->attributes[0].value.stringify() + "-" + auto connectionName = directConnection->attributes[0].value.stringify() + "-" +
directConnection->attributes[1].value.stringify(); directConnection->attributes[1].value.stringify();
update->addAction(QString::fromStdString("Izmjeni " + connectionName), [directConnection]() { update->addAction(QString::fromStdString("Izmjeni " + connectionName), [directConnection]() {
auto dialog = new SingleAutomaticDialog("Izmjeni sabirnicu", "Izmjeni", directConnection->attributes); auto dialog = new SingleAutomaticDialog(directConnection->attributes);
dialog->exec(); dialog->exec();
}); });
remove->addAction(QString::fromStdString("Ukloni " + connectionName), remove->addAction(QString::fromStdString("Ukloni " + connectionName),
@ -110,7 +109,7 @@ namespace display {
for (int i = 0; i < pinConnection->attributes.size(); i++) { for (int i = 0; i < pinConnection->attributes.size(); i++) {
auto *attr = &pinConnection->attributes[i]; auto *attr = &pinConnection->attributes[i];
menu.addAction(QString::fromStdString("Izmjeni '" + attr->name + "'"),[attr]() { menu.addAction(QString::fromStdString("Izmjeni '" + attr->name + "'"),[attr]() {
auto dialog = new AttributeDialog("Izmjeni '" + attr->name + "'", "Izmjeni", attr); auto dialog = new AttributeDialog(attr);
dialog->exec(); dialog->exec();
}); });
} }

View File

@ -1,180 +0,0 @@
#include "attribute_dialog.h"
#include "mainwindow.h"
#include "application.h"
#include "error_dialog.h"
#include "warning_dialog.h"
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::exception();
}
}
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("da", group);
connect(isTrue, &QRadioButton::clicked, [this]() {
this->value = domain::Value::fromBool(true);
});
auto isFalse = new QRadioButton("ne", 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

@ -1,47 +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/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

@ -1,34 +0,0 @@
#include <QVBoxLayout>
#include <QLabel>
#include <QPlainTextEdit>
#include "error_dialog.h"
namespace display {
ErrorDialog::ErrorDialog(std::vector<domain::ValidationError> errors)
: GenericDialog("Greške", "") {
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("Greške", "") {
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

@ -1,22 +0,0 @@
#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

@ -1,29 +0,0 @@
#include <QVBoxLayout>
#include "generic_dialog.h"
display::GenericDialog::GenericDialog(std::string title, std::string action) {
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle(QString::fromStdString(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.empty()) {
okButton = new QPushButton(QString::fromStdString(action), this);
connect(okButton, &QPushButton::clicked, this, [this](){if(this->onUpdate()) this->accept();});
actionBar->addWidget(okButton);
}
cancelButton = new QPushButton("Odustani", this);
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
actionBar->addWidget(cancelButton);
}
void display::GenericDialog::setOkButtonDisabled(bool disabled) {
okButton->setDisabled(disabled);
}

View File

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

View File

@ -1,59 +0,0 @@
#include <QVBoxLayout>
#include <QLabel>
#include "memory_dialog.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("null");
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

@ -1,33 +0,0 @@
#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

@ -1,39 +0,0 @@
#include <set>
#include "name_dialog.h"
namespace display {
NameDialog::NameDialog(std::string currentName, std::set<std::string> &names)
: GenericDialog("Izmjeni ime", "Izmjeni"), currentName(currentName), usedNames(names) {
usedNames.erase(currentName);
auto *contentLayout = new QVBoxLayout();
contentLayout->addWidget(new QLabel("Izmjeni ime", 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

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

View File

@ -1,19 +0,0 @@
//
// 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, std::string action = "Ok");
};
} // display
#endif //SCHEMEEDITOR_SUCCESS_DIALOG_H

View File

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

View File

@ -1,20 +0,0 @@
#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

@ -0,0 +1,50 @@
//
// Created by bbr on 18. 04. 2022..
//
#include <set>
#include "name_dialog.h"
display::NameDialog::NameDialog(std::string currentName, std::set<std::string> &names): currentName(currentName) {
usedNames.erase(currentName);
auto *layout = new QVBoxLayout(this);
layout->addWidget(new QLabel("Izmjeni ime", this));
edit = new QLineEdit(this);
edit->insert(currentName.c_str());
connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate);
layout->addWidget(edit);
setWindowTitle("Izmjeni ime");
setLayout(layout);
auto buttonLayout = new QHBoxLayout(this);
button = new QPushButton("Ažuriraj");
auto cancelButton = new QPushButton("Odustani", this);
connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange);
connect(cancelButton, &QPushButton::clicked, [this]() { reject(); });
buttonLayout->addWidget(button);
buttonLayout->addWidget(cancelButton);
layout->addLayout(buttonLayout);
}
void display::NameDialog::onNameUpdate(const QString &text) {
if(usedNames.find(text.toStdString()) == usedNames.end()) {
button->setDisabled(false);
} else {
button->setDisabled(true);
}
}
void display::NameDialog::onNameChange() {
currentName = edit->text().toStdString();
close();
}
std::string display::NameDialog::getName() {
return currentName;
}

View File

@ -9,29 +9,25 @@
#include <set> #include <set>
#include "comdel/domain/instance.h" #include <comdel/domain/instance.h>
#include "generic_dialog.h"
namespace display { namespace display {
class NameDialog : public GenericDialog { class NameDialog : public QDialog {
std::set<std::string> usedNames;
QLineEdit *edit = nullptr;
std::string currentName;
QPushButton *button;
public: public:
NameDialog(std::string currentName, std::set<std::string>& names); NameDialog(std::string currentName, std::set<std::string>& names);
std::string getName(); std::string getName();
protected:
bool onUpdate() override;
public slots: public slots:
void onNameUpdate(const QString& text); void onNameUpdate(const QString& text);
void onNameChange();
private:
std::set<std::string> usedNames;
QLineEdit *edit = nullptr;
std::string currentName;
}; };
} }

View File

@ -1,9 +1,8 @@
#include "component_display.h" #include "component_display.h"
#include "schema_display.h" #include "schema_display.h"
#include "application.h" #include "application.h"
#include "comdel/display/dialog/attribute_dialog.h" #include "attribute_dialog.h"
#include "comdel/display/dialog/single_automatic_dialog.h" #include "single_automatic_dialog.h"
#include "comdel/display/dialog/memory_dialog.h"
#include <QDrag> #include <QDrag>
#include <QDragEnterEvent> #include <QDragEnterEvent>
@ -276,13 +275,13 @@ namespace display {
domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr); domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr);
if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) { if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) {
if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) { if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) {
auto dialog = new MemoryDialog("Postavi memoriju", "Postavi", &attribute, schema->componentInstances); auto dialog = new MemoryDialog(&attribute, schema->componentInstances, false);
if(dialog->exec() == QDialog::Rejected) { if(dialog->exec() == QDialog::Rejected) {
// if any dialog isn't set, whole creation is rejected // if any dialog isn't set, whole creation is rejected
return {}; return {};
} }
} else { } else {
auto dialog = new AttributeDialog("Postavi " + attribute.name, "Postavi", &attribute); auto dialog = new AttributeDialog(&attribute, false);
if(dialog->exec() == QDialog::Rejected) { if(dialog->exec() == QDialog::Rejected) {
// if any dialog isn't set, whole creation is rejected // if any dialog isn't set, whole creation is rejected
return {}; return {};
@ -301,7 +300,7 @@ namespace display {
instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr); instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr);
} }
auto dialog = new display::SingleAutomaticDialog("Postavi sabirnicu", "Postavi", instanceAttributes); auto dialog = new display::SingleAutomaticDialog(instanceAttributes, false);
if(dialog->exec() == QDialog::Rejected) { if(dialog->exec() == QDialog::Rejected) {
// if dialog is rejected, whole creation is rejected // if dialog is rejected, whole creation is rejected
return {}; return {};

View File

@ -1,3 +1,7 @@
//
// Created by bbr on 05.06.22..
//
#include "single_automatic_dialog.h" #include "single_automatic_dialog.h"
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QLabel> #include <QLabel>
@ -5,23 +9,38 @@
#include <QPushButton> #include <QPushButton>
namespace display { namespace display {
SingleAutomaticDialog::SingleAutomaticDialog(std::vector<domain::InstanceAttribute> &values, bool updating): attributes(values) {
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle(QString::fromStdString(updating ? "Ažuriraj poveznicu" : "Postavi poveznicu"));
SingleAutomaticDialog::SingleAutomaticDialog(std::string title, std::string action,
std::vector<domain::InstanceAttribute> &values)
: GenericDialog(title, action), attributes(values) {
firstValue = values[0].value; firstValue = values[0].value;
secondValue = values[1].value; secondValue = values[1].value;
auto *contentLayout = new QHBoxLayout(); auto *parentLayout = new QVBoxLayout(this);
auto *firstLayout = new QVBoxLayout(); auto *contentLayout = new QHBoxLayout(this);
auto *secondLayout = new QVBoxLayout(); auto *firstLayout = new QVBoxLayout(this);
auto *secondLayout = new QVBoxLayout(this);
content->setLayout(contentLayout); parentLayout->addLayout(contentLayout);
contentLayout->addLayout(firstLayout); contentLayout->addLayout(firstLayout);
contentLayout->addLayout(secondLayout); contentLayout->addLayout(secondLayout);
this->setLayout(parentLayout);
setupValues(firstLayout, values[0], &SingleAutomaticDialog::onFirstEnumerationChanged); setupValues(firstLayout, values[0], &SingleAutomaticDialog::onFirstEnumerationChanged);
setupValues(secondLayout, values[1], &SingleAutomaticDialog::onSecondEnumerationChanged); setupValues(secondLayout, values[1], &SingleAutomaticDialog::onSecondEnumerationChanged);
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);
parentLayout->addLayout(buttonLayout);
} }
void SingleAutomaticDialog::setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)) { void SingleAutomaticDialog::setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int)) {
@ -56,10 +75,10 @@ namespace display {
secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue(); secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue();
} }
bool SingleAutomaticDialog::onUpdate() { void SingleAutomaticDialog::onUpdate() {
attributes[0].value = firstValue; attributes[0].value = firstValue;
attributes[1].value = secondValue; attributes[1].value = secondValue;
return true; accept();
} }
} // display } // display

View File

@ -1,3 +1,7 @@
//
// Created by bbr on 05.06.22..
//
#ifndef SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H #ifndef SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
#define SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H #define SCHEMEEDITOR_SINGLE_AUTOMATIC_DIALOG_H
@ -6,29 +10,24 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include "comdel/domain/value.h" #include "comdel/domain/value.h"
#include "comdel/domain/instance_attribute.h" #include "comdel/domain/instance_attribute.h"
#include "generic_dialog.h"
namespace display { namespace display {
class SingleAutomaticDialog: public GenericDialog { class SingleAutomaticDialog: public QDialog {
domain::Value firstValue; domain::Value firstValue;
domain::Value secondValue; domain::Value secondValue;
std::vector<domain::InstanceAttribute> &attributes; std::vector<domain::InstanceAttribute> &attributes;
public: public:
explicit SingleAutomaticDialog( explicit SingleAutomaticDialog(std::vector<domain::InstanceAttribute>& values, bool updating = true);
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)); void setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int));
public slots: public slots:
void onFirstEnumerationChanged(int index); void onFirstEnumerationChanged(int index);
void onSecondEnumerationChanged(int index); void onSecondEnumerationChanged(int index);
void onUpdate();
}; };
} // display } // display

View File

@ -68,7 +68,7 @@ namespace domain {
errors.emplace_back(Action::ERROR, message); errors.emplace_back(Action::ERROR, message);
} else if (count > bus.getCount().second) { } else if (count > bus.getCount().second) {
auto message = populateMessage( auto message = populateMessage(
"Previše instanci sabirnice '{busName}' dozvoljeno najviše {max}, pronađeno {count}", context); "Previše instanci sabirnice '{busName}' dozvoljeno najviše {max}, pronašeno {count}", context);
errors.emplace_back(Action::ERROR, message); errors.emplace_back(Action::ERROR, message);
} }
} }
@ -82,11 +82,11 @@ namespace domain {
for (auto &inst: schema.componentInstances) { for (auto &inst: schema.componentInstances) {
for (auto &pin: inst->component.getPins()) { for (auto &pin: inst->component.getPins()) {
if (pin.getConnection().has_value()) { if (pin.getConnection().getType() == PinConnection::REQUIRED) {
if (!connectionExists(schema, inst, pin)) { if (!connectionExists(schema, inst, pin)) {
context.instance = inst.get(); context.instance = inst.get();
context.attributes["instanceName"] = Value::fromString(inst->name); context.attributes["instanceName"] = Value::fromString(inst->name);
auto message = populateMessage(pin.getConnection().value(), context); auto message = populateMessage(pin.getConnection().getMessage(), context);
errors.emplace_back(Action::ERROR, message); errors.emplace_back(Action::ERROR, message);
} }
} }

View File

@ -2,7 +2,19 @@
namespace domain { namespace domain {
Pin::Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin, PinConnection::PinConnection(std::string message, ConnectionType type)
: message(message), type(type) {}
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) std::optional<std::vector<Value>> wires)
: name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires) {} : name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires) {}
@ -22,7 +34,7 @@ namespace domain {
return displayPin; return displayPin;
} }
std::optional<std::string> Pin::getConnection() { PinConnection &Pin::getConnection() {
return connection; return connection;
} }

View File

@ -9,6 +9,25 @@
namespace domain { namespace domain {
class PinConnection {
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 { class Pin {
public: public:
enum PinType { enum PinType {
@ -21,13 +40,13 @@ namespace domain {
std::string name; std::string name;
PinType type; PinType type;
std::string tooltip; std::string tooltip;
std::optional<std::string> connection; PinConnection 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, std::optional<std::string> connection, domain::ui::Pin pin, Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin,
std::optional<std::vector<Value>> wires); std::optional<std::vector<Value>> wires);
std::string &getName(); std::string &getName();
@ -38,7 +57,7 @@ namespace domain {
ui::Pin &getDisplayPin(); ui::Pin &getDisplayPin();
std::optional<std::string> getConnection(); PinConnection &getConnection();
std::optional<std::vector<Value>> &getWires(); std::optional<std::vector<Value>> &getWires();
}; };

View File

@ -5,8 +5,9 @@
namespace domain { namespace domain {
ComdelContext::ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection)
: name(std::move(name)), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection) {} ComdelContext::ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus)
: name(std::move(name)), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection), inBus(inBus) {}
bool ComdelContext::doesAttributeExists(std::string name, Value::ValueType type) { bool ComdelContext::doesAttributeExists(std::string name, Value::ValueType type) {
for (auto &attribute: attributes) { for (auto &attribute: attributes) {
@ -26,9 +27,7 @@ namespace domain {
return false; return false;
} }
/***********************************************************************
* ENUM CONVERSIONS *
***********************************************************************/
Component::ComponentType toType(ComponentNode::ComponentType type) { Component::ComponentType toType(ComponentNode::ComponentType type) {
if (type == ComponentNode::MEMORY) { if (type == ComponentNode::MEMORY) {
return Component::MEMORY; return Component::MEMORY;
@ -79,26 +78,29 @@ namespace domain {
} }
} }
Value toType(ValueNode node, Value::ValueType type = Value::ValueType::UNDEFINED) { Value toType(ValueNode node, Value::ValueType type = Value::ValueType::UNDEFINED) {
if (type == Value::MEMORY_REFERENCE) { if (type == Value::MEMORY_REFERENCE) {
if (node.is(ValueNode::NIL)) { if (node.getType() == ValueNode::NIL) {
return Value::fromMemoryReference(nullopt); return Value::fromMemoryReference(nullopt);
} else { } else {
return Value::fromMemoryReference(node.asIdentifier()); return Value::fromMemoryReference(node.asIdentifier());
} }
} }
if (node.is(ValueNode::BOOL)) {
if (node.getType() == ValueNode::BOOL) {
return Value::fromBool(node.asBool()); return Value::fromBool(node.asBool());
} else if (node.is(ValueNode::INT)) { } else if (node.getType() == ValueNode::INT) {
return Value::fromInt(node.asInt()); return Value::fromInt(node.asInt());
} else if (node.is(ValueNode::STRING)) { } else if (node.getType() == ValueNode::STRING) {
return Value::fromString(node.asString()); return Value::fromString(node.asString());
} else if (node.is(ValueNode::NIL)) { } else if (node.getType() == ValueNode::NIL) {
return Value::fromNull(); return Value::fromNull();
} }
return Value::fromReference(node.asIdentifier(), Value::UNDEFINED); return Value::fromReference(node.asIdentifier(), Value::UNDEFINED);
} }
Bus::BusType toType(BusNode::BusType type) { Bus::BusType toType(BusNode::BusType type) {
if (type == BusNode::AUTOMATIC) { if (type == BusNode::AUTOMATIC) {
return Bus::AUTOMATIC; return Bus::AUTOMATIC;
@ -108,6 +110,7 @@ namespace domain {
return Bus::REGULAR; return Bus::REGULAR;
} }
Pin::PinType toType(PinNode::PinType type) { Pin::PinType toType(PinNode::PinType type) {
if (type == PinNode::IN) { if (type == PinNode::IN) {
return Pin::IN; return Pin::IN;
@ -117,6 +120,14 @@ namespace domain {
return Pin::IN_OUT; return Pin::IN_OUT;
} }
PinConnection::ConnectionType toType(PinConnectionNode::ConnectionType type) {
if (type == PinConnectionNode::OPTIONAL) {
return PinConnection::OPTIONAL;
}
return PinConnection::REQUIRED;
}
Popup::PopupType toType(PopupNode::PopupType type) { Popup::PopupType toType(PopupNode::PopupType type) {
if (type == PopupNode::AUTOMATIC) { if (type == PopupNode::AUTOMATIC) {
return Popup::AUTOMATIC; return Popup::AUTOMATIC;
@ -124,11 +135,6 @@ namespace domain {
return Popup::ON_DEMAND; return Popup::ON_DEMAND;
} }
/***********************************************************************
* SCHEMA CREATOR *
***********************************************************************/
SchemaCreator::SchemaCreator(std::vector<FunctionValidator *> validators) SchemaCreator::SchemaCreator(std::vector<FunctionValidator *> validators)
: validators(std::move(validators)) {} : validators(std::move(validators)) {}
@ -153,6 +159,7 @@ namespace domain {
} }
header = node.header ? node.header->asString() : ""; header = node.header ? node.header->asString() : "";
libraryInfo = node.libraryInfo ? node.libraryInfo->asString() : ""; libraryInfo = node.libraryInfo ? node.libraryInfo->asString() : "";
for (auto &as: node.addressSpaces) { for (auto &as: node.addressSpaces) {
@ -194,6 +201,7 @@ namespace domain {
} else { } else {
return nullopt; return nullopt;
} }
} }
std::optional<Bus> SchemaCreator::loadBus(BusNode node) { std::optional<Bus> SchemaCreator::loadBus(BusNode node) {
@ -264,12 +272,13 @@ namespace domain {
return Bus(busName, instanceName, tooltip, type, count, wires, displayBus); return Bus(busName, instanceName, tooltip, type, count, wires, displayBus);
} }
std::optional<AddressSpace> SchemaCreator::loadAddressSpace(AddressSpaceNode node) { std::optional<AddressSpace> SchemaCreator::loadAddressSpace(AddressSpaceNode node) {
return AddressSpace(node.name.value, node.range.first.value, node.range.second.value); return AddressSpace(node.name.value, node.start.value, node.end.value);
} }
std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node) { std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node) {
push(ComdelContext("connection", false, true, false)); push(ComdelContext("connection", false, true, false, false));
std::string bus = node.bus.value; std::string bus = node.bus.value;
auto busInstance = getBus(bus); auto busInstance = getBus(bus);
@ -444,6 +453,7 @@ namespace domain {
attributes[1].setPupup(popup); attributes[1].setPupup(popup);
} }
} }
pop(); pop();
return Connection(first, second, bus, attributes, firstWires, secondWires); return Connection(first, second, bus, attributes, firstWires, secondWires);
@ -455,7 +465,7 @@ namespace domain {
} }
std::optional<Component> SchemaCreator::loadComponent(ComponentNode node) { std::optional<Component> SchemaCreator::loadComponent(ComponentNode node) {
push(ComdelContext(node.name.value, true, false, false)); push(ComdelContext(node.name.value, true, false, false, false));
std::string componentName = node.name.value; std::string componentName = node.name.value;
@ -574,10 +584,12 @@ namespace domain {
} }
ui::Pin displayPin = *display->getItems()[0].pin; ui::Pin displayPin = *display->getItems()[0].pin;
std::optional<std::string> connection = std::nullopt;
if (node.connection) { if (!node.connection) {
connection = node.connection->asString(); errors.emplace_back(node.span, "missing @connection");
return nullopt;
} }
auto connection = loadPinConnection(*node.connection);
std::optional<std::vector<Value>> wiresOpt = std::nullopt; std::optional<std::vector<Value>> wiresOpt = std::nullopt;
if (node.wires.has_value()) { if (node.wires.has_value()) {
@ -598,74 +610,47 @@ namespace domain {
return Pin(pinName, type, tooltip, connection, displayPin, wiresOpt); return Pin(pinName, type, tooltip, connection, displayPin, wiresOpt);
} }
Color readColor(std::vector<SourceError>& errors, DisplayItemNode& item, std::string property, Color _default) {
auto color = item.asColor(property, _default);
if(!color.has_value()) {
errors.emplace_back(item.span, "expected color");
return _default;
}
return *color;
}
std::string readString(std::vector<SourceError>& errors, DisplayItemNode& item, std::string property, std::string _default = "") {
auto value = item.asString(property, _default);
if(!value.has_value()) {
errors.emplace_back(item.span, "expected string");
return _default;
}
return *value;
}
long long int readInt(std::vector<SourceError>& errors, DisplayItemNode& item, std::string property, long long int _default = 0) {
auto value = item.asInt(property, _default);
if(!value.has_value()) {
errors.emplace_back(item.span, "expected int");
return _default;
}
return *value;
}
std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node) { std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node) {
std::vector<ui::Item> items; std::vector<ui::Item> items;
for (auto &item: node.items) { for (auto &item: node.items) {
ui::Item displayItem; ui::Item displayItem;
std::string type = item.type.value; std::string type = item.type.value;
auto fillColor = readColor(errors, item, "fillColor", Color(255, 255, 255, 255)); auto fillColor = item.asColor(&errors, "fillColor", Color(255, 255, 255, 255));
auto lineColor = readColor(errors, item, "lineColor", Color(0, 0, 0, 255)); auto lineColor = item.asColor(&errors, "lineColor", Color(0, 0, 0, 255));
if (type == "text") { if (type == "text") {
long long int x, y, w, h; long long int x, y, w, h;
std::string text; std::string text;
auto color = readColor(errors, item, "color", Color(0, 0, 0, 255)); auto color = item.asColor(&errors, "color", Color(0, 0, 0, 255));
x = readInt(errors, item, "x"); x = item.asInt(&errors, "x");
y = readInt(errors, item, "y"); y = item.asInt(&errors, "y");
w = readInt(errors, item, "w"); w = item.asInt(&errors, "w");
h = readInt(errors, item, "h"); h = item.asInt(&errors, "h");
text = readString(errors, item, "text"); text = item.asString(&errors, "text");
displayItem.text = ui::Text(x, y, w, h, text, color); displayItem.text = ui::Text(x, y, w, h, text, color);
} else if (type == "rect") { } else if (type == "rect") {
long long int x, y, w, h; long long int x, y, w, h;
x = readInt(errors, item, "x"); x = item.asInt(&errors, "x");
y = readInt(errors, item, "y"); y = item.asInt(&errors, "y");
w = readInt(errors, item, "w"); w = item.asInt(&errors, "w");
h = readInt(errors, item, "h"); h = item.asInt(&errors, "h");
displayItem.rect = ui::Rect(x, y, w, h, {lineColor, fillColor}); displayItem.rect = ui::Rect(x, y, w, h, {lineColor, fillColor});
} else if (type == "line") { } else if (type == "line") {
long long int x1, y1, x2, y2; long long int x1, y1, x2, y2;
x1 = readInt(errors, item, "x1"); x1 = item.asInt(&errors, "x1");
y1 = readInt(errors, item, "y1"); y1 = item.asInt(&errors, "y1");
x2 = readInt(errors, item, "x2"); x2 = item.asInt(&errors, "x2");
y2 = readInt(errors, item, "y2"); y2 = item.asInt(&errors, "y2");
displayItem.line = ui::Line(x1, y1, x2, y2, {lineColor, fillColor}); displayItem.line = ui::Line(x1, y1, x2, y2, {lineColor, fillColor});
} else if (type == "pin") { } else if (type == "pin") {
long long int x, y, w, h; long long int x, y, w, h;
x = readInt(errors, item, "x"); x = item.asInt(&errors, "x");
y = readInt(errors, item, "y"); y = item.asInt(&errors, "y");
w = readInt(errors, item, "w"); w = item.asInt(&errors, "w");
h = readInt(errors, item, "h"); h = item.asInt(&errors, "h");
std::string _orientation = readString(errors, item, "orientation", "bottom"); std::string _orientation = item.asString(&errors, "orientation", "bottom");
std::string _pinType = readString(errors, item, "type", "out"); std::string _pinType = item.asString(&errors, "type", "out");
ui::PinOrientation orientation; ui::PinOrientation orientation;
if (_orientation == "left") { if (_orientation == "left") {
@ -694,11 +679,11 @@ namespace domain {
displayItem.pin = ui::Pin(x, y, w, h, orientation, pinType, {lineColor, fillColor}); displayItem.pin = ui::Pin(x, y, w, h, orientation, pinType, {lineColor, fillColor});
} else if (type == "bus") { } else if (type == "bus") {
long long int x, y, w, h; long long int x, y, w, h;
x = readInt(errors, item, "x"); x = item.asInt(&errors, "x");
y = readInt(errors, item, "y"); y = item.asInt(&errors, "y");
w = readInt(errors, item, "w"); w = item.asInt(&errors, "w");
h = readInt(errors, item, "h"); h = item.asInt(&errors, "h");
std::string _orientation = readString(errors, item, "orientation", "bottom"); std::string _orientation = item.asString(&errors, "orientation", "bottom");
ui::BusOrientation orientation; ui::BusOrientation orientation;
if (_orientation == "horizontal") { if (_orientation == "horizontal") {
@ -718,6 +703,13 @@ namespace domain {
return Display(items); return Display(items);
} }
PinConnection SchemaCreator::loadPinConnection(PinConnectionNode node) {
std::string message = node.message.asString();
PinConnection::ConnectionType type = toType(node.type.value);
return {message, type};
}
std::optional<Attribute> SchemaCreator::loadAttribute(AttributeNode node) { std::optional<Attribute> SchemaCreator::loadAttribute(AttributeNode node) {
std::string name = node.name.value; std::string name = node.name.value;
pushAdditional(name); pushAdditional(name);
@ -1006,6 +998,7 @@ namespace domain {
} }
shared_ptr<ComponentInstance> SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) { shared_ptr<ComponentInstance> SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) {
auto componentInstanceName = instance.name.value; auto componentInstanceName = instance.name.value;
auto position = std::make_pair(instance.position->first.value, instance.position->second.value); auto position = std::make_pair(instance.position->first.value, instance.position->second.value);
@ -1110,7 +1103,7 @@ namespace domain {
this->context.push_back(current()); this->context.push_back(current());
current().name = name; current().name = name;
} else { } else {
ComdelContext con(name, false, false, false); ComdelContext con(name, false, false, false, false);
push(con); push(con);
} }
} }

View File

@ -13,7 +13,6 @@
namespace domain { namespace domain {
/** Context used for loading model */
struct ComdelContext { struct ComdelContext {
std::vector<Attribute> attributes; std::vector<Attribute> attributes;
std::vector<std::string> wires; std::vector<std::string> wires;
@ -21,8 +20,9 @@ namespace domain {
bool inComponent; bool inComponent;
bool inConnection; bool inConnection;
bool inSingleAutomaticConnection; bool inSingleAutomaticConnection;
bool inBus;
ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection); ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus);
bool doesAttributeExists(std::string name, Value::ValueType type); bool doesAttributeExists(std::string name, Value::ValueType type);
bool doesWireExists(std::string name); bool doesWireExists(std::string name);
@ -30,16 +30,6 @@ namespace domain {
}; };
class SchemaCreator { 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::vector<ComdelContext> context;
std::string name; std::string name;
@ -53,6 +43,7 @@ namespace domain {
std::vector<Connection> connections; std::vector<Connection> connections;
std::map<std::string, std::string> messages; std::map<std::string, std::string> messages;
std::vector<SourceError> errors; std::vector<SourceError> errors;
std::vector<FunctionValidator *> validators; std::vector<FunctionValidator *> validators;
@ -66,25 +57,35 @@ namespace domain {
std::optional<Display> loadDisplay(DisplayNode node); std::optional<Display> loadDisplay(DisplayNode node);
std::optional<Wire> loadWire(WireNode node); std::optional<Wire> loadWire(WireNode node);
std::optional<Pin> loadPin(PinNode pins); std::optional<Pin> loadPin(PinNode pins);
PinConnection loadPinConnection(PinConnectionNode node);
std::optional<Connection> loadConnection(ConnectionNode node); std::optional<Connection> loadConnection(ConnectionNode node);
std::optional<Bus> loadBus(BusNode node); std::optional<Bus> loadBus(BusNode node);
std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library); std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library);
std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library); std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library);
/** Utility classes */
std::optional<Bus> getBus(std::string name); std::optional<Bus> getBus(std::string name);
std::optional<Pin> getComponentPin(std::string name, std::string pin); std::optional<Pin> getComponentPin(std::string name, std::string pin);
bool hasAddressSpace(std::string name); bool hasAddressSpace(std::string name);
void push(ComdelContext context);
void pushAdditional(std::string name);
ComdelContext &current();
void pop();
std::optional<Attribute> createMemoryAttribute(); std::optional<Attribute> createMemoryAttribute();
vector<Enumeration> createWireEnumeration(vector<Value> enumeration); vector<Enumeration> createWireEnumeration(vector<Value> enumeration);
std::optional<Popup> createMemoryPopup(); std::optional<Popup> createMemoryPopup();
/** Context stack operations */ public:
void push(ComdelContext context); explicit SchemaCreator(std::vector<FunctionValidator *> validators);
void pushAdditional(std::string name);
ComdelContext &current(); std::vector<SourceError> getErrors();
void pop();
std::optional<Library> loadLibrary(LibraryNode node);
Schema *loadSchema(SchemaNode node, Library &library);
}; };
} // namespace domain } // namespace domain

View File

@ -197,31 +197,4 @@ namespace domain {
return val; return val;
} }
bool Value::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;
}
} // namespace domain } // namespace domain

View File

@ -43,7 +43,32 @@ namespace domain {
Value() = default; 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();

View File

@ -1,5 +1,9 @@
#include "ast_nodes.h" #include "ast_nodes.h"
/*************************** AST NODE ********************************/
AstNode::~AstNode() = default;
/*************************** NUMBER NODE ********************************/ /*************************** NUMBER NODE ********************************/
NumberNode::NumberNode(const std::string &expression) { NumberNode::NumberNode(const std::string &expression) {
@ -37,11 +41,7 @@ std::string StringNode::asString() {
/*************************** VALUE NODE ********************************/ /*************************** VALUE NODE ********************************/
ValueNode::ValueType ValueNode::getType() const { long long ValueNode::asInt() {
return type.value;
}
long long int ValueNode::asInt() {
if (is(INT)) { if (is(INT)) {
return intValue.value(); return intValue.value();
} }
@ -135,38 +135,3 @@ ValueNode ValueNode::ofMemory(std::optional<std::string> _value) {
value.identifierValue = _value; value.identifierValue = _value;
return 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;
}

View File

@ -8,30 +8,28 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
/*****************************************************************************
* BASE TYPES *
*****************************************************************************/
/** /**
* AST base class, all AST node classes extend this class. Class contains basic * AST base class, all AST node classes extend this class. Class contains basic
* information about nodes location in file. * information about nodes location in file.
*/ */
class AstNode { class AstNode {
public: public:
/** Contains information about where in source file given node is located */
Span span; Span span;
AstNode() = default; AstNode() = default;
virtual ~AstNode();
AstNode(AstNode &&) = default; AstNode(AstNode &&) = default;
AstNode &operator=(AstNode &&) = default; AstNode &operator=(AstNode &&) = default;
AstNode(const AstNode &) = default; AstNode(const AstNode &) = default;
AstNode &operator=(const AstNode &) = default; AstNode &operator=(const AstNode &) = default;
}; };
/**
* AST base enum class,
* Used to represent AST enums
* */
template<typename T> template<typename T>
struct EnumNode : public AstNode { struct EnumNode : public AstNode {
EnumNode() = default; EnumNode() = default;
@ -41,416 +39,284 @@ struct EnumNode : public AstNode {
T value; T value;
}; };
/** Represents string
* value contains quote-marks ("" or '' depending on string type)
* */
struct StringNode : public AstNode { struct StringNode : public AstNode {
/** String including quote-marks*/
std::string value; std::string value;
/** Returns string without quote-marks */
std::string asString(); std::string asString();
}; };
/** Represents identifiers */
struct IdentifierNode : public AstNode { struct IdentifierNode : public AstNode {
std::string value; std::string value;
}; };
/** Represents all numbers used
* All numbers must fit into long long int
* */
struct NumberNode : public AstNode { struct NumberNode : public AstNode {
long long int value = 0; long long int value;
explicit NumberNode(const std::string &expression); explicit NumberNode(const std::string &expression);
NumberNode() = default; NumberNode() : value(0) {}
}; };
/** Represents color
* color comes in two formats #RRGGBB or #RRGGBBAA (AA representing opacity)
* */
struct ColorNode : public AstNode { struct ColorNode : public AstNode {
Color color; Color color;
explicit ColorNode(const std::string &expression); explicit ColorNode(const std::string &expression);
ColorNode() = default; ColorNode() {}
}; };
/** Represents ordered number pair */
struct NumberPairNode : public AstNode { struct CountNode : public AstNode {
NumberNode first; NumberNode first;
NumberNode second; NumberNode second;
NumberPairNode(NumberNode first, NumberNode second) : first(first), second(second) {} CountNode(NumberNode first, NumberNode second) : first(std::move(first)), second(std::move(second)) {}
NumberPairNode() = default; CountNode() = default;
};
struct AddressSpaceNode : public AstNode {
IdentifierNode name;
NumberNode start;
NumberNode end;
}; };
/** 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 { class ValueNode : public AstNode {
public: public:
enum ValueType { enum ValueType {
/** Stores same content as NumberNode */
INT, INT,
/** Stores same content as StringNode */
STRING, STRING,
/** Stores true or false */
BOOL, BOOL,
/** Stores wire nam or null */
WIRE, WIRE,
/** Default type assigned when node value is of type IdentifierNode and more correct type is assigned later */
IDENTIFIER, IDENTIFIER,
/** Stores memory name or null */
MEMORY, MEMORY,
/** Stores null */
NIL, NIL,
/** Store same content as ColorNode */
COLOR, COLOR,
}; };
private: private:
/** Type determines what is stored inside ValueNode */ EnumNode<ValueType> type;
EnumNode<ValueType> type = EnumNode(NIL); std::optional<long long> intValue;
/** All possible values for ValueNode are stored inside optionals */ std::optional<std::string> stringValue;
std::optional<long long> intValue = std::nullopt; std::optional<bool> boolValue;
std::optional<std::string> stringValue = std::nullopt; std::optional<std::string> identifierValue;
std::optional<bool> boolValue = std::nullopt; std::optional<Color> colorValue;
std::optional<std::string> identifierValue = std::nullopt;
std::optional<Color> colorValue = std::nullopt;
public: public:
ValueNode() = default; ValueNode() = default;
ValueType getType() const; ValueType getType() const {
return type.value;
}
long long asInt();
/** 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 asString();
std::string asIdentifier(); std::string asIdentifier();
Color asColor(); Color asColor();
bool asBool(); bool asBool();
/** Returns true if ValueNode is of given valueType */
bool is(ValueType valueType); bool is(ValueType valueType);
/** Static methods used to generate ValueNodes of requested type */
static ValueNode ofBool(bool _value); static ValueNode ofBool(bool _value);
static ValueNode ofInt(long long _value); static ValueNode ofInt(long long _value);
static ValueNode ofString(std::string _value); static ValueNode ofString(std::string _value);
static ValueNode ofIdentifier(std::string _value); static ValueNode ofIdentifier(std::string _value);
static ValueNode ofMemory(std::optional<std::string> _value); static ValueNode ofMemory(std::optional<std::string> _value);
static ValueNode ofNull(); static ValueNode ofNull();
static ValueNode ofColor(Color color); static ValueNode ofColor(Color color);
static ValueNode ofWire(std::optional<std::string> _value); 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 { struct ConditionNode {
bool negated; bool negated;
IdentifierNode functionName; IdentifierNode functionName;
std::vector<ValueNode> params; std::vector<ValueNode> params;
}; };
/** Represents action executed inside if statement class ActionNode : public AstNode {
* */ public:
struct ActionNode : public AstNode {
/** There are two types of action determined by action type */
enum ActionType { enum ActionType {
/** Error actions represent invalid state and cause validation to fail */
ERROR, ERROR,
/** Warning actions represent states that can cause issue when simulating
* model but models created with it are still valid
* */
WARNING WARNING
}; };
EnumNode<ActionType> type; EnumNode<ActionType> type;
/** Message used if condition is fulfilled */
StringNode message; StringNode message;
}; };
/** If statements represents one validation check inside rule */
struct IfStatementNode : public AstNode { struct IfStatementNode : public AstNode {
ConditionNode condition; ConditionNode condition;
ActionNode action; ActionNode action;
}; };
struct RuleNode : public AstNode {
std::vector<IfStatementNode> statements;
};
/***************************************************************************** struct EnumerationNode : public AstNode {
* ATTRIBUTE TYPES * StringNode key;
*****************************************************************************/ ValueNode value;
};
/** Represents popup dialog used to modified attribute inside which it is defined
* */
struct PopupNode : public AstNode { struct PopupNode : public AstNode {
/** Determines type of popup*/
enum PopupType { enum PopupType {
/** Automatic popup is opened when component or connection containing it is defined */
AUTOMATIC, AUTOMATIC,
/** On demand popups are opened on user request usually from context menus*/
ON_DEMAND ON_DEMAND
}; };
std::optional<EnumNode<PopupType>> type; std::optional<EnumNode<PopupType>> type;
/** Title of popup */
std::optional<StringNode> title; std::optional<StringNode> title;
/** Text of popup */
std::optional<StringNode> text; std::optional<StringNode> text;
/** If popup contains an enumeration*/
bool enumerated; bool enumerated;
std::vector<StringPropertyNode> enumeration; std::vector<EnumerationNode> enumeration;
/** Validation rules for given popup */
std::vector<RuleNode> rules; std::vector<RuleNode> rules;
}; };
/** Represents component or connection attribute struct PropertyNode : public AstNode {
* Attributes are values that can programmatically be changed IdentifierNode key;
* if popup is defined ValueNode value;
* */
struct AttributeNode : public AstNode {
/** Type of attribute */
ValueNode::ValueType type;
/** Name of attribute */
IdentifierNode name;
/** Default type of attribute */
std::optional<ValueNode> defaultValue;
/** Popup used to change attribute value */
std::optional<PopupNode> popup;
}; };
/***************************************************************************** struct DisplayItemNode : public AstNode {
* DISPLAY TYPES * IdentifierNode type;
*****************************************************************************/ std::vector<PropertyNode> values;
struct DisplayItemNode; 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;
}
Color asColor(std::vector<SourceError> *errors, const std::string &property, Color _default = Color(0, 0, 0)) {
for (auto &prop: values) {
if (prop.key.value == property) {
if (prop.value.is(ValueNode::COLOR)) {
return prop.value.asColor();
} 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;
}
};
/** Represents how a component or bus is rendered
* Display is made from an list of display items
* */
struct DisplayNode : public AstNode { struct DisplayNode : public AstNode {
std::vector<DisplayItemNode> items; std::vector<DisplayItemNode> items;
}; };
/** DisplayItem represents one rendered item struct PinConnectionNode : public AstNode {
* in source code items are defined similar to json objects enum ConnectionType {
* eg. REQUIRED,
* @code rect { OPTIONAL
* 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);
}; };
/***************************************************************************** StringNode message;
* LIBRARY TYPES * EnumNode<ConnectionType> type;
*****************************************************************************/
/** 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 { struct PinNode : public AstNode {
/** Determines pin type, pin types currently only affect how pins are rendered */
enum PinType { enum PinType {
IN_OUT, IN_OUT,
IN, IN,
OUT OUT
}; };
/** Name of pin */
IdentifierNode name; IdentifierNode name;
/** Type of pin */
EnumNode<PinType> type; EnumNode<PinType> type;
/** Tooltip content displayed on hover over pin */
std::optional<StringNode> tooltip; std::optional<StringNode> tooltip;
/** If present this means pin must be connected to another component or bus to create connection std::optional<PinConnectionNode> connection;
* Connection contains error message shown
* */
std::optional<StringNode> connection;
/** Determines how the pin is displayed */
std::optional<DisplayNode> display; 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; 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;
/** 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 { struct WireNode : public AstNode {
/** Determines type of wires */
enum WireType { enum WireType {
/** Generic wire */
WIRE, WIRE,
/** wired_and can have multiple sources, that are ANDed together */
WIRED_AND, WIRED_AND,
/** wired_and can have multiple sources, that are ORed together */
WIRED_OR, WIRED_OR,
/** r_wire can remain unconnected */
R_WIRE R_WIRE
}; };
EnumNode<WireType> type; EnumNode<WireType> type;
/** Name of wire */
IdentifierNode name; IdentifierNode name;
/** Number of bits inside of a wire */
NumberNode size; NumberNode size;
/** If wire is visible or hidden, this determines how wires are generated in COMDEL */
bool hidden = false; bool hidden = false;
/** If wire isn't connected to anything it is replaced with terminate with terminateWith value */
bool hasTerminateWith; bool hasTerminateWith;
ValueNode terminateWith; ValueNode terminateWith;
}; };
/** Buses dont exist in COMDEL but they are useful struct AttributeNode : public AstNode {
* as they allow us to connect multiple COMDEL wires together ValueNode::ValueType type;
* */
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;
IdentifierNode name; IdentifierNode name;
/** Default used to name instances */ std::optional<ValueNode> defaultValue;
std::optional<IdentifierNode> instanceName; std::optional<PopupNode> popup;
/** 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 { struct ConnectionComponentNode : public AstNode {
IdentifierNode component; IdentifierNode component;
IdentifierNode pin; 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 { struct ConnectionNode : public AstNode {
ConnectionComponentNode first; ConnectionComponentNode first;
std::optional<ConnectionComponentNode> second; std::optional<ConnectionComponentNode> second;
@ -458,22 +324,51 @@ struct ConnectionNode : public AstNode {
IdentifierNode bus; IdentifierNode bus;
std::vector<AttributeNode> attributes; std::vector<AttributeNode> attributes;
/** If connection is of type component-component it contains two pairs of wires */
std::vector<ValueNode> firstWires; std::vector<ValueNode> firstWires;
std::optional<std::vector<ValueNode>> secondWires; std::optional<std::vector<ValueNode>> secondWires;
}; };
/** LibraryNode represent library instance */ 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<IdentifierNode> 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<IdentifierNode> instanceName;
std::optional<StringNode> tooltip;
std::optional<CountNode> count;
std::optional<DisplayNode> display;
std::vector<WireNode> wires;
};
struct LibraryNode : public AstNode { struct LibraryNode : public AstNode {
/** Name of library */
std::optional<StringNode> name; std::optional<StringNode> name;
/** Library info contains generic information about library */
std::optional<StringNode> libraryInfo; std::optional<StringNode> libraryInfo;
/** Contains text that is added to top of COMDEL file */
std::optional<StringNode> header; std::optional<StringNode> header;
/** Contains path to component directory */
std::optional<StringNode> componentDirectory; std::optional<StringNode> componentDirectory;
/** Contains text that is added to top of System component in COMDEL file */
std::optional<StringNode> componentHeader; std::optional<StringNode> componentHeader;
std::vector<AddressSpaceNode> addressSpaces; std::vector<AddressSpaceNode> addressSpaces;
@ -482,64 +377,46 @@ struct LibraryNode : public AstNode {
std::vector<BusNode> buses; std::vector<BusNode> buses;
std::vector<ConnectionNode> connections; std::vector<ConnectionNode> connections;
/** Contains properties used to translate dialog and error messages */
std::vector<PropertyNode> messages; std::vector<PropertyNode> messages;
}; };
/***************************************************************************** // SCHEMA models
* LIBRARY TYPES *
*****************************************************************************/
/** Represents instance of attribute in component or connection instance */
struct InstanceAttributeNode : public AstNode { struct InstanceAttributeNode : public AstNode {
IdentifierNode name; IdentifierNode name;
ValueNode value; ValueNode value;
}; };
/** Represents instance of a component or a bus */
struct InstanceNode : public AstNode { struct InstanceNode : public AstNode {
/** Contains instance name */
IdentifierNode name; IdentifierNode name;
/** Contains component name */
IdentifierNode component; IdentifierNode component;
/** Contains position of component instance */ std::optional<CountNode> position;
std::optional<NumberPairNode> position;
std::vector<InstanceAttributeNode> attributes; std::vector<InstanceAttributeNode> attributes;
/** Contains size of bus instances */
std::optional<NumberNode> size; std::optional<NumberNode> size;
}; };
/** Represents ComponentConnection of a selected instance */ struct ConnectionComponentInstance : public AstNode {
struct ConnectionComponentInstanceNode : public AstNode {
/** Name of component instance */
IdentifierNode instance; IdentifierNode instance;
/** Name of pin */
IdentifierNode pin; IdentifierNode pin;
}; };
/** Represents Connection instance */
struct ConnectionInstanceNode : public AstNode { struct ConnectionInstanceNode : public AstNode {
ConnectionComponentInstanceNode first; ConnectionComponentInstance first;
std::optional<ConnectionComponentInstanceNode> second; std::optional<ConnectionComponentInstance> second;
IdentifierNode bus; IdentifierNode bus;
std::vector<InstanceAttributeNode> attributes; std::vector<InstanceAttributeNode> attributes;
}; };
/** Represent schema instance */
struct SchemaNode : public AstNode { struct SchemaNode : public AstNode {
/** Contains path to library source */
std::optional<StringNode> source; std::optional<StringNode> source;
/** Contains list of instances */
std::vector<InstanceNode> instances; std::vector<InstanceNode> instances;
/** Contains list of connection */
std::vector<ConnectionInstanceNode> connections; std::vector<ConnectionInstanceNode> connections;
/** Contains library */
std::optional<LibraryNode> library; std::optional<LibraryNode> library;
}; };

5
comdel/parser/color.cpp Normal file
View File

@ -0,0 +1,5 @@
//
// Created by bbr on 12.06.22..
//
#include "color.h"

View File

@ -7,12 +7,12 @@
struct Color { struct Color {
unsigned char r = 0; unsigned char r;
unsigned char g = 0; unsigned char g;
unsigned char b = 0; unsigned char b;
unsigned char a = 255; unsigned char a;
Color() = default; Color(): r(0), g(0), b(0), a(0) {}
Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0): r(r), g(g), b(b), a(a) {} Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0): r(r), g(g), b(b), a(a) {}
}; };

View File

@ -11,14 +11,11 @@
#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;
}; };
/** Used to tokenize input string */
class ComdelLexer { class ComdelLexer {
enum Radix { enum Radix {
@ -27,11 +24,9 @@ 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;
@ -41,32 +36,34 @@ public:
LexerResult tokenize(); LexerResult tokenize();
private: private:
/** Current parsing info */ void skipWhitespace();
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

@ -223,22 +223,6 @@ Spanner ComdelParser::getSpanner() {
* *
****************************************************************************/ ****************************************************************************/
/****************************************************************************
*
* ComponentNode :=
* "@name" + StringNode
* "@header" + StringNode
* "@componentHeader" + StringNode
* "@directory" + StringNode
* "@info" + StringNode
* [AddressSpaceNode]{0..N}
* [ComponentNode]{0..N}
* [BusNode]{0..N}
* [ConnectionNode]{0..N}
* @messages "{" + PropertyNode{0..N} + "}"
*
****************************************************************************/
std::optional<LibraryNode> ComdelParser::parseLibrary() { std::optional<LibraryNode> ComdelParser::parseLibrary() {
auto spanner = getSpanner(); auto spanner = getSpanner();
@ -246,15 +230,20 @@ std::optional<LibraryNode> ComdelParser::parseLibrary() {
while (!check(TokenType::END_OF_FILE)) { while (!check(TokenType::END_OF_FILE)) {
PResult<poly<AstNode>> err; PResult<poly<AstNode>> err;
if (consume(TokenType::KW_NAME)) { if (check(TokenType::KW_NAME)) {
bump();
ASSIGN_OR_SET_ERR(library.name, parseString()); ASSIGN_OR_SET_ERR(library.name, parseString());
} else if (consume(TokenType::KW_HEADER)) { } else if (check(TokenType::KW_HEADER)) {
bump();
ASSIGN_OR_SET_ERR(library.header, parseString()); ASSIGN_OR_SET_ERR(library.header, parseString());
} else if (consume(TokenType::KW_COMPONENT_HEADER)) { } else if (check(TokenType::KW_COMPONENT_HEADER)) {
bump();
ASSIGN_OR_SET_ERR(library.componentHeader, parseString()); ASSIGN_OR_SET_ERR(library.componentHeader, parseString());
} else if (consume(TokenType::KW_DIRECTORY)) { } else if (check(TokenType::KW_DIRECTORY)) {
bump();
ASSIGN_OR_SET_ERR(library.componentDirectory, parseString()); ASSIGN_OR_SET_ERR(library.componentDirectory, parseString());
} else if (consume(TokenType::KW_INFO)) { } else if (check(TokenType::KW_INFO)) {
bump();
ASSIGN_OR_SET_ERR(library.libraryInfo, parseString()); ASSIGN_OR_SET_ERR(library.libraryInfo, parseString());
} else if (check(TokenType::KW_ADDRESS)) { } else if (check(TokenType::KW_ADDRESS)) {
APPEND_OR_SET_ERR(library.addressSpaces, parseAddress()); APPEND_OR_SET_ERR(library.addressSpaces, parseAddress());
@ -264,7 +253,8 @@ std::optional<LibraryNode> ComdelParser::parseLibrary() {
APPEND_OR_SET_ERR(library.buses, parseBus()); APPEND_OR_SET_ERR(library.buses, parseBus());
} else if (check(TokenType::KW_CONNECTION)) { } else if (check(TokenType::KW_CONNECTION)) {
APPEND_OR_SET_ERR(library.connections, parseConnection()); APPEND_OR_SET_ERR(library.connections, parseConnection());
} else if (consume(TokenType::KW_MESSAGES)) { } else if (check(TokenType::KW_MESSAGES)) {
bump();
ASSIGN_OR_SET_ERR(library.messages, parseList<PropertyNode>(TokenType::LBRACE, ASSIGN_OR_SET_ERR(library.messages, parseList<PropertyNode>(TokenType::LBRACE,
TokenType::RBRACE, TokenType::RBRACE,
std::nullopt, std::nullopt,
@ -294,7 +284,7 @@ std::optional<LibraryNode> ComdelParser::parseLibrary() {
/**************************************************************************** /****************************************************************************
* *
* StringNode := ('"' + TEXT + '"' | "'" + TEXT + "'") * StringNode := "\"" + CONTENT + "\""
* *
****************************************************************************/ ****************************************************************************/
PResult<StringNode> ComdelParser::parseString() { PResult<StringNode> ComdelParser::parseString() {
@ -302,15 +292,17 @@ PResult<StringNode> ComdelParser::parseString() {
if (check(TokenType::STRING)) { if (check(TokenType::STRING)) {
StringNode node; StringNode node;
node.value = current().text; node.value = current().text;
node.span = current().span;
bump(); bump();
return spanner(node); return spanner(node);
} }
return unexpected(); return unexpected();
} }
/**************************************************************************** /****************************************************************************
* *
* ColorNode := '#' + [0-9A-Fa-f]{6,8} * ColorNode := #RRGGBB[AA]
* *
****************************************************************************/ ****************************************************************************/
PResult<ColorNode> ComdelParser::parseColor() { PResult<ColorNode> ComdelParser::parseColor() {
@ -327,7 +319,7 @@ PResult<ColorNode> ComdelParser::parseColor() {
/**************************************************************************** /****************************************************************************
* *
* IdentifierNode := [_a-zA-Z][_a-zA-Z0-9]* * IdentifierNode := IDENTIFIER
* *
****************************************************************************/ ****************************************************************************/
PResult<IdentifierNode> ComdelParser::parseIdentifier() { PResult<IdentifierNode> ComdelParser::parseIdentifier() {
@ -335,6 +327,7 @@ PResult<IdentifierNode> ComdelParser::parseIdentifier() {
if (check(TokenType::IDENTIFIER)) { if (check(TokenType::IDENTIFIER)) {
IdentifierNode node; IdentifierNode node;
node.value = current().text; node.value = current().text;
node.span = current().span;
bump(); bump();
return spanner(node); return spanner(node);
} }
@ -357,14 +350,16 @@ PResult<NumberNode> ComdelParser::parseNumber() {
return unexpected(); return unexpected();
} }
/**************************************************************************** /****************************************************************************
* *
* NumberPairNode := '(' + NumberNode + ',' + NumberNode + ')' * CountNode := "@size (" + NumberNode + "," + NumberNode + ")"
* *
****************************************************************************/ ****************************************************************************/
PResult<CountNode> ComdelParser::parseCount() {
PResult<NumberPairNode> ComdelParser::parseNumberPair() {
auto spanner = getSpanner(); auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_COUNT);
RETURN_IF_NOT_TOKEN(TokenType::LPAREN); RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
auto first = parseNumber(); auto first = parseNumber();
if (!first.has_value()) { if (!first.has_value()) {
@ -377,41 +372,12 @@ PResult<NumberPairNode> ComdelParser::parseNumberPair() {
} }
RETURN_IF_NOT_TOKEN(TokenType::RPAREN); RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
return spanner(NumberPairNode{*first, *second}); return spanner(CountNode{first.value(), second.value()});
} }
/**************************************************************************** /****************************************************************************
* *
* ValueNode := (IdentifierNode | NumberNode | ColorNode | "NULL" | "true" | "false") * PropertyNode := key: value;
*
****************************************************************************/
PResult<ValueNode> ComdelParser::parseValue() {
auto spanner = getSpanner();
ValueNode value;
if (check(TokenType::IDENTIFIER)) {
value = ValueNode::ofIdentifier(parseIdentifier()->value);
} else if (check(TokenType::STRING)) {
value = ValueNode::ofString(parseString()->asString());
} else if (check(TokenType::NUMBER)) {
value = ValueNode::ofInt(parseNumber()->value);
} else if (consume(TokenType::TRUE)) {
value = ValueNode::ofBool(true);
} else if (consume(TokenType::FALSE)) {
value = ValueNode::ofBool(false);
} else if (consume(TokenType::NIL)) {
value = ValueNode::ofNull();
} else if(check(TokenType::COLOR)) {
value = ValueNode::ofColor(parseColor()->color);
} else {
return unexpected();
}
return spanner(value);
}
/****************************************************************************
*
* PropertyNode := IdentifierNode + ":" + ValueNode + ";"
* *
****************************************************************************/ ****************************************************************************/
PResult<PropertyNode> ComdelParser::parseProperty(std::optional<TokenType> valueType = std::nullopt) { PResult<PropertyNode> ComdelParser::parseProperty(std::optional<TokenType> valueType = std::nullopt) {
@ -421,7 +387,6 @@ PResult<PropertyNode> ComdelParser::parseProperty(std::optional<TokenType> value
RETURN_IF_NOT_TOKEN(TokenType::COLON); RETURN_IF_NOT_TOKEN(TokenType::COLON);
// if valueType is defined value must be of given TokenType
if (valueType.has_value()) { if (valueType.has_value()) {
if (valueType == TokenType::BOOL_TYPE) { if (valueType == TokenType::BOOL_TYPE) {
if (!(check(TokenType::TRUE) || check(TokenType::FALSE))) { if (!(check(TokenType::TRUE) || check(TokenType::FALSE))) {
@ -436,31 +401,16 @@ PResult<PropertyNode> ComdelParser::parseProperty(std::optional<TokenType> value
RETURN_IF_NOT_TOKEN(TokenType::SEMICOLON); RETURN_IF_NOT_TOKEN(TokenType::SEMICOLON);
return spanner(PropertyNode(key, value)); PropertyNode node;
node.key = key;
node.value = value;
return spanner(node);
} }
/**************************************************************************** /****************************************************************************
* *
* StringPropertyNode := StringNode + ":" + ValueNode + ";" * AddressSpaceNode := "@address" + IDENTIFIER "(" + NUMBER + "," + NUMBER + ")"
*
****************************************************************************/
PResult<StringPropertyNode> ComdelParser::parseStringProperty() {
auto spanner = getSpanner();
StringNode key;
ASSIGN_OR_RETURN_IF_ERR(key, parseString());
RETURN_IF_NOT_TOKEN(TokenType::EQUALS);
ValueNode value;
ASSIGN_OR_RETURN_IF_ERR(value, parseValue());
return spanner(StringPropertyNode{key, value});
}
/****************************************************************************
*
* AddressSpaceNode := "@address" + IdentifierNode + NumberPairNode
* *
****************************************************************************/ ****************************************************************************/
PResult<AddressSpaceNode> ComdelParser::parseAddress() { PResult<AddressSpaceNode> ComdelParser::parseAddress() {
@ -471,7 +421,11 @@ PResult<AddressSpaceNode> ComdelParser::parseAddress() {
RETURN_IF_NOT_TOKEN(TokenType::KW_ADDRESS); RETURN_IF_NOT_TOKEN(TokenType::KW_ADDRESS);
ASSIGN_OR_RETURN_IF_ERR(addressSpace.name, parseIdentifier()); ASSIGN_OR_RETURN_IF_ERR(addressSpace.name, parseIdentifier());
ASSIGN_OR_RETURN_IF_ERR(addressSpace.range, parseNumberPair()); RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(addressSpace.start, parseNumber());
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
ASSIGN_OR_RETURN_IF_ERR(addressSpace.end, parseNumber());
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
return spanner(addressSpace); return spanner(addressSpace);
} }
@ -479,17 +433,7 @@ PResult<AddressSpaceNode> ComdelParser::parseAddress() {
/**************************************************************************** /****************************************************************************
* *
* ComponentNode := "@component" + IdentifierNode + ComponentType + "{" * ComponentNode := "@component" + IDENTIFIER + ("processor" | "memory") { COMPONENT_BLOCK }
* "@instanceName" + IdentifierNode
* "@tooltip" + StringNode
* "@source" + StringNode
* "@tooltip" + StringNode
* "@count" + NumberPairNode
* DisplayNode
* [PinNode]{0..N}
* [AttributeNode]{0..N}
* [RuleNode]{0..N}
* "}"
* *
****************************************************************************/ ****************************************************************************/
PResult<ComponentNode> ComdelParser::parseComponent() { PResult<ComponentNode> ComdelParser::parseComponent() {
@ -503,16 +447,20 @@ PResult<ComponentNode> ComdelParser::parseComponent() {
ASSIGN_OR_RETURN_IF_ERR(component.type, parseComponentType()); ASSIGN_OR_RETURN_IF_ERR(component.type, parseComponentType());
RETURN_IF_NOT_TOKEN(TokenType::LBRACE); RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while (!check(TokenType::RBRACE)) { while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err; PResult<poly<AstNode>> err;
if (consume(TokenType::KW_INSTANCE_NAME)) { if (check(TokenType::KW_INSTANCE_NAME)) {
bump();
ASSIGN_OR_SET_ERR(component.instanceName, parseIdentifier()); ASSIGN_OR_SET_ERR(component.instanceName, parseIdentifier());
} else if (consume(TokenType::KW_TOOLTIP)) { } else if (check(TokenType::KW_TOOLTIP)) {
bump();
ASSIGN_OR_SET_ERR(component.tooltip, parseString()); ASSIGN_OR_SET_ERR(component.tooltip, parseString());
} else if (consume(TokenType::KW_SOURCE)) { } else if (check(TokenType::KW_SOURCE)) {
bump();
ASSIGN_OR_SET_ERR(component.source, parseString()); ASSIGN_OR_SET_ERR(component.source, parseString());
} else if (consume(TokenType::KW_COUNT)) { } else if (check(TokenType::KW_COUNT)) {
ASSIGN_OR_SET_ERR(component.count, parseNumberPair()); ASSIGN_OR_SET_ERR(component.count, parseCount());
} else if (check(TokenType::KW_DISPLAY)) { } else if (check(TokenType::KW_DISPLAY)) {
ASSIGN_OR_SET_ERR(component.display, parseDisplay()); ASSIGN_OR_SET_ERR(component.display, parseDisplay());
} else if (check(TokenType::KW_PIN)) { } else if (check(TokenType::KW_PIN)) {
@ -533,25 +481,22 @@ PResult<ComponentNode> ComdelParser::parseComponent() {
} }
} }
} }
RETURN_IF_NOT_TOKEN(TokenType::RBRACE); RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
return spanner(component); return spanner(component);
} }
/****************************************************************************
*
* ComponentType := ["processor" | "memory"]{0,1}
*
****************************************************************************/
PResult<EnumNode<ComponentNode::ComponentType>> ComdelParser::parseComponentType() { PResult<EnumNode<ComponentNode::ComponentType>> ComdelParser::parseComponentType() {
EnumNode<ComponentNode::ComponentType> type; EnumNode<ComponentNode::ComponentType> type;
auto spanner = getSpanner(); auto spanner = getSpanner();
if (consume(TokenType::CT_PROCESSOR)) { if (check(TokenType::CT_PROCESSOR)) {
bump();
type = EnumNode(ComponentNode::PROCESSOR); type = EnumNode(ComponentNode::PROCESSOR);
} else if (consume(TokenType::CT_MEMORY)) { } else if (check(TokenType::CT_MEMORY)) {
bump();
type = EnumNode(ComponentNode::MEMORY); type = EnumNode(ComponentNode::MEMORY);
} else { } else {
type = EnumNode(ComponentNode::OTHER); type = EnumNode(ComponentNode::OTHER);
@ -562,7 +507,7 @@ PResult<EnumNode<ComponentNode::ComponentType>> ComdelParser::parseComponentType
/**************************************************************************** /****************************************************************************
* *
* DisplayNode := "@display {" + DisplayItemNode{0..N} + "}" * DisplayNode := "@display {" + (DISPLAY_ITEM)* + "}"
* *
****************************************************************************/ ****************************************************************************/
PResult<DisplayNode> ComdelParser::parseDisplay() { PResult<DisplayNode> ComdelParser::parseDisplay() {
@ -583,7 +528,7 @@ PResult<DisplayNode> ComdelParser::parseDisplay() {
/**************************************************************************** /****************************************************************************
* *
* DisplayItemNode := IdentifierNode + "{" + PropertyNode{0..N} + "}" * DisplayItemNode := "TYPE {(KEY + ":" + VALUE + ";")*}
* *
****************************************************************************/ ****************************************************************************/
PResult<DisplayItemNode> ComdelParser::parseDisplayItem() { PResult<DisplayItemNode> ComdelParser::parseDisplayItem() {
@ -605,12 +550,7 @@ PResult<DisplayItemNode> ComdelParser::parseDisplayItem() {
/**************************************************************************** /****************************************************************************
* *
* BusNode := "@bus " + IdentifierNode + BusType + "{" * BusNode := "@bus " + NAME + TYPE + "{" + POPUP + "}"
* "@tooltip" + StringNode
* "@instanceName" + StringNode
* DisplayNode
* "@wires {" + [WireNode + ","]{0..N} + WireNode "}"
* "}"
* *
****************************************************************************/ ****************************************************************************/
PResult<BusNode> ComdelParser::parseBus() { PResult<BusNode> ComdelParser::parseBus() {
@ -626,15 +566,18 @@ PResult<BusNode> ComdelParser::parseBus() {
while (!check(TokenType::RBRACE)) { while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err; PResult<poly<AstNode>> err;
if (consume(TokenType::KW_TOOLTIP)) { if (check(TokenType::KW_TOOLTIP)) {
bump();
ASSIGN_OR_SET_ERR(bus.tooltip, parseString()); ASSIGN_OR_SET_ERR(bus.tooltip, parseString());
} else if (consume(TokenType::KW_INSTANCE_NAME)) { } else if (check(TokenType::KW_INSTANCE_NAME)) {
bump();
ASSIGN_OR_SET_ERR(bus.instanceName, parseIdentifier()); ASSIGN_OR_SET_ERR(bus.instanceName, parseIdentifier());
} else if (consume(TokenType::KW_COUNT)) { } else if (check(TokenType::KW_COUNT)) {
ASSIGN_OR_SET_ERR(bus.count, parseNumberPair()); ASSIGN_OR_SET_ERR(bus.count, parseCount());
} else if (check(TokenType::KW_DISPLAY)) { } else if (check(TokenType::KW_DISPLAY)) {
ASSIGN_OR_SET_ERR(bus.display, parseDisplay()); ASSIGN_OR_SET_ERR(bus.display, parseDisplay());
} else if (consume(TokenType::KW_WIRES)) { } else if (check(TokenType::KW_WIRES)) {
bump();
if(consume(TokenType::LBRACE)) { if(consume(TokenType::LBRACE)) {
while (check(TokenType::IDENTIFIER)) { while (check(TokenType::IDENTIFIER)) {
APPEND_OR_RETURN_IF_ERR(bus.wires, parseWire()); APPEND_OR_RETURN_IF_ERR(bus.wires, parseWire());
@ -667,11 +610,6 @@ PResult<BusNode> ComdelParser::parseBus() {
return spanner(bus); return spanner(bus);
} }
/****************************************************************************
*
* BusType := ["automatic" | "regular" | "singleAutomatic"]{0,1}
*
****************************************************************************/
PResult<EnumNode<BusNode::BusType>> ComdelParser::parseBusType() { PResult<EnumNode<BusNode::BusType>> ComdelParser::parseBusType() {
PResult<EnumNode<BusNode::BusType>> type; PResult<EnumNode<BusNode::BusType>> type;
@ -692,9 +630,10 @@ PResult<EnumNode<BusNode::BusType>> ComdelParser::parseBusType() {
return type; return type;
} }
/**************************************************************************** /****************************************************************************
* *
* WireNode := Identifier + ["<" + NumberNode + ">"]{0,1} + WireType{0,1} + "hidden"{0,1} + ["terminated_with" + (NumberNode | NULL)]{0,1} * WireNode := NAME(<SIZE>){0,1} TYPE [hidden | terminated_with (#number | null)])*
* *
****************************************************************************/ ****************************************************************************/
PResult<WireNode> ComdelParser::parseWire() { PResult<WireNode> ComdelParser::parseWire() {
@ -714,22 +653,29 @@ PResult<WireNode> ComdelParser::parseWire() {
// default // default
wire.type = EnumNode(WireNode::WIRE); wire.type = EnumNode(WireNode::WIRE);
if (consume(TokenType::WIRE_DEFAULT)) { if (check(TokenType::WIRE_DEFAULT)) {
bump();
wire.type = EnumNode(WireNode::WIRE); wire.type = EnumNode(WireNode::WIRE);
} else if (consume(TokenType::WIRE_AND)) { } else if (check(TokenType::WIRE_AND)) {
bump();
wire.type = EnumNode(WireNode::WIRED_AND); wire.type = EnumNode(WireNode::WIRED_AND);
} else if (consume(TokenType::WIRE_OR)) { } else if (check(TokenType::WIRE_OR)) {
bump();
wire.type = EnumNode(WireNode::WIRED_OR); wire.type = EnumNode(WireNode::WIRED_OR);
} else if (consume(TokenType::R_WIRE)) { } else if (check(TokenType::R_WIRE)) {
bump();
wire.type = EnumNode(WireNode::R_WIRE); wire.type = EnumNode(WireNode::R_WIRE);
} }
while (true) { while (true) {
if (consume(TokenType::HIDDEN)) { if (check(TokenType::HIDDEN)) {
bump();
wire.hidden = true; wire.hidden = true;
} else if (consume(TokenType::TERMINATE_WITH)) { } else if (check(TokenType::TERMINATE_WITH)) {
bump();
wire.hasTerminateWith = true; wire.hasTerminateWith = true;
if (consume(TokenType::NIL)) { if (check(TokenType::NIL)) {
bump();
wire.terminateWith = ValueNode::ofNull(); wire.terminateWith = ValueNode::ofNull();
} else if (check(TokenType::NUMBER)) { } else if (check(TokenType::NUMBER)) {
auto number = parseNumber(); auto number = parseNumber();
@ -749,12 +695,11 @@ PResult<WireNode> ComdelParser::parseWire() {
/**************************************************************************** /****************************************************************************
* *
* PinNode := "@pin" + IdentifierType + PinType + "{" * PinNode := "@pin" NAME TYPE "{"
* "@tooltip" + StringNode "@tooltip" MESSAGE
* "@connection" + StringNode "@connection" TYPE "(" MESSAGE ")"
* DisplayNode DisplayNode
* "@wires {" + [ConnectionWireNode + ","]{0..N} + ConnectionWireNode + "}" }
* "}"
* *
****************************************************************************/ ****************************************************************************/
PResult<PinNode> ComdelParser::parsePin() { PResult<PinNode> ComdelParser::parsePin() {
@ -765,26 +710,32 @@ PResult<PinNode> ComdelParser::parsePin() {
ASSIGN_OR_RETURN_IF_ERR(pin.name, parseIdentifier()); ASSIGN_OR_RETURN_IF_ERR(pin.name, parseIdentifier());
if (consume(TokenType::PIN_IN)) { if (check(TokenType::PIN_IN)) {
bump();
pin.type = EnumNode(PinNode::IN); pin.type = EnumNode(PinNode::IN);
} else if (consume(TokenType::PIN_OUT)) { } else if (check(TokenType::PIN_OUT)) {
bump();
pin.type = EnumNode(PinNode::OUT); pin.type = EnumNode(PinNode::OUT);
} else if (consume(TokenType::PIN_IN_OUT)) { } else if (check(TokenType::PIN_IN_OUT)) {
bump();
pin.type = EnumNode(PinNode::IN_OUT); pin.type = EnumNode(PinNode::IN_OUT);
} else { } else {
return unexpected(); return unexpected();
} }
RETURN_IF_NOT_TOKEN(TokenType::LBRACE); RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while (!check(TokenType::RBRACE)) { while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err; PResult<poly<AstNode>> err;
if (consume(TokenType::KW_TOOLTIP)) { if (check(TokenType::KW_TOOLTIP)) {
bump();
ASSIGN_OR_SET_ERR(pin.tooltip, parseString()); ASSIGN_OR_SET_ERR(pin.tooltip, parseString());
} else if (check(TokenType::KW_DISPLAY)) { } else if (check(TokenType::KW_DISPLAY)) {
ASSIGN_OR_SET_ERR(pin.display, parseDisplay()); ASSIGN_OR_SET_ERR(pin.display, parseDisplay());
} else if (consume(TokenType::KW_CONNECTION)) { } else if (check(TokenType::KW_CONNECTION)) {
ASSIGN_OR_SET_ERR(pin.connection, parseString()); ASSIGN_OR_SET_ERR(pin.connection, parsePinConnection());
} else if (consume(TokenType::KW_WIRES)) { } else if (check(TokenType::KW_WIRES)) {
bump();
auto wires = parseList<ValueNode>(TokenType::LBRACE, auto wires = parseList<ValueNode>(TokenType::LBRACE,
TokenType::RBRACE, TokenType::RBRACE,
TokenType::COMMA, TokenType::COMMA,
@ -804,14 +755,57 @@ PResult<PinNode> ComdelParser::parsePin() {
} }
} }
} }
RETURN_IF_NOT_TOKEN(TokenType::RBRACE); RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
return spanner(pin); return spanner(pin);
} }
/**************************************************************************** /****************************************************************************
* *
* AttributeNode := "@attribute " + IdentifierNode + ValueType + ("default" + ValueNode){0,1} + ("{" PopupNode "}"){0,1} * PinConnectionNode := "@connection " + ("check_only" | "automatically") + "(" + MESSAGE + ")"
*
****************************************************************************/
PResult<PinConnectionNode> ComdelParser::parsePinConnection() {
auto spanner = getSpanner();
PinConnectionNode connection{};
RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION);
ASSIGN_OR_RETURN_IF_ERR(connection.type, parseConnectionType());
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(connection.message, parseString());
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
return spanner(connection);
}
PResult<EnumNode<PinConnectionNode::ConnectionType>> ComdelParser::parseConnectionType() {
auto spanner = getSpanner();
EnumNode<PinConnectionNode::ConnectionType> type;
if (check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier();
if (identifier.value().value == "required") {
type = EnumNode(PinConnectionNode::REQUIRED);
} else if (identifier.value().value == "optional") {
type = EnumNode(PinConnectionNode::OPTIONAL);
} else {
return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"});
}
} else {
return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"});
}
return spanner(type);
}
/****************************************************************************
*
* AttributeNode := "@attribute " + NAME + TYPE ("default" + VALUE){0,1} ("{" POPUP "}"){0,1}
* *
****************************************************************************/ ****************************************************************************/
PResult<AttributeNode> ComdelParser::parseAttribute() { PResult<AttributeNode> ComdelParser::parseAttribute() {
@ -826,24 +820,27 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
return unexpected(); return unexpected();
} }
if (consume(TokenType::INT_TYPE)) { if (check(TokenType::INT_TYPE)) {
attribute.type = ValueNode::INT; attribute.type = ValueNode::INT;
} else if (consume(TokenType::STRING_TYPE)) { } else if (check(TokenType::STRING_TYPE)) {
attribute.type = ValueNode::STRING; attribute.type = ValueNode::STRING;
} else if (consume(TokenType::BOOL_TYPE)) { } else if (check(TokenType::BOOL_TYPE)) {
attribute.type = ValueNode::BOOL; attribute.type = ValueNode::BOOL;
} else if (consume(TokenType::WIRE_TYPE)) { } else if (check(TokenType::WIRE_TYPE)) {
attribute.type = ValueNode::WIRE; attribute.type = ValueNode::WIRE;
} else { } else {
return unexpected(); return unexpected();
} }
bump();
RETURN_IF_NOT_TOKEN(TokenType::DEFAULT); RETURN_IF_NOT_TOKEN(TokenType::DEFAULT);
if (attribute.type == ValueNode::BOOL) { if (attribute.type == ValueNode::BOOL) {
if (consume(TokenType::TRUE)) { if (check(TokenType::TRUE)) {
bump();
attribute.defaultValue = ValueNode::ofBool(true); attribute.defaultValue = ValueNode::ofBool(true);
} else if (consume(TokenType::FALSE)) { } else if (check(TokenType::FALSE)) {
bump();
attribute.defaultValue = ValueNode::ofBool(false); attribute.defaultValue = ValueNode::ofBool(false);
} else { } else {
return unexpected(); return unexpected();
@ -873,7 +870,8 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
if (check(TokenType::IDENTIFIER)) { if (check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier(); auto identifier = parseIdentifier();
attribute.defaultValue = ValueNode::ofMemory(identifier->value); attribute.defaultValue = ValueNode::ofMemory(identifier->value);
} else if (consume(TokenType::NIL)) { } else if (check(TokenType::NIL)) {
bump();
attribute.defaultValue = ValueNode::ofMemory(std::nullopt); attribute.defaultValue = ValueNode::ofMemory(std::nullopt);
} else { } else {
return unexpected(); return unexpected();
@ -882,7 +880,8 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
if (check(TokenType::IDENTIFIER)) { if (check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier(); auto identifier = parseIdentifier();
attribute.defaultValue = ValueNode::ofWire(identifier->value); attribute.defaultValue = ValueNode::ofWire(identifier->value);
} else if (consume(TokenType::NIL)) { } else if (check(TokenType::NIL)) {
bump();
attribute.defaultValue = ValueNode::ofWire(std::nullopt); attribute.defaultValue = ValueNode::ofWire(std::nullopt);
} else { } else {
return unexpected(); return unexpected();
@ -891,11 +890,12 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
if (check(TokenType::LBRACE)) { if (check(TokenType::LBRACE)) {
RETURN_IF_NOT_TOKEN(TokenType::LBRACE); RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
PopupNode popup;
if (!check(TokenType::KW_POPUP)) { if (!check(TokenType::KW_POPUP)) {
return unexpected(); return unexpected();
} }
PopupNode popup;
ASSIGN_OR_RETURN_IF_ERR(popup, parsePopup()); ASSIGN_OR_RETURN_IF_ERR(popup, parsePopup());
attribute.popup = std::optional<PopupNode>(popup); attribute.popup = std::optional<PopupNode>(popup);
RETURN_IF_NOT_TOKEN(TokenType::RBRACE); RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
@ -906,12 +906,29 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
/**************************************************************************** /****************************************************************************
* *
* PopupNode := "@popup " + ("automatic" | "on_demand") + "{" * Enumeration
* "@title" + StringNode *
* "@text" + StringNode ****************************************************************************/
* [RuleNode]{0..N} PResult<EnumerationNode> ComdelParser::parseEnumeration() {
* "@enumerated {" + [StringPropertyNode + ","]{0..N} + StringPropertyNode + "}" auto spanner = getSpanner();
* "}" StringNode key;
ASSIGN_OR_RETURN_IF_ERR(key, parseString());
RETURN_IF_NOT_TOKEN(TokenType::EQUALS);
ValueNode value;
ASSIGN_OR_RETURN_IF_ERR(value, parseValue());
EnumerationNode node;
node.key = key;
node.value = value;
return spanner(node);
}
/****************************************************************************
*
* PopupNode := "@popup " + ("automatic" | "on_demand") { POPUP BODY }
* *
****************************************************************************/ ****************************************************************************/
PResult<PopupNode> ComdelParser::parsePopup() { PResult<PopupNode> ComdelParser::parsePopup() {
@ -937,21 +954,24 @@ PResult<PopupNode> ComdelParser::parsePopup() {
while (!check(TokenType::RBRACE)) { while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err; PResult<poly<AstNode>> err;
if (consume(TokenType::KW_TITLE)) { if (check(TokenType::KW_TITLE)) {
bump();
ASSIGN_OR_SET_ERR(popup.title, parseString()); ASSIGN_OR_SET_ERR(popup.title, parseString());
} else if (consume(TokenType::KW_TEXT)) { } else if (check(TokenType::KW_TEXT)) {
bump();
ASSIGN_OR_SET_ERR(popup.text, parseString()); ASSIGN_OR_SET_ERR(popup.text, parseString());
} else if (check(TokenType::KW_RULE)) { } else if (check(TokenType::KW_RULE)) {
APPEND_OR_SET_ERR(popup.rules, parseRule()); APPEND_OR_SET_ERR(popup.rules, parseRule());
} else if (consume(TokenType::KW_ENUMERATED)) { } else if (check(TokenType::KW_ENUMERATED)) {
bump();
popup.enumerated = true; popup.enumerated = true;
ASSIGN_OR_SET_ERR(popup.enumeration, ASSIGN_OR_SET_ERR(popup.enumeration,
parseList<StringPropertyNode>( parseList<EnumerationNode>(
TokenType::LBRACE, TokenType::LBRACE,
TokenType::RBRACE, TokenType::RBRACE,
TokenType::COMMA, TokenType::COMMA,
true, true,
[this] { return parseStringProperty(); } [this] { return parseEnumeration(); }
) )
); );
} else { } else {
@ -974,26 +994,7 @@ PResult<PopupNode> ComdelParser::parsePopup() {
/**************************************************************************** /****************************************************************************
* *
* ConnectionComponentNode := IdentifierNode + "." + IdentifierNode * ConnectionNode := "@connection (" + COMPONENT + "." + PIN + "," + BUS [ + "," + COMPONENT2 + "." + "PIN2"] + ") {" + CONNECTION + "}"
*
****************************************************************************/
PResult<ConnectionComponentNode> ComdelParser::parseConnectionComponent() {
auto spanner = getSpanner();
ConnectionComponentNode node;
ASSIGN_OR_RETURN_IF_ERR(node.component, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(node.pin, parseIdentifier());
return spanner(node);
}
/****************************************************************************
*
* ConnectionNode := "@connection (" + ConnectionComponentNode + "," + IdentifierNode + ["," + ConnectionComponentNode]{0,1} + ") {"
* [AttributeNode]{0..N}
* ["@wires {" + [ConnectionWireNode + ","]{0..N} + ConnectionWireNode + "}"]{1,2}
* "}"
* *
****************************************************************************/ ****************************************************************************/
PResult<ConnectionNode> ComdelParser::parseConnection() { PResult<ConnectionNode> ComdelParser::parseConnection() {
@ -1003,24 +1004,33 @@ PResult<ConnectionNode> ComdelParser::parseConnection() {
RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION); RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION);
RETURN_IF_NOT_TOKEN(TokenType::LPAREN); RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(connection.first, parseConnectionComponent()); ASSIGN_OR_RETURN_IF_ERR(connection.first.component, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(connection.first.pin, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::COMMA); RETURN_IF_NOT_TOKEN(TokenType::COMMA);
ASSIGN_OR_RETURN_IF_ERR(connection.bus, parseIdentifier()); ASSIGN_OR_RETURN_IF_ERR(connection.bus, parseIdentifier());
if (check(TokenType::COMMA)) { if (check(TokenType::COMMA)) {
auto conn = ConnectionComponentNode{};
RETURN_IF_NOT_TOKEN(TokenType::COMMA); RETURN_IF_NOT_TOKEN(TokenType::COMMA);
ASSIGN_OR_RETURN_IF_ERR(connection.second, parseConnectionComponent()); ASSIGN_OR_RETURN_IF_ERR(conn.component, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(conn.pin, parseIdentifier());
connection.second = conn;
} }
RETURN_IF_NOT_TOKEN(TokenType::RPAREN); RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
int wireCount = 0; int wireCount = 0;
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while (!check(TokenType::RBRACE)) { while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err; PResult<poly<AstNode>> err;
if (check(TokenType::KW_ATTRIBUTE)) { if (check(TokenType::KW_ATTRIBUTE)) {
APPEND_OR_RETURN_IF_ERR(connection.attributes, parseAttribute()); APPEND_OR_RETURN_IF_ERR(connection.attributes, parseAttribute());
} else if (consume(TokenType::KW_WIRES)) { } else if (check(TokenType::KW_WIRES)) {
bump();
auto wires = parseList<ValueNode>(TokenType::LBRACE, TokenType::RBRACE, TokenType::COMMA, false, auto wires = parseList<ValueNode>(TokenType::LBRACE, TokenType::RBRACE, TokenType::COMMA, false,
[this] { return parseConnectionWire(); }); [this] { return parseConnectionWire(); });
RETURN_IF_ERR(wires); RETURN_IF_ERR(wires);
@ -1053,10 +1063,7 @@ PResult<ConnectionNode> ComdelParser::parseConnection() {
/**************************************************************************** /****************************************************************************
* *
* RuleNode := "@rule {" * RuleNode := "@rule {" + if-else statements + "}"
* IfStatementNode
* ["else" + IfStatementNode]{0..N}
* "}"
* *
****************************************************************************/ ****************************************************************************/
PResult<RuleNode> ComdelParser::parseRule() { PResult<RuleNode> ComdelParser::parseRule() {
@ -1083,9 +1090,7 @@ PResult<RuleNode> ComdelParser::parseRule() {
/**************************************************************************** /****************************************************************************
* *
* IfStatement := "if(" + "!"{0,1} + IdentifierNode + "(" + [ValueNode + ","]{0..N} + ValueNode + ")) {" * IfStatement := "if(!function(params...)) { error(MESSAGE) | warning(MESSAGE) }
* ["error" | "warning"] + "(" + StringNode + ")"
* "}"
* *
****************************************************************************/ ****************************************************************************/
PResult<IfStatementNode> ComdelParser::parseIfStatement() { PResult<IfStatementNode> ComdelParser::parseIfStatement() {
@ -1096,53 +1101,79 @@ PResult<IfStatementNode> ComdelParser::parseIfStatement() {
RETURN_IF_NOT_TOKEN(TokenType::LPAREN); RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
if (consume(TokenType::NOT)) { if (check(TokenType::NOT)) {
ifStatement.condition.negated = true; ifStatement.condition.negated = true;
bump();
} else { } else {
ifStatement.condition.negated = false; ifStatement.condition.negated = false;
} }
ASSIGN_OR_RETURN_IF_ERR(ifStatement.condition.functionName, parseIdentifier()); ASSIGN_OR_RETURN_IF_ERR(ifStatement.condition.functionName, parseIdentifier());
ASSIGN_OR_RETURN_IF_ERR(ifStatement.condition.params, parseList<ValueNode>(TokenType::LPAREN, ASSIGN_OR_RETURN_IF_ERR(ifStatement.condition.params, parseList<ValueNode>(TokenType::LPAREN,
TokenType::RPAREN, TokenType::RPAREN,
TokenType::COMMA, TokenType::COMMA,
false, false,
[this] { return parseValue(); } [this] { return parseValue(); }
)); ));
RETURN_IF_NOT_TOKEN(TokenType::RPAREN); RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
RETURN_IF_NOT_TOKEN(TokenType::LBRACE); RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
if (consume(TokenType::ERROR)) {
if (check(TokenType::ERROR)) {
ifStatement.action.type = EnumNode(ActionNode::ERROR); ifStatement.action.type = EnumNode(ActionNode::ERROR);
} else if (consume(TokenType::WARNING)) { } else if (check(TokenType::WARNING)) {
ifStatement.action.type = EnumNode(ActionNode::WARNING); ifStatement.action.type = EnumNode(ActionNode::WARNING);
} else { } else {
return unexpected(); return unexpected();
} }
bump();
RETURN_IF_NOT_TOKEN(TokenType::LPAREN); RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(ifStatement.action.message, parseString()); ASSIGN_OR_RETURN_IF_ERR(ifStatement.action.message, parseString());
RETURN_IF_NOT_TOKEN(TokenType::RPAREN); RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
RETURN_IF_NOT_TOKEN(TokenType::RBRACE); RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
return spanner(ifStatement); return spanner(ifStatement);
} }
PResult<ValueNode> ComdelParser::parseValue() {
auto spanner = getSpanner();
ValueNode value;
if (check(TokenType::IDENTIFIER)) {
value = ValueNode::ofIdentifier(parseIdentifier()->value);
} else if (check(TokenType::STRING)) {
value = ValueNode::ofString(parseString()->asString());
} else if (check(TokenType::NUMBER)) {
value = ValueNode::ofInt(parseNumber()->value);
} else if (check(TokenType::TRUE)) {
bump();
value = ValueNode::ofBool(true);
} else if (check(TokenType::FALSE)) {
bump();
value = ValueNode::ofBool(false);
} else if (check(TokenType::NIL)) {
bump();
value = ValueNode::ofNull();
} else if(check(TokenType::COLOR)) {
value = ValueNode::ofColor(parseColor()->color);
} else {
return unexpected();
}
return spanner(value);
}
/****************************************************************************
*
* SchemaNode :=
* "@source" + StringNode
* "@schema {"
* [InstanceNode]{0..N}
* [ConnectionInstanceNode]{0..N}
* "}"
*
****************************************************************************/
std::optional<SchemaNode> ComdelParser::parseSchema() { std::optional<SchemaNode> ComdelParser::parseSchema() {
auto spanner = getSpanner(); auto spanner = getSpanner();
SchemaNode schema{}; SchemaNode schema{};
if (consume(TokenType::KW_SOURCE)) { if (check(TokenType::KW_SOURCE)) {
bump();
if (check(TokenType::STRING)) { if (check(TokenType::STRING)) {
auto source = parseString(); auto source = parseString();
schema.source = *source; schema.source = *source;
@ -1155,14 +1186,16 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
return std::nullopt; return std::nullopt;
} }
if (!consume(TokenType::KW_SCHEMA)) { if (!check(TokenType::KW_SCHEMA)) {
errors.emplace_back(current().span, "expected `@schema`"); errors.emplace_back(current().span, "expected `@schema`");
return std::nullopt; return std::nullopt;
} }
if (!consume(TokenType::LBRACE)) { bump();
if (!check(TokenType::LBRACE)) {
errors.emplace_back(current().span, "expected `{`"); errors.emplace_back(current().span, "expected `{`");
return std::nullopt; return std::nullopt;
} }
bump();
while (!check(TokenType::RBRACE)) { while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err; PResult<poly<AstNode>> err;
@ -1183,9 +1216,11 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
} }
} }
} }
if (!consume(TokenType::RBRACE)) { if (!check(TokenType::RBRACE)) {
errors.emplace_back(current().span, "expected `}`"); errors.emplace_back(current().span, "expected `}`");
return std::nullopt; return std::nullopt;
} else {
bump();
} }
if (!check(TokenType::END_OF_FILE)) { if (!check(TokenType::END_OF_FILE)) {
@ -1200,13 +1235,28 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
/**************************************************************************** /****************************************************************************
* *
* InstanceNode := "@instance" + IdentifierNode + IdentifierNode "{" * CountNode := "@position (" + NumberNode + "," + NumberNode + ")"
* "@position" + NumberPairNode
* [InstanceAttributeNode]{0..N}
* "@size" + NumberNode
* "}"
* *
****************************************************************************/ ****************************************************************************/
PResult<CountNode> ComdelParser::parsePosition() {
auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_POSITION);
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
auto first = parseNumber();
if (!first.has_value()) {
return PError(first.error());
}
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
auto second = parseNumber();
if (!second.has_value()) {
return PError(second.error());
}
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
return spanner(CountNode{first.value(), second.value()});
}
PResult<InstanceNode> ComdelParser::parseInstance() { PResult<InstanceNode> ComdelParser::parseInstance() {
auto spanner = getSpanner(); auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_INSTANCE); RETURN_IF_NOT_TOKEN(TokenType::KW_INSTANCE);
@ -1220,11 +1270,12 @@ PResult<InstanceNode> ComdelParser::parseInstance() {
while (!check(TokenType::RBRACE)) { while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err; PResult<poly<AstNode>> err;
if (consume(TokenType::KW_POSITION)) { if (check(TokenType::KW_POSITION)) {
ASSIGN_OR_SET_ERR(instance.position, parseNumberPair()); ASSIGN_OR_SET_ERR(instance.position, parsePosition());
} else if (check(TokenType::KW_ATTRIBUTE)) { } else if (check(TokenType::KW_ATTRIBUTE)) {
APPEND_OR_SET_ERR(instance.attributes, parseInstanceAttribute()); APPEND_OR_SET_ERR(instance.attributes, parseInstanceAttribute());
} else if (consume(TokenType::KW_SIZE)) { } else if (check(TokenType::KW_SIZE)) {
bump();
auto number = parseNumber(); auto number = parseNumber();
RETURN_IF_ERR(number); RETURN_IF_ERR(number);
instance.size = *number; instance.size = *number;
@ -1246,11 +1297,6 @@ PResult<InstanceNode> ComdelParser::parseInstance() {
return spanner(instance); return spanner(instance);
} }
/****************************************************************************
*
* InstanceAttributeNode := "@attribute" + IdentifierNode + ValueNode
*
****************************************************************************/
PResult<InstanceAttributeNode> ComdelParser::parseInstanceAttribute() { PResult<InstanceAttributeNode> ComdelParser::parseInstanceAttribute() {
auto spanner = getSpanner(); auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_ATTRIBUTE); RETURN_IF_NOT_TOKEN(TokenType::KW_ATTRIBUTE);
@ -1262,28 +1308,6 @@ PResult<InstanceAttributeNode> ComdelParser::parseInstanceAttribute() {
return spanner(attribute); return spanner(attribute);
} }
/****************************************************************************
*
* ConnectionComponentInstanceNode := IdentifierNode + "." + IdentifierNode
*
****************************************************************************/
PResult<ConnectionComponentInstanceNode> ComdelParser::parseConnectionComponentInstance() {
auto spanner = getSpanner();
ConnectionComponentInstanceNode node;
ASSIGN_OR_RETURN_IF_ERR(node.instance, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(node.pin, parseIdentifier());
return spanner(node);
}
/****************************************************************************
*
* ConnectionInstanceNode := "@connection (" + ConnectionComponentInstanceNode + "," + IdentifierNode + ["," + ConnectionComponentInstanceNode ] + ") {"
* [InstanceAttributeNode]{0..N}
* "}"
*
****************************************************************************/
PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() { PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
auto spanner = getSpanner(); auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION); RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION);
@ -1291,20 +1315,25 @@ PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
ConnectionInstanceNode connection; ConnectionInstanceNode connection;
RETURN_IF_NOT_TOKEN(TokenType::LPAREN); RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(connection.first, parseConnectionComponentInstance()); ASSIGN_OR_RETURN_IF_ERR(connection.first.instance, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(connection.first.pin, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::COMMA); RETURN_IF_NOT_TOKEN(TokenType::COMMA);
ASSIGN_OR_RETURN_IF_ERR(connection.bus, parseIdentifier()); ASSIGN_OR_RETURN_IF_ERR(connection.bus, parseIdentifier());
if (check(TokenType::COMMA)) { if (check(TokenType::COMMA)) {
bump(); bump();
ConnectionComponentInstanceNode second; ConnectionComponentInstance second;
ASSIGN_OR_RETURN_IF_ERR(second, parseConnectionComponentInstance()); ASSIGN_OR_RETURN_IF_ERR(second.instance, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(second.pin, parseIdentifier());
connection.second = second; connection.second = second;
} }
RETURN_IF_NOT_TOKEN(TokenType::RPAREN); RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
RETURN_IF_NOT_TOKEN(TokenType::LBRACE); RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while (!check(TokenType::RBRACE)) { while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err; PResult<poly<AstNode>> err;
if (check(TokenType::KW_ATTRIBUTE)) { if (check(TokenType::KW_ATTRIBUTE)) {
@ -1321,16 +1350,12 @@ PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
} }
} }
} }
RETURN_IF_NOT_TOKEN(TokenType::RBRACE); RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
return spanner(connection); return spanner(connection);
} }
/****************************************************************************
*
* ConnectionWireNode := [IdentifierNode | StringNode | "NULL" | NumberNode]
*
****************************************************************************/
PResult<ValueNode> ComdelParser::parseConnectionWire() { PResult<ValueNode> ComdelParser::parseConnectionWire() {
auto spanner = getSpanner(); auto spanner = getSpanner();
if (check(TokenType::NUMBER)) { if (check(TokenType::NUMBER)) {
@ -1346,3 +1371,4 @@ PResult<ValueNode> ComdelParser::parseConnectionWire() {
return unexpected(); return unexpected();
} }
} }

View File

@ -42,20 +42,16 @@ 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>
@ -67,45 +63,73 @@ private:
Spanner getSpanner(); Spanner getSpanner();
/** Base types */ // used to parse library and schema
PResult<StringNode> parseString(); PResult<StringNode> parseString();
PResult<ColorNode> parseColor(); PResult<ColorNode> parseColor();
PResult<IdentifierNode> parseIdentifier(); PResult<IdentifierNode> parseIdentifier();
PResult<NumberNode> parseNumber(); PResult<NumberNode> parseNumber();
PResult<NumberPairNode> parseNumberPair();
PResult<CountNode> parseCount();
PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType); PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType);
PResult<StringPropertyNode> parseStringProperty();
PResult<EnumerationNode> parseEnumeration();
PResult<ValueNode> parseConnectionWire();
PResult<ComponentNode> parseComponent();
PResult<AddressSpaceNode> parseAddress();
PResult<PinNode> parsePin();
PResult<DisplayNode> parseDisplay();
PResult<PinConnectionNode> parsePinConnection();
PResult<AttributeNode> parseAttribute();
PResult<PopupNode> parsePopup();
PResult<RuleNode> parseRule();
PResult<BusNode> parseBus();
PResult<WireNode> parseWire();
PResult<ConnectionNode> parseConnection();
PResult<DisplayItemNode> parseDisplayItem();
PResult<IfStatementNode> parseIfStatement();
PResult<ValueNode> parseValue(); PResult<ValueNode> parseValue();
/** Library types */ // used to parse schema
PResult<ValueNode> parseConnectionWire(); PResult<CountNode> parsePosition();
PResult<ComponentNode> parseComponent();
PResult<InstanceNode> parseInstance();
PResult<InstanceAttributeNode> parseInstanceAttribute();
PResult<ConnectionInstanceNode> parseConnectionInstance();
PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType(); PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType();
PResult<AddressSpaceNode> parseAddress();
PResult<PinNode> parsePin();
PResult<DisplayNode> parseDisplay();
PResult<AttributeNode> parseAttribute();
PResult<PopupNode> parsePopup();
PResult<RuleNode> parseRule();
PResult<BusNode> parseBus();
PResult<WireNode> parseWire();
PResult<ConnectionNode> parseConnection();
PResult<ConnectionComponentNode> parseConnectionComponent();
PResult<DisplayItemNode> parseDisplayItem();
PResult<IfStatementNode> parseIfStatement();
PResult<EnumNode<BusNode::BusType>> parseBusType(); PResult<EnumNode<BusNode::BusType>> parseBusType();
/** Schema types */ PResult<EnumNode<PinConnectionNode::ConnectionType>> parseConnectionType();
PResult<InstanceNode> parseInstance();
PResult<InstanceAttributeNode> parseInstanceAttribute();
PResult<ConnectionInstanceNode> parseConnectionInstance();
PResult<ConnectionComponentInstanceNode> parseConnectionComponentInstance();
public: public:
explicit ComdelParser(std::vector<Token> tokens); explicit ComdelParser(std::vector<Token> tokens);
std::optional<SchemaNode> parseSchema(); std::optional<SchemaNode> parseSchema();
std::optional<LibraryNode> parseLibrary(); std::optional<LibraryNode> parseLibrary();
const std::vector<SourceError> &getErrors(); const std::vector<SourceError> &getErrors();
}; };

View File

@ -7,7 +7,6 @@
#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;
@ -23,7 +22,7 @@ public:
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;

View File

@ -101,6 +101,7 @@ enum class TokenType {
KW_SCHEMA, KW_SCHEMA,
KW_POSITION, KW_POSITION,
KW_SIZE, KW_SIZE,
KW_UNKNOWN,
// TYPES // TYPES
INT_TYPE, INT_TYPE,

View File

@ -1,6 +1,5 @@
// Version 0.0.1 // Version 0.0.1
#include "libraries\frisc\vjezba1\FRISC.cdl" #include "libraries\frisc\vjezba1\FRISC.cdl"
#include "libraries\frisc\vjezba1\dma.cdl"
#include "libraries\frisc\vjezba1\memory.cdl" #include "libraries\frisc\vjezba1\memory.cdl"
@ -24,43 +23,31 @@ component System
wire --BACK; wire --BACK;
//PIOSabirnica
wire<8> PIO_DATA;
wire READY;
wire STROBE;
//directRam //directRam
wire INT; wire INT;
// components -------------------------------------------- // components --------------------------------------------
subcomponent Memorija memorija<false, 1, 1024, 8, 0>(ADR, DATA, READ, WRITE, SIZE, WAIT, INT, *, *, *); subcomponent Memorija memorija<false, 1, 65536, 8, 0>(ADR, DATA, READ, WRITE, SIZE, WAIT, *, *, *, INT);
subcomponent FRISC procesor(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, INT, *, *, *); subcomponent FRISC procesor(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, INT, *, *, *);
subcomponent DMA dma<1024>(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, --BREQ, --BACK, 0, 0, *, *);
display { display {
component { x: -104; y: -102; ref: "procesor"; } component { x: -377; y: -302; ref: "procesor"; }
component { x: 39; y: 199; ref: "memorija"; } component { x: -56; y: -80; ref: "memorija"; }
component { x: -352; y: 13; ref: "dma"; }
// glavnaSabirnica bus // glavnaSabirnica bus
rectangle { rectangle {
x: -106; y: 80; x: -377; y: -106;
w: 100; h: 20; w: 100; h: 20;
} }
// PIOSabirnica bus
// directRam bus // directRam bus
line {x1:-54; y1:14; x2:-55; y2:90;} line {x1:-6; y1:-96; x2:-326; y2:-95;}
line {x1:89; y1:183; x2:-55; y2:90;} line {x1:-327; y1:-186; x2:-326; y2:-95;}
line {x1:-236; y1:51; x2:-55; y2:90;} line {x1:-72; y1:-52; x2:-261; y2:-252;}
line {x1:23; y1:227; x2:12; y2:-52;}
} }
} }

View File

@ -60,7 +60,7 @@
} }
@pin glavniPin in { @pin glavniPin in {
@tooltip "pin za spajanje na glavnu sabirnicu" @tooltip "pin za spajanje na glavnu sabirnicu"
@connection "COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu" @connection required("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu")
@display { @display {
pin { pin {
x: 42; y: 100; w: 16; h:16; x: 42; y: 100; w: 16; h:16;
@ -72,6 +72,7 @@
@pin memDirect inOut { @pin memDirect inOut {
@tooltip "pin za izravno spajanje na RAM" @tooltip "pin za izravno spajanje na RAM"
@connection optional("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu")
@display { @display {
pin { pin {
x: 100; y: 42; w: 16; h:16; x: 100; y: 42; w: 16; h:16;
@ -180,7 +181,7 @@
@pin glavniPin inOut { @pin glavniPin inOut {
@tooltip "pin za spajanje na glavnu sabirnicu" @tooltip "pin za spajanje na glavnu sabirnicu"
@connection "COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu" @connection required("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu")
@display { @display {
/* /*
pin { pin {
@ -203,6 +204,7 @@
@pin memDirect inOut { @pin memDirect inOut {
@tooltip "pin za spajanje na procesor" @tooltip "pin za spajanje na procesor"
@connection optional("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu")
@display { @display {
/* /*
pin { pin {
@ -274,7 +276,7 @@
@pin glavniPin in { @pin glavniPin in {
@tooltip "pin za spajanje na glavnu sabirnicu" @tooltip "pin za spajanje na glavnu sabirnicu"
@connection "COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu" @connection required("COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu")
@display { @display {
/* /*
pin { pin {
@ -296,6 +298,7 @@
@pin dodatnaPoveznica in { @pin dodatnaPoveznica in {
@tooltip "pin za spajanje na pomocnu sabirnicu" @tooltip "pin za spajanje na pomocnu sabirnicu"
@connection optional("COMDEL se ne može stvoriti. DMA nije spojen na nesto!")
@display { @display {
pin { pin {
x: 100; y: 7; w: 16; h: 16; x: 100; y: 7; w: 16; h: 16;

View File

@ -2,48 +2,15 @@
@schema { @schema {
@instance procesor FRISC { @instance procesor FRISC {
@position (-104, -102) @position (-543, -304)
@attribute _memory null @attribute _memory null
} }
@instance memorija Memorija {
@position (39, 199)
@attribute sinkroniziran false
@attribute brzina 1
@attribute kapacitet 1024
@attribute size 8
@attribute pocetnaAdresa 0
}
@instance dma DMA {
@position (-352, 13)
@attribute pocetnaAdresa 1024
}
@instance glavnaSabirnica glavnaSabirnica { @instance glavnaSabirnica glavnaSabirnica {
@position (-106, 80) @position (-544, -91)
@size 100 @size 100
} }
@instance PIOSabirnica PIOSabirnica {
@position (0, 0)
@size -1
}
@instance directRam directRam {
@position (0, 0)
@size -1
}
@connection (procesor.glavniPin, glavnaSabirnica) { @connection (procesor.glavniPin, glavnaSabirnica) {
} }
@connection (memorija.glavniPin, glavnaSabirnica) {
}
@connection (dma.glavniPin, glavnaSabirnica) {
@attribute interupt INT0
}
@connection (memorija.memDirect, directRam, procesor.memDirect) {
@attribute procConn "INT"
@attribute memConn "INT"
}
} }

View File

@ -1,17 +1,19 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "application.h" #include "application.h"
#include "comdel/display/dialog/error_dialog.h"
#include "comdel/display/dialog/success_dialog.h"
#include <QFileDialog> #include <QFileDialog>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <comdel/parser/parse_context.h> #include <comdel/parser/parse_context.h>
#include <comdel/domain/comdel_validator.h> #include <comdel/parser/parser_util.h>
#include <comdel/domain/schema_creator.h>
#include <iostream> #include <iostream>
#include <QPlainTextEdit>
#include <comdel/domain/comdel_validator.h>
#include <fstream> #include <fstream>
#include <comdel/domain/comdel_generator.h>
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
@ -53,6 +55,11 @@ void MainWindow::setupUi()
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(libraryDisplay); layout->addWidget(libraryDisplay);
layout->addWidget(schemaParent, 1); layout->addWidget(schemaParent, 1);
log = new QPlainTextEdit();
log->setFont(QFont("Courier"));
log->setReadOnly(false);
schemaLayout->addWidget(log);
} }
void MainWindow::onLoadLibrary() { void MainWindow::onLoadLibrary() {
@ -60,13 +67,13 @@ void MainWindow::onLoadLibrary() {
tr("Otvori biblioteku"), "", tr("Comdel biblioteka (*.csl)")); tr("Otvori biblioteku"), "", tr("Comdel biblioteka (*.csl)"));
if(!filename.isEmpty()) { if(!filename.isEmpty()) {
std::ostringstream output; std::ostringstream output;
log->clear();
auto librarySource = filename.toStdString(); auto librarySource = filename.toStdString();
auto instance = Application::instance(); auto instance = Application::instance();
if(!instance->loadLibrary(librarySource, output)) { if(!instance->loadLibrary(librarySource, output)) {
auto dialog = new display::ErrorDialog(output); log->appendPlainText(QString::fromStdString(output.str()));
dialog->exec();
} }
libraryDisplay->refreshContent(); libraryDisplay->refreshContent();
@ -79,6 +86,7 @@ void MainWindow::onLoadSchema() {
tr("Otvori shemu"), "", tr("Comdel shema (*.csl)")); tr("Otvori shemu"), "", tr("Comdel shema (*.csl)"));
if(!filename.isEmpty()) { if(!filename.isEmpty()) {
std::ostringstream output; std::ostringstream output;
log->clear();
auto schemaSource = filename.toStdString(); auto schemaSource = filename.toStdString();
@ -86,8 +94,7 @@ void MainWindow::onLoadSchema() {
auto result = instance->loadSchema(schemaSource, output); auto result = instance->loadSchema(schemaSource, output);
if(!result.first){ if(!result.first){
formatErrors(result.second, output); formatErrors(result.second, output);
auto dialog = new display::ErrorDialog(output); log->appendPlainText(QString::fromStdString(output.str()));
dialog->exec();
} }
libraryDisplay->refreshContent(); libraryDisplay->refreshContent();
@ -99,6 +106,8 @@ void MainWindow::onStoreScheme() {
auto filename = QFileDialog::getSaveFileName(this, auto filename = QFileDialog::getSaveFileName(this,
tr("Spremi shemu"), "", tr("Comdel shema (*.csl)")); tr("Spremi shemu"), "", tr("Comdel shema (*.csl)"));
if(!filename.isEmpty()) { if(!filename.isEmpty()) {
log->clear();
std::ostringstream output; std::ostringstream output;
if(Application::instance()->generateSchema(output)) { if(Application::instance()->generateSchema(output)) {
@ -106,11 +115,9 @@ void MainWindow::onStoreScheme() {
out<<output.str(); out<<output.str();
out.close(); out.close();
auto dialog = new display::SuccessDialog("Uspješno spremljena shema"); log->appendPlainText("Uspješno spremljena shema\n");
dialog->exec();
} else { } else {
auto dialog = new display::ErrorDialog(output); log->appendPlainText("Greška tijekom spremanja sheme\n");
dialog->exec();
} }
} }
@ -120,23 +127,24 @@ void MainWindow::onGenerateComdel() {
auto filename = QFileDialog::getSaveFileName(this, auto filename = QFileDialog::getSaveFileName(this,
tr("Spremi shemu"), "", tr("Comdel sustav (*.system)")); tr("Spremi shemu"), "", tr("Comdel sustav (*.system)"));
if(!filename.isEmpty()) { if(!filename.isEmpty()) {
log->clear();
std::ostringstream output; std::ostringstream output;
auto validationErrors = Application::instance()->generateComdel(output); auto validationErrors = Application::instance()->generateComdel(output);
std::ostringstream buff; std::ostringstream buff;
formatErrors(validationErrors, buff); formatErrors(validationErrors, buff);
log->appendPlainText(QString::fromStdString(buff.str()));
if(!Application::hasErrors(validationErrors)) { if(!Application::hasErrors(validationErrors)) {
std::ofstream out(filename.toStdString(), std::ios::out | std::ios::binary); std::ofstream out(filename.toStdString(), std::ios::out | std::ios::binary);
out<<output.str(); out<<output.str();
out.close(); out.close();
auto dialog = new display::SuccessDialog("Uspješno generiran comdel model"); log->appendPlainText("Uspješno generiranje comdel modela\n");
dialog->exec();
} else { } else {
auto dialog = new display::ErrorDialog(output); log->appendPlainText("Neuspješno generiranje comdel modela\n");
dialog->exec();
} }
} }
} }
@ -144,17 +152,15 @@ void MainWindow::onGenerateComdel() {
void MainWindow::onValidateSchema(bool /*toggled*/) { void MainWindow::onValidateSchema(bool /*toggled*/) {
log->clear();
auto errors = Application::instance()->validateSchema(); auto errors = Application::instance()->validateSchema();
if(Application::hasErrors(errors)) {
std::ostringstream buff; std::ostringstream buff;
formatErrors(errors, buff); formatErrors(errors, buff);
auto dialog = new display::ErrorDialog(buff);
dialog->exec(); log->appendPlainText(QString::fromStdString(buff.str()));
} else {
auto dialog = new display::SuccessDialog("Nema validacijskih greški");
dialog->exec();
}
} }
void MainWindow::formatErrors(std::vector<domain::ValidationError>& errors, std::ostream& output) { void MainWindow::formatErrors(std::vector<domain::ValidationError>& errors, std::ostream& output) {

View File

@ -40,6 +40,7 @@ private:
display::Library *libraryDisplay; display::Library *libraryDisplay;
display::Schema *schemaDisplay; display::Schema *schemaDisplay;
Ui::MainWindow *ui; Ui::MainWindow *ui;
QPlainTextEdit *log;
static void formatErrors(std::vector<domain::ValidationError>& errors, std::ostream& output); static void formatErrors(std::vector<domain::ValidationError>& errors, std::ostream& output);
}; };