Compare commits
3 Commits
ae2a3c64ef
...
7be3a1b5bc
Author | SHA1 | Date |
---|---|---|
Borna Rajković | 7be3a1b5bc | |
Borna Rajković | fe4a39803c | |
Borna Rajković | 1ec0433cfe |
|
@ -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/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)
|
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)
|
||||||
target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets)
|
target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets)
|
||||||
|
|
|
@ -90,7 +90,7 @@ std::pair<bool, std::vector<domain::ValidationError>> Application::loadSchema(st
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
errorOutput << "Failed parsing library" << std::endl;
|
errorOutput << "Failed schema library" << std::endl;
|
||||||
return {false, errors};
|
return {false, errors};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,283 +0,0 @@
|
||||||
//
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +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"
|
|
||||||
|
|
||||||
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
|
|
|
@ -1,9 +1,10 @@
|
||||||
#include "component_display.h"
|
#include "component_display.h"
|
||||||
#include "attribute_dialog.h"
|
#include "comdel/display/dialog/attribute_dialog.h"
|
||||||
#include "name_dialog.h"
|
#include "comdel/display/dialog/name_dialog.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "single_automatic_dialog.h"
|
#include "comdel/display/dialog/single_automatic_dialog.h"
|
||||||
|
#include "comdel/display/dialog/memory_dialog.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QLine>
|
#include <QLine>
|
||||||
|
@ -45,14 +46,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(attr,
|
auto dialog = new MemoryDialog("Izmjeni memoriju", "Izmjeni", 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(attr);
|
auto dialog = new AttributeDialog("Izmjeni " + attr->name, "Izmjeni", attr);
|
||||||
dialog->exec();
|
dialog->exec();
|
||||||
});
|
});
|
||||||
action->setEnabled(enabled);
|
action->setEnabled(enabled);
|
||||||
|
@ -83,7 +84,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(directConnection->attributes);
|
auto dialog = new SingleAutomaticDialog("Izmjeni sabirnicu", "Izmjeni", directConnection->attributes);
|
||||||
dialog->exec();
|
dialog->exec();
|
||||||
});
|
});
|
||||||
remove->addAction(QString::fromStdString("Ukloni " + connectionName),
|
remove->addAction(QString::fromStdString("Ukloni " + connectionName),
|
||||||
|
@ -109,7 +110,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(attr);
|
auto dialog = new AttributeDialog("Izmjeni '" + attr->name + "'", "Izmjeni", attr);
|
||||||
dialog->exec();
|
dialog->exec();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef ATTRIBUTE_DIALOG_H
|
||||||
|
#define ATTRIBUTE_DIALOG_H
|
||||||
|
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QRadioButton>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <utility>
|
||||||
|
#include "comdel/domain/instance_attribute.h"
|
||||||
|
|
||||||
|
#include "comdel/domain/value.h"
|
||||||
|
#include "comdel/domain/comdel_validator.h"
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class AttributeDialog : public GenericDialog {
|
||||||
|
public:
|
||||||
|
AttributeDialog(std::string title, std::string action, domain::InstanceAttribute *attribute);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onTextChanged(const QString &string);
|
||||||
|
void onEnumerationChanged(int index);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *setupEnumeration();
|
||||||
|
QLineEdit *setupLineEdit(domain::Value::ValueType type);
|
||||||
|
QGroupBox *setupBool();
|
||||||
|
|
||||||
|
std::vector<domain::ValidationError> validate();
|
||||||
|
|
||||||
|
domain::Value value;
|
||||||
|
domain::InstanceAttribute *attributeValue;
|
||||||
|
domain::Popup popup;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //ATTRIBUTE_DIALOG_H
|
|
@ -0,0 +1,34 @@
|
||||||
|
#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
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef SCHEMEEDITOR_ERROR_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_ERROR_DIALOG_H
|
||||||
|
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
#include "comdel/domain/comdel_validator.h"
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class ErrorDialog : public GenericDialog {
|
||||||
|
public:
|
||||||
|
ErrorDialog(std::vector<domain::ValidationError> errors);
|
||||||
|
ErrorDialog(std::ostringstream& errorStream);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // display
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_ERROR_DIALOG_H
|
|
@ -0,0 +1,29 @@
|
||||||
|
#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);
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#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
|
|
@ -0,0 +1,59 @@
|
||||||
|
#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
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef SCHEMEEDITOR_MEMORY_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_MEMORY_DIALOG_H
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
#include "comdel/domain/instance_attribute.h"
|
||||||
|
#include "comdel/domain/instance.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class MemoryDialog : public GenericDialog {
|
||||||
|
public:
|
||||||
|
MemoryDialog(std::string title, std::string action, domain::InstanceAttribute *attribute,
|
||||||
|
std::vector<std::shared_ptr<domain::ComponentInstance>> instances);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QComboBox *setupEnumeration();
|
||||||
|
|
||||||
|
domain::Value value;
|
||||||
|
domain::InstanceAttribute *attributeValue;
|
||||||
|
std::vector<std::string> memoryInstances;
|
||||||
|
|
||||||
|
domain::Popup popup;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // display
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_MEMORY_DIALOG_H
|
|
@ -0,0 +1,39 @@
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,25 +9,29 @@
|
||||||
|
|
||||||
#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 QDialog {
|
class NameDialog : public GenericDialog {
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,7 +1,3 @@
|
||||||
//
|
|
||||||
// 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>
|
||||||
|
@ -9,38 +5,23 @@
|
||||||
#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 *parentLayout = new QVBoxLayout(this);
|
auto *contentLayout = new QHBoxLayout();
|
||||||
auto *contentLayout = new QHBoxLayout(this);
|
auto *firstLayout = new QVBoxLayout();
|
||||||
auto *firstLayout = new QVBoxLayout(this);
|
auto *secondLayout = new QVBoxLayout();
|
||||||
auto *secondLayout = new QVBoxLayout(this);
|
|
||||||
|
|
||||||
parentLayout->addLayout(contentLayout);
|
content->setLayout(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)) {
|
||||||
|
@ -75,10 +56,10 @@ namespace display {
|
||||||
secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue();
|
secondValue = attributes[1].attribute.getPopup()->getEnumeration()[index].getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SingleAutomaticDialog::onUpdate() {
|
bool SingleAutomaticDialog::onUpdate() {
|
||||||
attributes[0].value = firstValue;
|
attributes[0].value = firstValue;
|
||||||
attributes[1].value = secondValue;
|
attributes[1].value = secondValue;
|
||||||
accept();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // display
|
} // display
|
|
@ -1,7 +1,3 @@
|
||||||
//
|
|
||||||
// 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
|
||||||
|
|
||||||
|
@ -10,24 +6,29 @@
|
||||||
#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 QDialog {
|
class SingleAutomaticDialog: public GenericDialog {
|
||||||
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(std::vector<domain::InstanceAttribute>& values, bool updating = true);
|
explicit SingleAutomaticDialog(
|
||||||
|
std::string title,
|
||||||
|
std::string action,
|
||||||
|
std::vector<domain::InstanceAttribute>& values);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override;
|
||||||
void setupValues(QVBoxLayout *layout, domain::InstanceAttribute &attribute, void (display::SingleAutomaticDialog::* handler)(int));
|
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
|
|
@ -0,0 +1,17 @@
|
||||||
|
#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
|
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// Created by bbr on 14.06.22..
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SCHEMEEDITOR_SUCCESS_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_SUCCESS_DIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class SuccessDialog: public QDialog {
|
||||||
|
public:
|
||||||
|
explicit SuccessDialog(std::string message, std::string action = "Ok");
|
||||||
|
};
|
||||||
|
|
||||||
|
} // display
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_SUCCESS_DIALOG_H
|
|
@ -0,0 +1,16 @@
|
||||||
|
#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
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef SCHEMEEDITOR_WARNING_DIALOG_H
|
||||||
|
#define SCHEMEEDITOR_WARNING_DIALOG_H
|
||||||
|
|
||||||
|
#include "generic_dialog.h"
|
||||||
|
#include "comdel/domain/comdel_validator.h"
|
||||||
|
|
||||||
|
namespace display {
|
||||||
|
|
||||||
|
class WarningDialog : public GenericDialog {
|
||||||
|
public:
|
||||||
|
WarningDialog(domain::ValidationError error);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onUpdate() override { return true; };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // display
|
||||||
|
|
||||||
|
#endif //SCHEMEEDITOR_WARNING_DIALOG_H
|
|
@ -1,50 +0,0 @@
|
||||||
//
|
|
||||||
// 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;
|
|
||||||
}
|
|
|
@ -1,8 +1,9 @@
|
||||||
#include "component_display.h"
|
#include "component_display.h"
|
||||||
#include "schema_display.h"
|
#include "schema_display.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
#include "attribute_dialog.h"
|
#include "comdel/display/dialog/attribute_dialog.h"
|
||||||
#include "single_automatic_dialog.h"
|
#include "comdel/display/dialog/single_automatic_dialog.h"
|
||||||
|
#include "comdel/display/dialog/memory_dialog.h"
|
||||||
|
|
||||||
#include <QDrag>
|
#include <QDrag>
|
||||||
#include <QDragEnterEvent>
|
#include <QDragEnterEvent>
|
||||||
|
@ -275,13 +276,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(&attribute, schema->componentInstances, false);
|
auto dialog = new MemoryDialog("Postavi memoriju", "Postavi", &attribute, schema->componentInstances);
|
||||||
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(&attribute, false);
|
auto dialog = new AttributeDialog("Postavi " + attribute.name, "Postavi", &attribute);
|
||||||
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 {};
|
||||||
|
@ -300,7 +301,7 @@ namespace display {
|
||||||
instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr);
|
instanceAttributes.emplace_back(attr.getName(), attr.getDefault(), attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dialog = new display::SingleAutomaticDialog(instanceAttributes, false);
|
auto dialog = new display::SingleAutomaticDialog("Postavi sabirnicu", "Postavi", instanceAttributes);
|
||||||
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 {};
|
||||||
|
|
|
@ -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().getType() == PinConnection::REQUIRED) {
|
if (pin.getConnection().has_value()) {
|
||||||
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().getMessage(), context);
|
auto message = populateMessage(pin.getConnection().value(), context);
|
||||||
errors.emplace_back(Action::ERROR, message);
|
errors.emplace_back(Action::ERROR, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,7 @@
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
PinConnection::PinConnection(std::string message, ConnectionType type)
|
Pin::Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin,
|
||||||
: message(message), type(type) {}
|
|
||||||
|
|
||||||
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) {}
|
||||||
|
|
||||||
|
@ -34,7 +22,7 @@ namespace domain {
|
||||||
return displayPin;
|
return displayPin;
|
||||||
}
|
}
|
||||||
|
|
||||||
PinConnection &Pin::getConnection() {
|
std::optional<std::string> Pin::getConnection() {
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,25 +9,6 @@
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -40,13 +21,13 @@ namespace domain {
|
||||||
std::string name;
|
std::string name;
|
||||||
PinType type;
|
PinType type;
|
||||||
std::string tooltip;
|
std::string tooltip;
|
||||||
PinConnection connection;
|
std::optional<std::string> connection;
|
||||||
domain::ui::Pin displayPin;
|
domain::ui::Pin displayPin;
|
||||||
|
|
||||||
std::optional<std::vector<Value>> wires;
|
std::optional<std::vector<Value>> wires;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin,
|
Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin,
|
||||||
std::optional<std::vector<Value>> wires);
|
std::optional<std::vector<Value>> wires);
|
||||||
|
|
||||||
std::string &getName();
|
std::string &getName();
|
||||||
|
@ -57,7 +38,7 @@ namespace domain {
|
||||||
|
|
||||||
ui::Pin &getDisplayPin();
|
ui::Pin &getDisplayPin();
|
||||||
|
|
||||||
PinConnection &getConnection();
|
std::optional<std::string> getConnection();
|
||||||
|
|
||||||
std::optional<std::vector<Value>> &getWires();
|
std::optional<std::vector<Value>> &getWires();
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
|
|
||||||
namespace domain {
|
namespace domain {
|
||||||
|
|
||||||
|
ComdelContext::ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection)
|
||||||
ComdelContext::ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus)
|
: name(std::move(name)), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection) {}
|
||||||
: 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) {
|
||||||
|
@ -27,7 +26,9 @@ 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;
|
||||||
|
@ -78,29 +79,26 @@ 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.getType() == ValueNode::NIL) {
|
if (node.is(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.getType() == ValueNode::INT) {
|
} else if (node.is(ValueNode::INT)) {
|
||||||
return Value::fromInt(node.asInt());
|
return Value::fromInt(node.asInt());
|
||||||
} else if (node.getType() == ValueNode::STRING) {
|
} else if (node.is(ValueNode::STRING)) {
|
||||||
return Value::fromString(node.asString());
|
return Value::fromString(node.asString());
|
||||||
} else if (node.getType() == ValueNode::NIL) {
|
} else if (node.is(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;
|
||||||
|
@ -110,7 +108,6 @@ 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;
|
||||||
|
@ -120,14 +117,6 @@ 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;
|
||||||
|
@ -135,6 +124,11 @@ 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)) {}
|
||||||
|
|
||||||
|
@ -159,7 +153,6 @@ 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) {
|
||||||
|
@ -201,7 +194,6 @@ namespace domain {
|
||||||
} else {
|
} else {
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Bus> SchemaCreator::loadBus(BusNode node) {
|
std::optional<Bus> SchemaCreator::loadBus(BusNode node) {
|
||||||
|
@ -272,13 +264,12 @@ 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.start.value, node.end.value);
|
return AddressSpace(node.name.value, node.range.first.value, node.range.second.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node) {
|
std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node) {
|
||||||
push(ComdelContext("connection", false, true, false, false));
|
push(ComdelContext("connection", false, true, false));
|
||||||
|
|
||||||
std::string bus = node.bus.value;
|
std::string bus = node.bus.value;
|
||||||
auto busInstance = getBus(bus);
|
auto busInstance = getBus(bus);
|
||||||
|
@ -453,7 +444,6 @@ 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);
|
||||||
|
@ -465,7 +455,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, false));
|
push(ComdelContext(node.name.value, true, false, false));
|
||||||
|
|
||||||
std::string componentName = node.name.value;
|
std::string componentName = node.name.value;
|
||||||
|
|
||||||
|
@ -584,12 +574,10 @@ 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) {
|
||||||
errors.emplace_back(node.span, "missing @connection");
|
connection = node.connection->asString();
|
||||||
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()) {
|
||||||
|
@ -610,47 +598,74 @@ 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 = item.asColor(&errors, "fillColor", Color(255, 255, 255, 255));
|
auto fillColor = readColor(errors, item, "fillColor", Color(255, 255, 255, 255));
|
||||||
auto lineColor = item.asColor(&errors, "lineColor", Color(0, 0, 0, 255));
|
auto lineColor = readColor(errors, item, "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 = item.asColor(&errors, "color", Color(0, 0, 0, 255));
|
auto color = readColor(errors, item, "color", Color(0, 0, 0, 255));
|
||||||
x = item.asInt(&errors, "x");
|
x = readInt(errors, item, "x");
|
||||||
y = item.asInt(&errors, "y");
|
y = readInt(errors, item, "y");
|
||||||
w = item.asInt(&errors, "w");
|
w = readInt(errors, item, "w");
|
||||||
h = item.asInt(&errors, "h");
|
h = readInt(errors, item, "h");
|
||||||
text = item.asString(&errors, "text");
|
text = readString(errors, item, "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 = item.asInt(&errors, "x");
|
x = readInt(errors, item, "x");
|
||||||
y = item.asInt(&errors, "y");
|
y = readInt(errors, item, "y");
|
||||||
w = item.asInt(&errors, "w");
|
w = readInt(errors, item, "w");
|
||||||
h = item.asInt(&errors, "h");
|
h = readInt(errors, item, "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 = item.asInt(&errors, "x1");
|
x1 = readInt(errors, item, "x1");
|
||||||
y1 = item.asInt(&errors, "y1");
|
y1 = readInt(errors, item, "y1");
|
||||||
x2 = item.asInt(&errors, "x2");
|
x2 = readInt(errors, item, "x2");
|
||||||
y2 = item.asInt(&errors, "y2");
|
y2 = readInt(errors, item, "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 = item.asInt(&errors, "x");
|
x = readInt(errors, item, "x");
|
||||||
y = item.asInt(&errors, "y");
|
y = readInt(errors, item, "y");
|
||||||
w = item.asInt(&errors, "w");
|
w = readInt(errors, item, "w");
|
||||||
h = item.asInt(&errors, "h");
|
h = readInt(errors, item, "h");
|
||||||
std::string _orientation = item.asString(&errors, "orientation", "bottom");
|
std::string _orientation = readString(errors, item, "orientation", "bottom");
|
||||||
std::string _pinType = item.asString(&errors, "type", "out");
|
std::string _pinType = readString(errors, item, "type", "out");
|
||||||
|
|
||||||
ui::PinOrientation orientation;
|
ui::PinOrientation orientation;
|
||||||
if (_orientation == "left") {
|
if (_orientation == "left") {
|
||||||
|
@ -679,11 +694,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 = item.asInt(&errors, "x");
|
x = readInt(errors, item, "x");
|
||||||
y = item.asInt(&errors, "y");
|
y = readInt(errors, item, "y");
|
||||||
w = item.asInt(&errors, "w");
|
w = readInt(errors, item, "w");
|
||||||
h = item.asInt(&errors, "h");
|
h = readInt(errors, item, "h");
|
||||||
std::string _orientation = item.asString(&errors, "orientation", "bottom");
|
std::string _orientation = readString(errors, item, "orientation", "bottom");
|
||||||
|
|
||||||
ui::BusOrientation orientation;
|
ui::BusOrientation orientation;
|
||||||
if (_orientation == "horizontal") {
|
if (_orientation == "horizontal") {
|
||||||
|
@ -703,13 +718,6 @@ 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);
|
||||||
|
@ -998,7 +1006,6 @@ 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);
|
||||||
|
|
||||||
|
@ -1103,7 +1110,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, false);
|
ComdelContext con(name, false, false, false);
|
||||||
push(con);
|
push(con);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
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;
|
||||||
|
@ -20,9 +21,8 @@ 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, bool inBus);
|
ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection);
|
||||||
|
|
||||||
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,6 +30,16 @@ 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;
|
||||||
|
@ -43,7 +53,6 @@ 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;
|
||||||
|
|
||||||
|
@ -57,35 +66,25 @@ 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 ¤t();
|
|
||||||
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();
|
||||||
|
|
||||||
public:
|
/** Context stack operations */
|
||||||
explicit SchemaCreator(std::vector<FunctionValidator *> validators);
|
void push(ComdelContext context);
|
||||||
|
void pushAdditional(std::string name);
|
||||||
std::vector<SourceError> getErrors();
|
ComdelContext ¤t();
|
||||||
|
void pop();
|
||||||
std::optional<Library> loadLibrary(LibraryNode node);
|
|
||||||
Schema *loadSchema(SchemaNode node, Library &library);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace domain
|
} // namespace domain
|
||||||
|
|
|
@ -197,4 +197,31 @@ 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
|
||||||
|
|
|
@ -43,32 +43,7 @@ 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();
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
#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) {
|
||||||
|
@ -41,7 +37,11 @@ std::string StringNode::asString() {
|
||||||
|
|
||||||
/*************************** VALUE NODE ********************************/
|
/*************************** VALUE NODE ********************************/
|
||||||
|
|
||||||
long long ValueNode::asInt() {
|
ValueNode::ValueType ValueNode::getType() const {
|
||||||
|
return type.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long int ValueNode::asInt() {
|
||||||
if (is(INT)) {
|
if (is(INT)) {
|
||||||
return intValue.value();
|
return intValue.value();
|
||||||
}
|
}
|
||||||
|
@ -135,3 +135,38 @@ 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;
|
||||||
|
}
|
|
@ -8,28 +8,30 @@
|
||||||
#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;
|
||||||
|
@ -39,284 +41,416 @@ 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;
|
long long int value = 0;
|
||||||
|
|
||||||
explicit NumberNode(const std::string &expression);
|
explicit NumberNode(const std::string &expression);
|
||||||
|
|
||||||
NumberNode() : value(0) {}
|
NumberNode() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 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() {}
|
ColorNode() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Represents ordered number pair */
|
||||||
struct CountNode : public AstNode {
|
struct NumberPairNode : public AstNode {
|
||||||
NumberNode first;
|
NumberNode first;
|
||||||
NumberNode second;
|
NumberNode second;
|
||||||
|
|
||||||
CountNode(NumberNode first, NumberNode second) : first(std::move(first)), second(std::move(second)) {}
|
NumberPairNode(NumberNode first, NumberNode second) : first(first), second(second) {}
|
||||||
|
|
||||||
CountNode() = default;
|
NumberPairNode() = 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:
|
||||||
EnumNode<ValueType> type;
|
/** Type determines what is stored inside ValueNode */
|
||||||
std::optional<long long> intValue;
|
EnumNode<ValueType> type = EnumNode(NIL);
|
||||||
std::optional<std::string> stringValue;
|
/** All possible values for ValueNode are stored inside optionals */
|
||||||
std::optional<bool> boolValue;
|
std::optional<long long> intValue = std::nullopt;
|
||||||
std::optional<std::string> identifierValue;
|
std::optional<std::string> stringValue = std::nullopt;
|
||||||
std::optional<Color> colorValue;
|
std::optional<bool> boolValue = std::nullopt;
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ActionNode : public AstNode {
|
/** Represents action executed inside if statement
|
||||||
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 {
|
/*****************************************************************************
|
||||||
StringNode key;
|
* ATTRIBUTE TYPES *
|
||||||
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<EnumerationNode> enumeration;
|
std::vector<StringPropertyNode> enumeration;
|
||||||
|
|
||||||
|
/** Validation rules for given popup */
|
||||||
std::vector<RuleNode> rules;
|
std::vector<RuleNode> rules;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PropertyNode : public AstNode {
|
/** Represents component or connection attribute
|
||||||
IdentifierNode key;
|
* Attributes are values that can programmatically be changed
|
||||||
ValueNode value;
|
* if popup is defined
|
||||||
|
* */
|
||||||
|
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 {
|
/*****************************************************************************
|
||||||
IdentifierNode type;
|
* DISPLAY TYPES *
|
||||||
std::vector<PropertyNode> values;
|
*****************************************************************************/
|
||||||
|
|
||||||
long long int asInt(std::vector<SourceError> *errors, const std::string &property, long long int _default = 0) {
|
struct DisplayItemNode;
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PinConnectionNode : public AstNode {
|
/** DisplayItem represents one rendered item
|
||||||
enum ConnectionType {
|
* in source code items are defined similar to json objects
|
||||||
REQUIRED,
|
* eg.
|
||||||
OPTIONAL
|
* @code rect {
|
||||||
|
* x: 100;
|
||||||
|
* y: 100;
|
||||||
|
* w: 100;
|
||||||
|
* h: 100;
|
||||||
|
* fillColor: #123456
|
||||||
|
* }
|
||||||
|
* */
|
||||||
|
struct DisplayItemNode : public AstNode {
|
||||||
|
/** Contains type of display item */
|
||||||
|
IdentifierNode type;
|
||||||
|
/** Contains all property nodes */
|
||||||
|
std::vector<PropertyNode> values;
|
||||||
|
|
||||||
|
/** Returns value of requested property
|
||||||
|
* If requested property doesn't exists default value is returned (eg. asInt is called but PropertyNode contains string)
|
||||||
|
* If value of requested property is different than expected nullopt is retured
|
||||||
|
* */
|
||||||
|
std::optional<long long int> asInt(const std::string &property, long long int _default = 0);
|
||||||
|
std::optional<Color> asColor(const std::string &property, Color _default = Color(0, 0, 0));
|
||||||
|
std::optional<std::string> asString(const std::string &property, std::string _default = "");
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::optional<PropertyNode> getProperty(const std::string &property);
|
||||||
};
|
};
|
||||||
|
|
||||||
StringNode message;
|
/*****************************************************************************
|
||||||
EnumNode<ConnectionType> type;
|
* LIBRARY TYPES *
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/** Represents AddressSpaces
|
||||||
|
* Address spaces are defined with their name and address range
|
||||||
|
* */
|
||||||
|
struct AddressSpaceNode : public AstNode {
|
||||||
|
IdentifierNode name;
|
||||||
|
/** Range represent which addresses are available for components that use memory space [first, second> */
|
||||||
|
NumberPairNode range;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Pins are used to create component-component or component-bus connections */
|
||||||
struct PinNode : public AstNode {
|
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;
|
||||||
std::optional<PinConnectionNode> connection;
|
/** If present this means pin must be connected to another component or bus to create connection
|
||||||
|
* Connection contains error message shown
|
||||||
|
* */
|
||||||
|
std::optional<StringNode> connection;
|
||||||
|
/** Determines how the pin is displayed */
|
||||||
std::optional<DisplayNode> display;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AttributeNode : public AstNode {
|
/** Buses dont exist in COMDEL but they are useful
|
||||||
ValueNode::ValueType type;
|
* as they allow us to connect multiple COMDEL wires together
|
||||||
IdentifierNode name;
|
* */
|
||||||
std::optional<ValueNode> defaultValue;
|
struct BusNode : public AstNode {
|
||||||
std::optional<PopupNode> popup;
|
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;
|
||||||
|
/** Default used to name instances */
|
||||||
|
std::optional<IdentifierNode> instanceName;
|
||||||
|
/** Tooltip displayed on hover */
|
||||||
|
std::optional<StringNode> tooltip;
|
||||||
|
/** Count determines number of instances allowed in a schema */
|
||||||
|
std::optional<NumberPairNode> count;
|
||||||
|
/** Display determines how component is rendered */
|
||||||
|
std::optional<DisplayNode> display;
|
||||||
|
|
||||||
|
/** List of all COMDEL wires contained in bus */
|
||||||
|
std::vector<WireNode> wires;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents ComponentConnection key in Connection node
|
||||||
|
* (eg. componentName.pinName)
|
||||||
|
* */
|
||||||
struct ConnectionComponentNode : public AstNode {
|
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;
|
||||||
|
@ -324,51 +458,22 @@ 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ComponentNode : public AstNode {
|
/** LibraryNode represent library instance */
|
||||||
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;
|
||||||
|
@ -377,46 +482,64 @@ 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;
|
||||||
|
|
||||||
std::optional<CountNode> position;
|
/** Contains position of component instance */
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ConnectionComponentInstance : public AstNode {
|
/** Represents ComponentConnection of a selected instance */
|
||||||
|
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 {
|
||||||
ConnectionComponentInstance first;
|
ConnectionComponentInstanceNode first;
|
||||||
std::optional<ConnectionComponentInstance> second;
|
std::optional<ConnectionComponentInstanceNode> 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
//
|
|
||||||
// Created by bbr on 12.06.22..
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "color.h"
|
|
|
@ -7,12 +7,12 @@
|
||||||
|
|
||||||
|
|
||||||
struct Color {
|
struct Color {
|
||||||
unsigned char r;
|
unsigned char r = 0;
|
||||||
unsigned char g;
|
unsigned char g = 0;
|
||||||
unsigned char b;
|
unsigned char b = 0;
|
||||||
unsigned char a;
|
unsigned char a = 255;
|
||||||
|
|
||||||
Color(): r(0), g(0), b(0), a(0) {}
|
Color() = default;
|
||||||
|
|
||||||
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) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,11 +11,14 @@
|
||||||
#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 {
|
||||||
|
@ -24,9 +27,11 @@ 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;
|
||||||
|
|
||||||
|
@ -36,34 +41,32 @@ public:
|
||||||
LexerResult tokenize();
|
LexerResult tokenize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void skipWhitespace();
|
/** Current parsing info */
|
||||||
|
|
||||||
unsigned takeNumberInRadix(Radix radix);
|
|
||||||
|
|
||||||
unsigned takeHexColor();
|
|
||||||
|
|
||||||
bool digitIsValid(char ch, Radix radix);
|
|
||||||
|
|
||||||
Radix takeRadix();
|
|
||||||
|
|
||||||
PResult<TokenType> nextTokenType();
|
|
||||||
|
|
||||||
Position tokenBegin;
|
Position tokenBegin;
|
||||||
Position position;
|
Position position;
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
|
/** Methods used to skip unused content */
|
||||||
|
void skipWhitespace();
|
||||||
void skipComment();
|
void skipComment();
|
||||||
|
|
||||||
bool skipMultilineComment();
|
bool skipMultilineComment();
|
||||||
|
void bump(unsigned count = 1);
|
||||||
|
|
||||||
|
/** Metods used for number parsing */
|
||||||
|
unsigned takeNumberInRadix(Radix radix);
|
||||||
|
bool digitIsValid(char ch, Radix radix);
|
||||||
|
Radix takeRadix();
|
||||||
|
|
||||||
|
unsigned takeHexColor();
|
||||||
|
|
||||||
|
PResult<TokenType> nextTokenType();
|
||||||
|
|
||||||
PResult<TokenType> takeString();
|
PResult<TokenType> takeString();
|
||||||
|
|
||||||
PResult<TokenType> takeRawString();
|
PResult<TokenType> takeRawString();
|
||||||
|
|
||||||
void bump(unsigned count = 1);
|
|
||||||
|
|
||||||
char peek();
|
char peek();
|
||||||
|
|
||||||
|
/** Checks if we reached end of file */
|
||||||
bool eof();
|
bool eof();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -223,6 +223,22 @@ 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();
|
||||||
|
@ -230,20 +246,15 @@ 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 (check(TokenType::KW_NAME)) {
|
if (consume(TokenType::KW_NAME)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(library.name, parseString());
|
ASSIGN_OR_SET_ERR(library.name, parseString());
|
||||||
} else if (check(TokenType::KW_HEADER)) {
|
} else if (consume(TokenType::KW_HEADER)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(library.header, parseString());
|
ASSIGN_OR_SET_ERR(library.header, parseString());
|
||||||
} else if (check(TokenType::KW_COMPONENT_HEADER)) {
|
} else if (consume(TokenType::KW_COMPONENT_HEADER)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(library.componentHeader, parseString());
|
ASSIGN_OR_SET_ERR(library.componentHeader, parseString());
|
||||||
} else if (check(TokenType::KW_DIRECTORY)) {
|
} else if (consume(TokenType::KW_DIRECTORY)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(library.componentDirectory, parseString());
|
ASSIGN_OR_SET_ERR(library.componentDirectory, parseString());
|
||||||
} else if (check(TokenType::KW_INFO)) {
|
} else if (consume(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());
|
||||||
|
@ -253,8 +264,7 @@ 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 (check(TokenType::KW_MESSAGES)) {
|
} else if (consume(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,
|
||||||
|
@ -284,7 +294,7 @@ std::optional<LibraryNode> ComdelParser::parseLibrary() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* StringNode := "\"" + CONTENT + "\""
|
* StringNode := ('"' + TEXT + '"' | "'" + TEXT + "'")
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<StringNode> ComdelParser::parseString() {
|
PResult<StringNode> ComdelParser::parseString() {
|
||||||
|
@ -292,17 +302,15 @@ 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 := #RRGGBB[AA]
|
* ColorNode := '#' + [0-9A-Fa-f]{6,8}
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<ColorNode> ComdelParser::parseColor() {
|
PResult<ColorNode> ComdelParser::parseColor() {
|
||||||
|
@ -319,7 +327,7 @@ PResult<ColorNode> ComdelParser::parseColor() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* IdentifierNode := IDENTIFIER
|
* IdentifierNode := [_a-zA-Z][_a-zA-Z0-9]*
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<IdentifierNode> ComdelParser::parseIdentifier() {
|
PResult<IdentifierNode> ComdelParser::parseIdentifier() {
|
||||||
|
@ -327,7 +335,6 @@ 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);
|
||||||
}
|
}
|
||||||
|
@ -350,16 +357,14 @@ PResult<NumberNode> ComdelParser::parseNumber() {
|
||||||
return unexpected();
|
return unexpected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* CountNode := "@size (" + NumberNode + "," + NumberNode + ")"
|
* NumberPairNode := '(' + NumberNode + ',' + NumberNode + ')'
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<CountNode> ComdelParser::parseCount() {
|
|
||||||
auto spanner = getSpanner();
|
|
||||||
RETURN_IF_NOT_TOKEN(TokenType::KW_COUNT);
|
|
||||||
|
|
||||||
|
PResult<NumberPairNode> ComdelParser::parseNumberPair() {
|
||||||
|
auto spanner = getSpanner();
|
||||||
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()) {
|
||||||
|
@ -372,12 +377,41 @@ PResult<CountNode> ComdelParser::parseCount() {
|
||||||
}
|
}
|
||||||
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
||||||
|
|
||||||
return spanner(CountNode{first.value(), second.value()});
|
return spanner(NumberPairNode{*first, *second});
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* PropertyNode := key: value;
|
* ValueNode := (IdentifierNode | NumberNode | ColorNode | "NULL" | "true" | "false")
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
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) {
|
||||||
|
@ -387,6 +421,7 @@ 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))) {
|
||||||
|
@ -401,16 +436,31 @@ PResult<PropertyNode> ComdelParser::parseProperty(std::optional<TokenType> value
|
||||||
|
|
||||||
RETURN_IF_NOT_TOKEN(TokenType::SEMICOLON);
|
RETURN_IF_NOT_TOKEN(TokenType::SEMICOLON);
|
||||||
|
|
||||||
PropertyNode node;
|
return spanner(PropertyNode(key, value));
|
||||||
node.key = key;
|
|
||||||
node.value = value;
|
|
||||||
|
|
||||||
return spanner(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* AddressSpaceNode := "@address" + IDENTIFIER "(" + NUMBER + "," + NUMBER + ")"
|
* StringPropertyNode := StringNode + ":" + ValueNode + ";"
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
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() {
|
||||||
|
@ -421,11 +471,7 @@ 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());
|
||||||
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
ASSIGN_OR_RETURN_IF_ERR(addressSpace.range, parseNumberPair());
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -433,7 +479,17 @@ PResult<AddressSpaceNode> ComdelParser::parseAddress() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* ComponentNode := "@component" + IDENTIFIER + ("processor" | "memory") { COMPONENT_BLOCK }
|
* ComponentNode := "@component" + IdentifierNode + ComponentType + "{"
|
||||||
|
* "@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() {
|
||||||
|
@ -447,20 +503,16 @@ 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 (check(TokenType::KW_INSTANCE_NAME)) {
|
if (consume(TokenType::KW_INSTANCE_NAME)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(component.instanceName, parseIdentifier());
|
ASSIGN_OR_SET_ERR(component.instanceName, parseIdentifier());
|
||||||
} else if (check(TokenType::KW_TOOLTIP)) {
|
} else if (consume(TokenType::KW_TOOLTIP)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(component.tooltip, parseString());
|
ASSIGN_OR_SET_ERR(component.tooltip, parseString());
|
||||||
} else if (check(TokenType::KW_SOURCE)) {
|
} else if (consume(TokenType::KW_SOURCE)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(component.source, parseString());
|
ASSIGN_OR_SET_ERR(component.source, parseString());
|
||||||
} else if (check(TokenType::KW_COUNT)) {
|
} else if (consume(TokenType::KW_COUNT)) {
|
||||||
ASSIGN_OR_SET_ERR(component.count, parseCount());
|
ASSIGN_OR_SET_ERR(component.count, parseNumberPair());
|
||||||
} 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)) {
|
||||||
|
@ -481,22 +533,25 @@ 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 (check(TokenType::CT_PROCESSOR)) {
|
if (consume(TokenType::CT_PROCESSOR)) {
|
||||||
bump();
|
|
||||||
type = EnumNode(ComponentNode::PROCESSOR);
|
type = EnumNode(ComponentNode::PROCESSOR);
|
||||||
} else if (check(TokenType::CT_MEMORY)) {
|
} else if (consume(TokenType::CT_MEMORY)) {
|
||||||
bump();
|
|
||||||
type = EnumNode(ComponentNode::MEMORY);
|
type = EnumNode(ComponentNode::MEMORY);
|
||||||
} else {
|
} else {
|
||||||
type = EnumNode(ComponentNode::OTHER);
|
type = EnumNode(ComponentNode::OTHER);
|
||||||
|
@ -507,7 +562,7 @@ PResult<EnumNode<ComponentNode::ComponentType>> ComdelParser::parseComponentType
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* DisplayNode := "@display {" + (DISPLAY_ITEM)* + "}"
|
* DisplayNode := "@display {" + DisplayItemNode{0..N} + "}"
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<DisplayNode> ComdelParser::parseDisplay() {
|
PResult<DisplayNode> ComdelParser::parseDisplay() {
|
||||||
|
@ -528,7 +583,7 @@ PResult<DisplayNode> ComdelParser::parseDisplay() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* DisplayItemNode := "TYPE {(KEY + ":" + VALUE + ";")*}
|
* DisplayItemNode := IdentifierNode + "{" + PropertyNode{0..N} + "}"
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<DisplayItemNode> ComdelParser::parseDisplayItem() {
|
PResult<DisplayItemNode> ComdelParser::parseDisplayItem() {
|
||||||
|
@ -550,7 +605,12 @@ PResult<DisplayItemNode> ComdelParser::parseDisplayItem() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* BusNode := "@bus " + NAME + TYPE + "{" + POPUP + "}"
|
* BusNode := "@bus " + IdentifierNode + BusType + "{"
|
||||||
|
* "@tooltip" + StringNode
|
||||||
|
* "@instanceName" + StringNode
|
||||||
|
* DisplayNode
|
||||||
|
* "@wires {" + [WireNode + ","]{0..N} + WireNode "}"
|
||||||
|
* "}"
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<BusNode> ComdelParser::parseBus() {
|
PResult<BusNode> ComdelParser::parseBus() {
|
||||||
|
@ -566,18 +626,15 @@ PResult<BusNode> ComdelParser::parseBus() {
|
||||||
|
|
||||||
while (!check(TokenType::RBRACE)) {
|
while (!check(TokenType::RBRACE)) {
|
||||||
PResult<poly<AstNode>> err;
|
PResult<poly<AstNode>> err;
|
||||||
if (check(TokenType::KW_TOOLTIP)) {
|
if (consume(TokenType::KW_TOOLTIP)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(bus.tooltip, parseString());
|
ASSIGN_OR_SET_ERR(bus.tooltip, parseString());
|
||||||
} else if (check(TokenType::KW_INSTANCE_NAME)) {
|
} else if (consume(TokenType::KW_INSTANCE_NAME)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(bus.instanceName, parseIdentifier());
|
ASSIGN_OR_SET_ERR(bus.instanceName, parseIdentifier());
|
||||||
} else if (check(TokenType::KW_COUNT)) {
|
} else if (consume(TokenType::KW_COUNT)) {
|
||||||
ASSIGN_OR_SET_ERR(bus.count, parseCount());
|
ASSIGN_OR_SET_ERR(bus.count, parseNumberPair());
|
||||||
} 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 (check(TokenType::KW_WIRES)) {
|
} else if (consume(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());
|
||||||
|
@ -610,6 +667,11 @@ 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;
|
||||||
|
|
||||||
|
@ -630,10 +692,9 @@ PResult<EnumNode<BusNode::BusType>> ComdelParser::parseBusType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* WireNode := NAME(<SIZE>){0,1} TYPE [hidden | terminated_with (#number | null)])*
|
* WireNode := Identifier + ["<" + NumberNode + ">"]{0,1} + WireType{0,1} + "hidden"{0,1} + ["terminated_with" + (NumberNode | NULL)]{0,1}
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<WireNode> ComdelParser::parseWire() {
|
PResult<WireNode> ComdelParser::parseWire() {
|
||||||
|
@ -653,29 +714,22 @@ PResult<WireNode> ComdelParser::parseWire() {
|
||||||
// default
|
// default
|
||||||
wire.type = EnumNode(WireNode::WIRE);
|
wire.type = EnumNode(WireNode::WIRE);
|
||||||
|
|
||||||
if (check(TokenType::WIRE_DEFAULT)) {
|
if (consume(TokenType::WIRE_DEFAULT)) {
|
||||||
bump();
|
|
||||||
wire.type = EnumNode(WireNode::WIRE);
|
wire.type = EnumNode(WireNode::WIRE);
|
||||||
} else if (check(TokenType::WIRE_AND)) {
|
} else if (consume(TokenType::WIRE_AND)) {
|
||||||
bump();
|
|
||||||
wire.type = EnumNode(WireNode::WIRED_AND);
|
wire.type = EnumNode(WireNode::WIRED_AND);
|
||||||
} else if (check(TokenType::WIRE_OR)) {
|
} else if (consume(TokenType::WIRE_OR)) {
|
||||||
bump();
|
|
||||||
wire.type = EnumNode(WireNode::WIRED_OR);
|
wire.type = EnumNode(WireNode::WIRED_OR);
|
||||||
} else if (check(TokenType::R_WIRE)) {
|
} else if (consume(TokenType::R_WIRE)) {
|
||||||
bump();
|
|
||||||
wire.type = EnumNode(WireNode::R_WIRE);
|
wire.type = EnumNode(WireNode::R_WIRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (check(TokenType::HIDDEN)) {
|
if (consume(TokenType::HIDDEN)) {
|
||||||
bump();
|
|
||||||
wire.hidden = true;
|
wire.hidden = true;
|
||||||
} else if (check(TokenType::TERMINATE_WITH)) {
|
} else if (consume(TokenType::TERMINATE_WITH)) {
|
||||||
bump();
|
|
||||||
wire.hasTerminateWith = true;
|
wire.hasTerminateWith = true;
|
||||||
if (check(TokenType::NIL)) {
|
if (consume(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();
|
||||||
|
@ -695,11 +749,12 @@ PResult<WireNode> ComdelParser::parseWire() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* PinNode := "@pin" NAME TYPE "{"
|
* PinNode := "@pin" + IdentifierType + PinType + "{"
|
||||||
"@tooltip" MESSAGE
|
* "@tooltip" + StringNode
|
||||||
"@connection" TYPE "(" MESSAGE ")"
|
* "@connection" + StringNode
|
||||||
DisplayNode
|
* DisplayNode
|
||||||
}
|
* "@wires {" + [ConnectionWireNode + ","]{0..N} + ConnectionWireNode + "}"
|
||||||
|
* "}"
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<PinNode> ComdelParser::parsePin() {
|
PResult<PinNode> ComdelParser::parsePin() {
|
||||||
|
@ -710,32 +765,26 @@ PResult<PinNode> ComdelParser::parsePin() {
|
||||||
|
|
||||||
ASSIGN_OR_RETURN_IF_ERR(pin.name, parseIdentifier());
|
ASSIGN_OR_RETURN_IF_ERR(pin.name, parseIdentifier());
|
||||||
|
|
||||||
if (check(TokenType::PIN_IN)) {
|
if (consume(TokenType::PIN_IN)) {
|
||||||
bump();
|
|
||||||
pin.type = EnumNode(PinNode::IN);
|
pin.type = EnumNode(PinNode::IN);
|
||||||
} else if (check(TokenType::PIN_OUT)) {
|
} else if (consume(TokenType::PIN_OUT)) {
|
||||||
bump();
|
|
||||||
pin.type = EnumNode(PinNode::OUT);
|
pin.type = EnumNode(PinNode::OUT);
|
||||||
} else if (check(TokenType::PIN_IN_OUT)) {
|
} else if (consume(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 (check(TokenType::KW_TOOLTIP)) {
|
if (consume(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 (check(TokenType::KW_CONNECTION)) {
|
} else if (consume(TokenType::KW_CONNECTION)) {
|
||||||
ASSIGN_OR_SET_ERR(pin.connection, parsePinConnection());
|
ASSIGN_OR_SET_ERR(pin.connection, parseString());
|
||||||
} else if (check(TokenType::KW_WIRES)) {
|
} else if (consume(TokenType::KW_WIRES)) {
|
||||||
bump();
|
|
||||||
auto wires = parseList<ValueNode>(TokenType::LBRACE,
|
auto wires = parseList<ValueNode>(TokenType::LBRACE,
|
||||||
TokenType::RBRACE,
|
TokenType::RBRACE,
|
||||||
TokenType::COMMA,
|
TokenType::COMMA,
|
||||||
|
@ -755,57 +804,14 @@ PResult<PinNode> ComdelParser::parsePin() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
||||||
|
|
||||||
return spanner(pin);
|
return spanner(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* PinConnectionNode := "@connection " + ("check_only" | "automatically") + "(" + MESSAGE + ")"
|
* AttributeNode := "@attribute " + IdentifierNode + ValueType + ("default" + ValueNode){0,1} + ("{" PopupNode "}"){0,1}
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
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() {
|
||||||
|
@ -820,27 +826,24 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
|
||||||
return unexpected();
|
return unexpected();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check(TokenType::INT_TYPE)) {
|
if (consume(TokenType::INT_TYPE)) {
|
||||||
attribute.type = ValueNode::INT;
|
attribute.type = ValueNode::INT;
|
||||||
} else if (check(TokenType::STRING_TYPE)) {
|
} else if (consume(TokenType::STRING_TYPE)) {
|
||||||
attribute.type = ValueNode::STRING;
|
attribute.type = ValueNode::STRING;
|
||||||
} else if (check(TokenType::BOOL_TYPE)) {
|
} else if (consume(TokenType::BOOL_TYPE)) {
|
||||||
attribute.type = ValueNode::BOOL;
|
attribute.type = ValueNode::BOOL;
|
||||||
} else if (check(TokenType::WIRE_TYPE)) {
|
} else if (consume(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 (check(TokenType::TRUE)) {
|
if (consume(TokenType::TRUE)) {
|
||||||
bump();
|
|
||||||
attribute.defaultValue = ValueNode::ofBool(true);
|
attribute.defaultValue = ValueNode::ofBool(true);
|
||||||
} else if (check(TokenType::FALSE)) {
|
} else if (consume(TokenType::FALSE)) {
|
||||||
bump();
|
|
||||||
attribute.defaultValue = ValueNode::ofBool(false);
|
attribute.defaultValue = ValueNode::ofBool(false);
|
||||||
} else {
|
} else {
|
||||||
return unexpected();
|
return unexpected();
|
||||||
|
@ -870,8 +873,7 @@ 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 (check(TokenType::NIL)) {
|
} else if (consume(TokenType::NIL)) {
|
||||||
bump();
|
|
||||||
attribute.defaultValue = ValueNode::ofMemory(std::nullopt);
|
attribute.defaultValue = ValueNode::ofMemory(std::nullopt);
|
||||||
} else {
|
} else {
|
||||||
return unexpected();
|
return unexpected();
|
||||||
|
@ -880,8 +882,7 @@ 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 (check(TokenType::NIL)) {
|
} else if (consume(TokenType::NIL)) {
|
||||||
bump();
|
|
||||||
attribute.defaultValue = ValueNode::ofWire(std::nullopt);
|
attribute.defaultValue = ValueNode::ofWire(std::nullopt);
|
||||||
} else {
|
} else {
|
||||||
return unexpected();
|
return unexpected();
|
||||||
|
@ -890,12 +891,11 @@ 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,29 +906,12 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* Enumeration
|
* PopupNode := "@popup " + ("automatic" | "on_demand") + "{"
|
||||||
*
|
* "@title" + StringNode
|
||||||
****************************************************************************/
|
* "@text" + StringNode
|
||||||
PResult<EnumerationNode> ComdelParser::parseEnumeration() {
|
* [RuleNode]{0..N}
|
||||||
auto spanner = getSpanner();
|
* "@enumerated {" + [StringPropertyNode + ","]{0..N} + StringPropertyNode + "}"
|
||||||
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() {
|
||||||
|
@ -954,24 +937,21 @@ PResult<PopupNode> ComdelParser::parsePopup() {
|
||||||
|
|
||||||
while (!check(TokenType::RBRACE)) {
|
while (!check(TokenType::RBRACE)) {
|
||||||
PResult<poly<AstNode>> err;
|
PResult<poly<AstNode>> err;
|
||||||
if (check(TokenType::KW_TITLE)) {
|
if (consume(TokenType::KW_TITLE)) {
|
||||||
bump();
|
|
||||||
ASSIGN_OR_SET_ERR(popup.title, parseString());
|
ASSIGN_OR_SET_ERR(popup.title, parseString());
|
||||||
} else if (check(TokenType::KW_TEXT)) {
|
} else if (consume(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 (check(TokenType::KW_ENUMERATED)) {
|
} else if (consume(TokenType::KW_ENUMERATED)) {
|
||||||
bump();
|
|
||||||
popup.enumerated = true;
|
popup.enumerated = true;
|
||||||
ASSIGN_OR_SET_ERR(popup.enumeration,
|
ASSIGN_OR_SET_ERR(popup.enumeration,
|
||||||
parseList<EnumerationNode>(
|
parseList<StringPropertyNode>(
|
||||||
TokenType::LBRACE,
|
TokenType::LBRACE,
|
||||||
TokenType::RBRACE,
|
TokenType::RBRACE,
|
||||||
TokenType::COMMA,
|
TokenType::COMMA,
|
||||||
true,
|
true,
|
||||||
[this] { return parseEnumeration(); }
|
[this] { return parseStringProperty(); }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -994,7 +974,26 @@ PResult<PopupNode> ComdelParser::parsePopup() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* ConnectionNode := "@connection (" + COMPONENT + "." + PIN + "," + BUS [ + "," + COMPONENT2 + "." + "PIN2"] + ") {" + CONNECTION + "}"
|
* ConnectionComponentNode := IdentifierNode + "." + IdentifierNode
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
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() {
|
||||||
|
@ -1004,33 +1003,24 @@ 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.component, parseIdentifier());
|
ASSIGN_OR_RETURN_IF_ERR(connection.first, parseConnectionComponent());
|
||||||
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(conn.component, parseIdentifier());
|
ASSIGN_OR_RETURN_IF_ERR(connection.second, parseConnectionComponent());
|
||||||
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 (check(TokenType::KW_WIRES)) {
|
} else if (consume(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);
|
||||||
|
@ -1063,7 +1053,10 @@ PResult<ConnectionNode> ComdelParser::parseConnection() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* RuleNode := "@rule {" + if-else statements + "}"
|
* RuleNode := "@rule {"
|
||||||
|
* IfStatementNode
|
||||||
|
* ["else" + IfStatementNode]{0..N}
|
||||||
|
* "}"
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<RuleNode> ComdelParser::parseRule() {
|
PResult<RuleNode> ComdelParser::parseRule() {
|
||||||
|
@ -1090,7 +1083,9 @@ PResult<RuleNode> ComdelParser::parseRule() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* IfStatement := "if(!function(params...)) { error(MESSAGE) | warning(MESSAGE) }
|
* IfStatement := "if(" + "!"{0,1} + IdentifierNode + "(" + [ValueNode + ","]{0..N} + ValueNode + ")) {"
|
||||||
|
* ["error" | "warning"] + "(" + StringNode + ")"
|
||||||
|
* "}"
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
PResult<IfStatementNode> ComdelParser::parseIfStatement() {
|
PResult<IfStatementNode> ComdelParser::parseIfStatement() {
|
||||||
|
@ -1101,79 +1096,53 @@ PResult<IfStatementNode> ComdelParser::parseIfStatement() {
|
||||||
|
|
||||||
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
||||||
|
|
||||||
if (check(TokenType::NOT)) {
|
if (consume(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 (check(TokenType::WARNING)) {
|
} else if (consume(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 (check(TokenType::KW_SOURCE)) {
|
if (consume(TokenType::KW_SOURCE)) {
|
||||||
bump();
|
|
||||||
if (check(TokenType::STRING)) {
|
if (check(TokenType::STRING)) {
|
||||||
auto source = parseString();
|
auto source = parseString();
|
||||||
schema.source = *source;
|
schema.source = *source;
|
||||||
|
@ -1186,16 +1155,14 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!check(TokenType::KW_SCHEMA)) {
|
if (!consume(TokenType::KW_SCHEMA)) {
|
||||||
errors.emplace_back(current().span, "expected `@schema`");
|
errors.emplace_back(current().span, "expected `@schema`");
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
bump();
|
if (!consume(TokenType::LBRACE)) {
|
||||||
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;
|
||||||
|
@ -1216,11 +1183,9 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!check(TokenType::RBRACE)) {
|
if (!consume(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)) {
|
||||||
|
@ -1235,28 +1200,13 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
*
|
*
|
||||||
* CountNode := "@position (" + NumberNode + "," + NumberNode + ")"
|
* InstanceNode := "@instance" + IdentifierNode + IdentifierNode "{"
|
||||||
|
* "@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);
|
||||||
|
@ -1270,12 +1220,11 @@ PResult<InstanceNode> ComdelParser::parseInstance() {
|
||||||
|
|
||||||
while (!check(TokenType::RBRACE)) {
|
while (!check(TokenType::RBRACE)) {
|
||||||
PResult<poly<AstNode>> err;
|
PResult<poly<AstNode>> err;
|
||||||
if (check(TokenType::KW_POSITION)) {
|
if (consume(TokenType::KW_POSITION)) {
|
||||||
ASSIGN_OR_SET_ERR(instance.position, parsePosition());
|
ASSIGN_OR_SET_ERR(instance.position, parseNumberPair());
|
||||||
} 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 (check(TokenType::KW_SIZE)) {
|
} else if (consume(TokenType::KW_SIZE)) {
|
||||||
bump();
|
|
||||||
auto number = parseNumber();
|
auto number = parseNumber();
|
||||||
RETURN_IF_ERR(number);
|
RETURN_IF_ERR(number);
|
||||||
instance.size = *number;
|
instance.size = *number;
|
||||||
|
@ -1297,6 +1246,11 @@ 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);
|
||||||
|
@ -1308,6 +1262,28 @@ 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);
|
||||||
|
@ -1315,25 +1291,20 @@ 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.instance, parseIdentifier());
|
ASSIGN_OR_RETURN_IF_ERR(connection.first, parseConnectionComponentInstance());
|
||||||
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();
|
||||||
ConnectionComponentInstance second;
|
ConnectionComponentInstanceNode second;
|
||||||
ASSIGN_OR_RETURN_IF_ERR(second.instance, parseIdentifier());
|
ASSIGN_OR_RETURN_IF_ERR(second, parseConnectionComponentInstance());
|
||||||
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)) {
|
||||||
|
@ -1350,12 +1321,16 @@ 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)) {
|
||||||
|
@ -1371,4 +1346,3 @@ PResult<ValueNode> ComdelParser::parseConnectionWire() {
|
||||||
return unexpected();
|
return unexpected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,16 +42,20 @@ private:
|
||||||
|
|
||||||
Span &getPreviousSpan();
|
Span &getPreviousSpan();
|
||||||
|
|
||||||
|
/** Skips current token */
|
||||||
void bump();
|
void bump();
|
||||||
|
/** Checks if next token is of given type and if it is consumes it */
|
||||||
bool consume(TokenType tokenType);
|
bool consume(TokenType tokenType);
|
||||||
|
/** Checks if next token is of given type */
|
||||||
bool check(TokenType tokenType);
|
bool check(TokenType tokenType);
|
||||||
|
/** Skips until next keyword on same level
|
||||||
|
* Used to continue parsing on error
|
||||||
|
* */
|
||||||
void skipUntilNextKeyword();
|
void skipUntilNextKeyword();
|
||||||
|
/** Retuns current token */
|
||||||
Token ¤t();
|
Token ¤t();
|
||||||
|
|
||||||
|
/** Throws error of unexpected types */
|
||||||
[[nodiscard]] PError unexpected();
|
[[nodiscard]] PError unexpected();
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -63,73 +67,45 @@ private:
|
||||||
|
|
||||||
Spanner getSpanner();
|
Spanner getSpanner();
|
||||||
|
|
||||||
// used to parse library and schema
|
/** Base types */
|
||||||
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();
|
||||||
|
|
||||||
// used to parse schema
|
/** Library types */
|
||||||
PResult<CountNode> parsePosition();
|
PResult<ValueNode> parseConnectionWire();
|
||||||
|
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();
|
||||||
|
|
||||||
PResult<EnumNode<PinConnectionNode::ConnectionType>> parseConnectionType();
|
/** Schema types */
|
||||||
|
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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#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;
|
||||||
|
@ -22,7 +23,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;
|
||||||
|
|
|
@ -101,7 +101,6 @@ enum class TokenType {
|
||||||
KW_SCHEMA,
|
KW_SCHEMA,
|
||||||
KW_POSITION,
|
KW_POSITION,
|
||||||
KW_SIZE,
|
KW_SIZE,
|
||||||
KW_UNKNOWN,
|
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
INT_TYPE,
|
INT_TYPE,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// 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"
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,31 +24,43 @@ 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, 65536, 8, 0>(ADR, DATA, READ, WRITE, SIZE, WAIT, *, *, *, INT);
|
subcomponent Memorija memorija<false, 1, 1024, 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: -377; y: -302; ref: "procesor"; }
|
component { x: -104; y: -102; ref: "procesor"; }
|
||||||
component { x: -56; y: -80; ref: "memorija"; }
|
component { x: 39; y: 199; ref: "memorija"; }
|
||||||
|
component { x: -352; y: 13; ref: "dma"; }
|
||||||
|
|
||||||
// glavnaSabirnica bus
|
// glavnaSabirnica bus
|
||||||
|
|
||||||
rectangle {
|
rectangle {
|
||||||
x: -377; y: -106;
|
x: -106; y: 80;
|
||||||
w: 100; h: 20;
|
w: 100; h: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// PIOSabirnica bus
|
||||||
|
|
||||||
|
|
||||||
// directRam bus
|
// directRam bus
|
||||||
|
|
||||||
|
|
||||||
line {x1:-6; y1:-96; x2:-326; y2:-95;}
|
line {x1:-54; y1:14; x2:-55; y2:90;}
|
||||||
line {x1:-327; y1:-186; x2:-326; y2:-95;}
|
line {x1:89; y1:183; x2:-55; y2:90;}
|
||||||
line {x1:-72; y1:-52; x2:-261; y2:-252;}
|
line {x1:-236; y1:51; x2:-55; y2:90;}
|
||||||
|
line {x1:23; y1:227; x2:12; y2:-52;}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 required("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu")
|
@connection "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,7 +72,6 @@
|
||||||
|
|
||||||
@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;
|
||||||
|
@ -181,7 +180,7 @@
|
||||||
|
|
||||||
@pin glavniPin inOut {
|
@pin glavniPin inOut {
|
||||||
@tooltip "pin za spajanje na glavnu sabirnicu"
|
@tooltip "pin za spajanje na glavnu sabirnicu"
|
||||||
@connection required("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu")
|
@connection "COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu"
|
||||||
@display {
|
@display {
|
||||||
/*
|
/*
|
||||||
pin {
|
pin {
|
||||||
|
@ -204,7 +203,6 @@
|
||||||
|
|
||||||
@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 {
|
||||||
|
@ -276,7 +274,7 @@
|
||||||
|
|
||||||
@pin glavniPin in {
|
@pin glavniPin in {
|
||||||
@tooltip "pin za spajanje na glavnu sabirnicu"
|
@tooltip "pin za spajanje na glavnu sabirnicu"
|
||||||
@connection required("COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu")
|
@connection "COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu"
|
||||||
@display {
|
@display {
|
||||||
/*
|
/*
|
||||||
pin {
|
pin {
|
||||||
|
@ -298,7 +296,6 @@
|
||||||
|
|
||||||
@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;
|
||||||
|
|
|
@ -2,15 +2,48 @@
|
||||||
|
|
||||||
@schema {
|
@schema {
|
||||||
@instance procesor FRISC {
|
@instance procesor FRISC {
|
||||||
@position (-543, -304)
|
@position (-104, -102)
|
||||||
@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 (-544, -91)
|
@position (-106, 80)
|
||||||
@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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
#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/parser/parser_util.h>
|
#include <comdel/domain/comdel_validator.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)
|
||||||
|
@ -55,11 +53,6 @@ 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() {
|
||||||
|
@ -67,13 +60,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)) {
|
||||||
log->appendPlainText(QString::fromStdString(output.str()));
|
auto dialog = new display::ErrorDialog(output);
|
||||||
|
dialog->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryDisplay->refreshContent();
|
libraryDisplay->refreshContent();
|
||||||
|
@ -86,7 +79,6 @@ 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();
|
||||||
|
|
||||||
|
@ -94,7 +86,8 @@ 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);
|
||||||
log->appendPlainText(QString::fromStdString(output.str()));
|
auto dialog = new display::ErrorDialog(output);
|
||||||
|
dialog->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
libraryDisplay->refreshContent();
|
libraryDisplay->refreshContent();
|
||||||
|
@ -106,8 +99,6 @@ 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)) {
|
||||||
|
@ -115,9 +106,11 @@ void MainWindow::onStoreScheme() {
|
||||||
out<<output.str();
|
out<<output.str();
|
||||||
out.close();
|
out.close();
|
||||||
|
|
||||||
log->appendPlainText("Uspješno spremljena shema\n");
|
auto dialog = new display::SuccessDialog("Uspješno spremljena shema");
|
||||||
|
dialog->exec();
|
||||||
} else {
|
} else {
|
||||||
log->appendPlainText("Greška tijekom spremanja sheme\n");
|
auto dialog = new display::ErrorDialog(output);
|
||||||
|
dialog->exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,24 +120,23 @@ 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();
|
||||||
|
|
||||||
log->appendPlainText("Uspješno generiranje comdel modela\n");
|
auto dialog = new display::SuccessDialog("Uspješno generiran comdel model");
|
||||||
|
dialog->exec();
|
||||||
} else {
|
} else {
|
||||||
log->appendPlainText("Neuspješno generiranje comdel modela\n");
|
auto dialog = new display::ErrorDialog(output);
|
||||||
|
dialog->exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,15 +144,17 @@ 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);
|
||||||
log->appendPlainText(QString::fromStdString(buff.str()));
|
dialog->exec();
|
||||||
|
} 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) {
|
||||||
|
|
|
@ -40,7 +40,6 @@ 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);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue