Compare commits

...

13 Commits

Author SHA1 Message Date
Borna Rajković e2e0506041 Added support for @componentHeader 2022-05-16 01:02:34 +02:00
Borna Rajković 59b19062ff Added support for memory attribute 2022-05-15 23:55:03 +02:00
Borna Rajković bb423c2184 Added warning and error dialogs to attribute change 2022-05-15 18:38:17 +02:00
Borna Rajković 65020c2b7f Updated name dialog 2022-05-15 17:00:20 +02:00
Borna Rajković 23764776f1 Updated attribute dialog 2022-05-15 16:13:29 +02:00
Borna Rajković 05fa2abbb0 Refactored function validators 2022-05-15 11:17:05 +02:00
Borna Rajković e7fd7df154 Added display code generation 2022-05-14 15:58:44 +02:00
Borna Rajković 45a668fc46 Added comdel system generation
// todo display generation
2022-05-09 00:51:47 +02:00
Borna Rajković 74a7ef3e7a Refactored instances 2022-05-08 15:47:47 +02:00
Borna Rajković fb8aafb2a9 Updated support for single automatic bus 2022-05-08 14:50:56 +02:00
Borna Rajković 9ff6633777 Removed @wire from schema 2022-05-07 18:28:31 +02:00
Borna Rajković 5ccd9b2fa4 Cleaned up connections 2022-05-07 14:19:43 +02:00
Borna Rajković 344fe7cfa6 Refactor 2022-05-07 13:20:09 +02:00
50 changed files with 1514 additions and 676 deletions

View File

@ -38,5 +38,5 @@ add_executable(SchemeEditor
comdel/parser/comdellexer.cpp
main.cpp
mainwindow.ui
comdel/domain/comdelvalidator.cpp comdel/domain/comdelvalidator.h comdel/display/dialogmanager.cpp comdel/display/dialogmanager.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h)
comdel/domain/comdelvalidator.cpp comdel/domain/comdelvalidator.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h)
target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets)

View File

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

View File

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

View File

@ -1,129 +1,49 @@
#include "component_display.h"
#include "attribute_dialog.h"
#include "name_dialog.h"
#include "mainwindow.h"
#include <QMenu>
#include <QGraphicsSceneContextMenuEvent>
#include <QGraphicsScene>
#include <iostream>
#include "dialogmanager.h"
namespace display {
ComponentWrapper *ComponentWrapper::ofWire(domain::WireInstance *wire) {
auto component = new ComponentWrapper();
component->wireInstance = wire;
component->redraw();
return component;
}
ComponentWrapper *ComponentWrapper::ofComponent(domain::ComponentInstance *instance) {
auto component = new ComponentWrapper();
component->componentInstance = instance;
component->setFlag(QGraphicsItem::ItemIsMovable, true);
component->componentItem = new ComponentItem(instance, component);
for(auto& pin: instance->component.getPins()) {
component->pinItems.push_back(new PinItem(pin, component));
}
component->redraw();
return component;
}
ComponentWrapper *ComponentWrapper::ofBus(domain::BusInstance *instance) {
auto component = new ComponentWrapper();
component->busInstance = instance;
component->setFlag(QGraphicsItem::ItemIsMovable, true);
component->redraw();
return component;
}
void ComponentWrapper::clear() {
for(auto item: childItems()) {
this->removeFromGroup(item);
item->scene()->removeItem(item);
delete item;
}
if(componentInstance) {
componentItem->clear();
for(auto pinItem: pinItems) {
pinItem->clear();
}
}
}
void ComponentWrapper::redraw() {
if(componentInstance) {
addToGroup(componentItem);
componentItem->redraw();
for(auto pinItem: pinItems) {
addToGroup(pinItem);
pinItem->redraw();
}
this->addToGroup(new QGraphicsSimpleTextItem(QString::fromStdString(componentInstance->name)));
}
if(busInstance && busInstance->bus.getDisplay()) {
busInstance->bus.getDisplay()->render(this);
this->addToGroup(new QGraphicsSimpleTextItem(QString::fromStdString(busInstance->name)));
}
if(wireInstance) {
wireInstance->display.render(this);
this->addToGroup(new QGraphicsSimpleTextItem(QString::fromStdString(wireInstance->name)));
}
}
ComponentItem::ComponentItem(domain::ComponentInstance *instance, QGraphicsItem *parent): componentInstance(instance) {
setParentItem(parent);
redraw();
setToolTip(QString::fromStdString(this->componentInstance->component.getTooltip()));
}
void ComponentItem::redraw() {
componentInstance->component.getDisplay().render(this);
}
void ComponentItem::clear() {
for(auto item: childItems()) {
this->removeFromGroup(item);
item->scene()->removeItem(item);
delete item;
}
}
void ComponentItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
QMenu menu;
auto instance = this->componentInstance;
menu.addAction("Izmjeni ime", [instance, this](){
DialogManager::updateName(instance);
auto *wrapper = static_cast<ComponentWrapper*>(this->parentItem());
wrapper->clear();
wrapper->redraw();
menu.addAction("Izmjeni ime", [this](){
auto dialog = new NameDialog(this->instance.get());
dialog->exec();
});
menu.addSeparator();
for(auto attr: componentInstance->attributes) {
for(int i=0; i<this->instance->attributes.size(); i++) {
auto* attr = &this->instance->attributes[i];
bool enabled = attr->attribute.getPopup().has_value();
auto action = menu.addAction(QString::fromStdString("Izmjeni " + attr->name),
[attr, this]() {
DialogManager::updateAttribute(attr);
this->redraw();
[attr]() {
if(attr->value.getType() == domain::Value::MEMORY_REFERENCE) {
auto dialog = new MemoryDialog(attr, MainWindow::getSchema()->componentInstances);
dialog->exec();
} else {
auto dialog = new AttributeDialog(attr);
dialog->exec();
}
});
action->setEnabled(enabled);
}
menu.exec(event->screenPos());
}
PinItem::PinItem(domain::Pin pin, QGraphicsItem *parent): pin(pin) {
setParentItem(parent);
redraw();
setToolTip(QString::fromStdString(pin.getTooltip()));
}
void PinItem::redraw() {
pin.getDisplay().render(this);
}
void PinItem::clear() {
for(auto item: childItems()) {
this->removeFromGroup(item);
item->scene()->removeItem(item);
delete item;
}
void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
QMenu menu;
menu.addAction("Izmjeni ime", [this](){
auto dialog = new NameDialog(this->busInstance.get());
dialog->exec();
});
menu.exec(event->screenPos());
}
} // namespace display

View File

@ -8,65 +8,71 @@
namespace display {
class ComponentItem: public QGraphicsItemGroup
class Pin: public QGraphicsItemGroup
{
public:
ComponentItem(domain::ComponentInstance *instance, QGraphicsItem *parent);
void redraw();
void clear();
private:
domain::ComponentInstance *componentInstance;
domain::Pin pin;
public:
Pin(domain::Pin pin): pin(pin) {
pin.getDisplay().render(this);
}
};
class Component: public QGraphicsItemGroup
{
private:
std::shared_ptr<domain::ComponentInstance> instance;
public:
Component(const std::shared_ptr<domain::ComponentInstance>& instance): instance(instance) {
instance->component.getDisplay().render(this);
}
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
};
class PinItem: public QGraphicsItemGroup
class Bus: public QGraphicsItemGroup
{
std::shared_ptr<domain::BusInstance> busInstance;
public:
PinItem(domain::Pin pin, QGraphicsItem *parent);
void redraw();
void clear();
private:
domain::Pin pin;
Bus(const std::shared_ptr<domain::BusInstance>& instance): busInstance(instance) {
instance->bus.getDisplay()->render(this);
}
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
};
class ComponentWrapper: public QGraphicsItemGroup
class ComponentGroup: public QGraphicsItemGroup
{
public:
static ComponentWrapper *ofComponent(domain::ComponentInstance *instance);
static ComponentWrapper *ofBus(domain::BusInstance *instance);
static ComponentWrapper *ofWire(domain::WireInstance *wire);
ComponentWrapper() {
this->setHandlesChildEvents(false);
}
void redraw();
void clear();
QVariant itemChange( GraphicsItemChange change, const QVariant &value ) override
{
auto response = QGraphicsItem::itemChange(change, value);
if (change == ItemPositionChange){
if(componentInstance != nullptr) {
componentInstance->position.first = (int)scenePos().x();
componentInstance->position.second = (int)scenePos().y();
} else if(busInstance != nullptr) {
busInstance->position.first = (int)scenePos().x();
busInstance->position.second = (int)scenePos().y();
}
}
return response;
}
private:
domain::ComponentInstance *componentInstance = nullptr;
domain::BusInstance *busInstance = nullptr;
domain::WireInstance *wireInstance = nullptr;
std::shared_ptr<domain::ComponentInstance> componentInstance;
ComponentItem *componentItem;
std::vector<PinItem*> pinItems;
public:
explicit ComponentGroup(const std::shared_ptr<domain::ComponentInstance>& instance): componentInstance(instance) {
setFlag(ItemIsMovable, true);
setHandlesChildEvents(false);
addToGroup(new display::Component(instance));
for(auto &pin: instance->component.getPins()) {
addToGroup(new display::Pin(pin));
}
setPos(instance->position.first, instance->position.second);
}
};
class BusGroup: public QGraphicsItemGroup
{
private:
std::shared_ptr<domain::BusInstance> busInstance;
public:
explicit BusGroup(const std::shared_ptr<domain::BusInstance>& instance): busInstance(instance) {
setFlag(ItemIsMovable, true);
setHandlesChildEvents(false);
addToGroup(new display::Bus(instance));
setPos(instance->position.first, instance->position.second);
}
};
} // namespace display

View File

@ -1,21 +0,0 @@
//
// Created by bbr on 18. 04. 2022..
//
#include "dialogmanager.h"
#include "attribute_dialog.h"
#include "name_dialog.h"
namespace display {
void DialogManager::updateAttribute(domain::InstanceAttribute *attribute) {
auto dialog = new AttributeDialog(attribute);
dialog->exec();
}
void DialogManager::updateName(domain::ComponentInstance *instance) {
auto dialog = new NameDialog(instance);
dialog->exec();
}
}

View File

@ -1,18 +0,0 @@
#ifndef DIALOG_MANAGER_H
#define DIALOG_MANAGER_H
#include <comdel/domain/instanceattribute.h>
#include <comdel/domain/instance.h>
namespace display {
class DialogManager {
public:
static void updateAttribute(domain::InstanceAttribute *attribute);
static void updateName(domain::ComponentInstance *instance);
};
}
#endif //DIALOG_MANAGER_H

View File

@ -13,12 +13,27 @@ namespace display {
class NameDialog: public QDialog {
QLineEdit *edit;
domain::ComponentInstance *instance;
QLineEdit *edit = nullptr;
domain::ComponentInstance *componentInstance = nullptr;
domain::BusInstance *busInstance = nullptr;
public:
NameDialog(domain::ComponentInstance *instance): instance(instance) {
NameDialog(domain::ComponentInstance *instance): componentInstance(instance) {
auto *layout = new QVBoxLayout(this);
layout->addWidget(new QLabel("Izmjeni ime", this));
edit = new QLineEdit(this);
edit->insert(instance->name.c_str());
layout->addWidget(edit);
this->setWindowTitle("Izmjeni ime");
auto *button = new QPushButton("Ažuriraj", this);
connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange);
layout->addWidget(button);
this->setLayout(layout);
}
NameDialog(domain::BusInstance *instance): busInstance(instance) {
auto *layout = new QVBoxLayout(this);
layout->addWidget(new QLabel("Izmjeni ime", this));
@ -34,7 +49,11 @@ public:
public slots:
void onNameChange() {
instance->name = this->edit->text().toStdString();
if(componentInstance != nullptr) {
componentInstance->name = this->edit->text().toStdString();
} else if(busInstance != nullptr) {
busInstance->name = this->edit->text().toStdString();
}
this->close();
}
};

View File

@ -9,30 +9,18 @@ Schema::Schema()
}
void Schema::setSchema(domain::Schema* schema)
void Schema::setSchema(domain::Schema* _schema)
{
scene.clear();
this->schema = schema;
this->schema = _schema;
if(schema != nullptr) {
for(auto &instance: schema->instances) {
ComponentWrapper *group = nullptr;
auto component = dynamic_cast<domain::ComponentInstance*>(instance);
if(component) {
group = ComponentWrapper::ofComponent(component);
}
auto bus = dynamic_cast<domain::BusInstance*>(instance);
if(bus) {
group = ComponentWrapper::ofBus(bus);
}
if(group != nullptr) {
group->setPos(instance->position.first, instance->position.second);
scene.addItem(group);
}
for(auto &instance: schema->componentInstances) {
scene.addItem(new display::ComponentGroup(instance));
}
for(auto &wire: schema->wires) {
auto group = ComponentWrapper::ofWire(wire);
group->setPos(wire->position.first, wire->position.second);
scene.addItem(group);
for(auto &instance: schema->busInstances) {
if(instance->bus.getDisplay().has_value()) {
scene.addItem(new display::BusGroup(instance));
}
}
}
}

View File

@ -20,7 +20,6 @@ private:
QGraphicsScene scene;
domain::Schema* schema;
};
} // namespace display

View File

@ -1,3 +1,4 @@
#include <algorithm>
#include "addressspace.h"
namespace domain {

View File

@ -6,7 +6,7 @@ Enumeration::Enumeration(std::string name, Value value)
: name(name), value(value)
{}
std::string Enumeration::getName() {
std::string& Enumeration::getName() {
return name;
}
Value Enumeration::getValue() {

View File

@ -1,6 +1,7 @@
#ifndef DOMAIN_ATTRIBUTE_H
#define DOMAIN_ATTRIBUTE_H
#include <utility>
#include <vector>
#include "rule.h"
@ -14,7 +15,7 @@ class Enumeration {
public:
Enumeration(std::string name, Value value);
std::string getName();
std::string& getName();
Value getValue();
};
@ -45,6 +46,11 @@ public:
bool isEnumerated();
std::vector<Enumeration> &getEnumeration();
void setEnumeration(std::vector<Enumeration> enums) {
enumerated = true;
enumeration = std::move(enums);
}
};
class Attribute

View File

@ -47,7 +47,7 @@ public:
enum BusType {
AUTOMATIC,
REGULAR,
AUTOMATIC_SINGLE
SINGLE_AUTOMATIC
};
private:
std::string name;

View File

@ -0,0 +1,339 @@
//
// Created by bbr on 08.05.22..
//
#include <set>
#include "comdel_generator.h"
namespace domain {
void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream &buffer) {
buffer << "@source " << librarySource << std::endl << std::endl;
buffer << "@schema {" << std::endl;
for(auto &componentInstance: schema->componentInstances) {
buffer << "\t" << "@instance " << componentInstance->name << " " << componentInstance->component.getName() << " {" << std::endl;
buffer << "\t\t" << "@position (" << componentInstance->position.first << ", " << componentInstance->position.second << ")" << std::endl;
for(auto &attribute: componentInstance->attributes) {
buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl;
}
buffer << "\t}" << std::endl << std::endl;
}
for(auto &busInstance: schema->busInstances) {
buffer << "\t" << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {" << std::endl;
buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second << ")" << std::endl;
buffer << "\t\t" << "@size " << busInstance->size << std::endl;
buffer << "\t}" << std::endl << std::endl;
}
for(auto &conn: schema->connections) {
auto busConn = dynamic_cast<domain::BusConnectionInstance*>(conn.get());
if(busConn) {
buffer << "\t" << "@connection (" << busConn->instance->name << "." << busConn->connection.getComponent().pin << ", " << busConn->bus->name << ") {" << std::endl;
for(auto attribute: busConn->attributes) {
buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl;
}
buffer << "\t" << "}" << std::endl;
}
auto dirConn = dynamic_cast<domain::DirectConnectionInstance*>(conn.get());
if(dirConn) {
buffer << "\t" << "@connection (" << dirConn->instance->name << "." << dirConn->connection.getComponent().pin << ", "
<< dirConn->bus->name << ", "
<< dirConn->secondInstance->name << "." << dirConn->connection.getSecondComponent()->pin
<< ") {" << std::endl;
for(auto attribute: dirConn->attributes) {
buffer << "\t\t" << "@attribute " << attribute.name << " " << attribute.value.stringify() << std::endl;
}
buffer << "\t" << "}" << std::endl;
}
}
buffer << "}" << std::endl;
}
std::set<std::string> createImports(Schema *schema);
std::map<string, string> generateWires(Schema *schema, ostream &ostream);
void generateSubComponents(Schema *schema, map <string, string> &wires, ostream &buffer);
void generateDisplay(Schema *schema, ostream &buffer);
void generateComdelFile(Schema *schema, Library &library, std::ostream &buffer) {
buffer << library.getHeader() << std::endl;
std::set<std::string> imports = createImports(schema);
for(auto& import: imports) {
buffer << "#include \"" << library.getComponentDirectory() << "\\" << import << "\"" << std::endl;
}
buffer << "\n\n" << std::endl;
buffer << "component System" << std::endl << "{" << std::endl;
if(library.getComponentHeader().has_value()) {
buffer << library.getComponentHeader().value() << endl;
}
auto wires = generateWires(schema, buffer);
generateSubComponents(schema, wires, buffer);
generateDisplay(schema, buffer);
buffer << "}";
}
void generateBus(BusInstance *bus, ostream &buffer);
void generateDisplay(Schema *schema, ostream &buffer) {
buffer << "\n\tdisplay {\n";
for(auto &component: schema->componentInstances) {
buffer << "\t\tcomponent { x: " << component->position.first << "; y: " << component->position.second << "; ref: \"" << component->name << "\"; }" << std::endl;
}
for(auto &bus: schema->busInstances) {
generateBus(bus.get(), buffer);
}
buffer << "\t}\n";
}
void generateBus(BusInstance *bus, ostream &buffer) {
buffer << "\n";
buffer << "\t\t// " << bus->name << " bus\n\n";
if(bus->bus.getDisplay().has_value()) {
bus->bus.getDisplay()->comdel(buffer, bus->position.first, bus->position.second, bus->size);
}
}
void generateWire(std::string &name, Wire& wire, ostream &buffer);
std::map<string, string> generateWires(Schema *schema, ostream &buffer) {
std::set<string> usedNames;
std::map<string, string> usedMappings;
for(auto &bus: schema->busInstances) {
buffer << "\t//" << bus->name << std::endl;
for(auto& wire: bus->bus.getWires()) {
std::string name = wire.getName();
if(usedNames.count(wire.getName()) > 0) {
name = bus->name + "__" + wire.getName();
}
if(wire.isHidden()) {
name = "--" + name;
}
usedNames.insert(name);
usedMappings.insert(std::make_pair(bus->name + "." + wire.getName(), name));
generateWire(name, wire, buffer);
}
buffer << std::endl << std::endl;
}
return usedMappings;
}
void generateWire(std::string &name, Wire& wire, ostream &buffer) {
buffer << "\t";
switch (wire.getType()) {
case Wire::R_WIRE:
buffer << "r_wire";
break;
case Wire::WIRED_AND:
buffer << "wired_and";
break;
case Wire::WIRED_OR:
buffer << "wired_or";
break;
default:
buffer << "wire";
}
if(wire.getWidth() != 1) {
buffer << "<" << wire.getWidth() << ">";
}
buffer << " " << name << ";" << std::endl;
}
std::set<std::string> createImports(Schema *schema) {
std::set<std::string> importSet;
for(auto &component: schema->componentInstances) {
importSet.insert(component->component.getSource());
}
return importSet;
}
void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, stringstream &buffer);
void generateSingleAutomaticPin(DirectConnectionInstance *instance, string name, string pin,
map <string, string> &wireNames,
stringstream &buffer);
void generateComponent(Schema *schema, map <string, string> &wires, ostream &buffer,
shared_ptr <ComponentInstance> &component);
void generateSubComponents(Schema *schema, map<string, string> &wires, ostream &buffer) {
buffer << "\t// components --------------------------------------------" << std::endl;
for(auto& component: schema->componentInstances) {
if(component->component.getType() == Component::MEMORY) {
generateComponent(schema, wires, buffer, component);
}
}
for(auto& component: schema->componentInstances) {
if(component->component.getType() != Component::MEMORY) {
generateComponent(schema, wires, buffer, component);
}
}
}
void generateComponent(Schema *schema, map <string, string> &wires, ostream &buffer,
shared_ptr <ComponentInstance> &component) {
buffer << "\tsubcomponent " << component->component.getName() << " " << component->name;
std::optional<InstanceAttribute> memory;
std::vector<InstanceAttribute> attributes;
for(auto& attr: component->attributes) {
if(attr.name != "_memory") {
attributes.push_back(attr);
} else if(attr.name == "_memory" && attr.value.asMemoryReference().has_value()) {
memory = attr;
}
}
if(!attributes.empty()) {
buffer << "<";
buffer << attributes[0].value.stringify();
for(int i=1; i<attributes.size(); i++) {
buffer << ", " << attributes[i].value.stringify();
}
buffer << ">";
}
stringstream tempOutput;
for(auto &pin: component->component.getPins()) {
if(schema->hasConnection(component->name, pin.getName())) {
auto conn = schema->getConnection(component->name, pin.getName());
auto busConn = dynamic_cast<BusConnectionInstance*>(conn);
if(busConn != nullptr) {
for(auto wire: busConn->connection.getWires()) {
if(wire.isType(Value::ATTRIBUTE_REFERENCE)) {
auto attribute = busConn->getAttribute(wire.asReference());
if(wire.isType(Value::WIRE_REFERENCE)) {
tempOutput << wires[busConn->bus->name + "." + attribute.value.asReference()] << ", ";
} else if(wire.isType(Value::NIL)) {
tempOutput << "*, ";
} else {
tempOutput << attribute.value.stringify() << ", ";
}
} else {
if(wire.isType(Value::WIRE_REFERENCE)) {
tempOutput << wires[busConn->bus->name + "." + wire.asReference()] << ", ";
} else if(wire.isType(Value::NIL)) {
tempOutput << "*, ";
} else {
tempOutput << wire.stringify() << ", ";
}
}
}
}
auto dirConn = dynamic_cast<DirectConnectionInstance*>(conn);
if(dirConn != nullptr) {
if(dirConn->bus->bus.getType() == Bus::AUTOMATIC) {
generateAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput);
} else {
generateSingleAutomaticPin(dirConn, component->name, pin.getName(), wires, tempOutput);
}
}
} else {
// if no connection exists than defaults must exist
for(auto& wire: *pin.getWires()) {
tempOutput << wire.stringify() << ", ";
}
}
}
auto wireList = tempOutput.str();
wireList.pop_back();
wireList.pop_back(); // remove last COMMA(", ")
buffer << "(" << wireList << ")";
if(memory.has_value()) {
buffer << " uses " << *memory->value.asMemoryReference();
}
buffer << ";" << std::endl;
}
void generateSingleAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map <string, string> &wireNames, stringstream &buffer) {
std::vector<Value> wires;
std::string selected;
std::vector<Value> defaults;
if(connection->instance->name == name && connection->connection.getComponent().pin == pin) {
wires = connection->connection.getWires();
selected = connection->attributes[0].value.asReference();
defaults = *connection->instance->component.getPin(pin).getWires();
} else {
wires = *connection->connection.getSecondWires();
selected = connection->attributes[1].value.asReference();
defaults = *connection->secondInstance->component.getPin(pin).getWires();
}
for(int i=0; i<wires.size(); i++) {
if(wires[i].isType(Value::STRING)) {
if(wires[i].asString() == selected) {
buffer << wireNames[connection->bus->name + "." + connection->bus->bus.getWires()[0].getName()] << ", ";
} else {
buffer << defaults[i].stringify();
}
} else {
buffer << wires[i].stringify() << ", ";
}
}
}
void generateAutomaticPin(DirectConnectionInstance *connection, string name, string pin, map<string, string> wireNames, stringstream &buffer) {
std::vector<Value> wires;
if(connection->instance->name == name && connection->connection.getComponent().pin == pin) {
wires = connection->connection.getWires();
} else {
wires = *connection->connection.getSecondWires();
}
for(auto& wire: wires) {
if(wire.isType(Value::ATTRIBUTE_REFERENCE)) {
auto attribute = connection->getAttribute(wire.asReference());
if(wire.isType(Value::WIRE_REFERENCE)) {
buffer << wireNames[connection->bus->name + "." + attribute.value.asReference()] << ", ";
} else if(wire.isType(Value::NIL)) {
buffer << "*, ";
} else {
buffer << attribute.value.stringify() << ", ";
}
} else {
if(wire.isType(Value::WIRE_REFERENCE)) {
buffer << wireNames[connection->bus->name + "." + wire.asReference()] << ", ";
} else if(wire.isType(Value::NIL)) {
buffer << "*, ";
} else {
buffer << wire.stringify() << ", ";
}
}
}
}
} // domain

View File

@ -0,0 +1,16 @@
#ifndef COMDEL_GENERATOR_H
#define COMDEL_GENERATOR_H
#include <sstream>
#include "schema.h"
#include "library.h"
namespace domain {
void generateSchemaFile(std::string& librarySource, Schema *schema, std::ostream &buffer);
void generateComdelFile(Schema *schema, Library &library, std::ostream &buffer);
} // domain
#endif //COMDEL_GENERATOR_H

View File

@ -8,24 +8,21 @@ std::vector<ValidationError> ComdelValidator::validateSchema(Schema &schema, Val
context.instance = nullptr;
context.attribute = nullptr;
for(auto &inst: schema.instances) {
auto *instance = dynamic_cast<ComponentInstance*>(inst);
if(instance) {
auto result = validateComponent(instance, context);
errors.insert(errors.end(), result.begin(), result.end());
}
for(auto &instance: schema.componentInstances) {
auto result = validateComponent(instance.get(), context);
errors.insert(errors.end(), result.begin(), result.end());
}
return errors;
}
std::vector<ValidationError> ComdelValidator::validateComponent(ComponentInstance *instance, ValidationContext context) {
std::vector<ValidationError> ComdelValidator::validateComponent(ComponentInstance* instance, ValidationContext context) {
std::vector<ValidationError> errors;
context.instance = instance;
context.attributes.clear();
for(auto &attribute: instance->attributes) {
context.attributes[attribute->name] = attribute->value;
context.attributes[attribute.name] = attribute.value;
}
for(auto &rule: instance->component.getRules()) {
@ -36,7 +33,7 @@ std::vector<ValidationError> ComdelValidator::validateComponent(ComponentInstanc
}
for(auto &attribute: instance->attributes) {
auto result = validateAttribute(attribute, context);
auto result = validateAttribute(&attribute, context);
errors.insert(errors.end(), result.begin(), result.end());
}
@ -64,7 +61,7 @@ std::optional<ValidationError> ComdelValidator::validateRule(Rule rule, Validati
RuleContext ruleContext;
ruleContext.addressSpaces = context.addressSpaces;
ruleContext.attributes = context.attributes;
ruleContext.function = callbacks;
ruleContext.function = validators;
auto action = rule.evaluate(ruleContext);
if (action) {
std::string message = this->populateMessage(action->getMessage(), context);

View File

@ -8,14 +8,14 @@ namespace domain {
struct ValidationError
{
Instance *instance;
ComponentInstance *instance;
InstanceAttribute *attribute;
Action::ActionType type;
std::string message;
};
struct ValidationContext {
Instance *instance;
ComponentInstance *instance;
InstanceAttribute *attribute;
std::map<std::string, AddressSpace> addressSpaces;
std::map<std::string, Value> attributes;
@ -29,14 +29,19 @@ public:
std::vector<ValidationError> validateAttribute(InstanceAttribute *attribute, ValidationContext context);
std::optional<ValidationError> validateRule(Rule rule, ValidationContext context);
ComdelValidator(std::map<std::string, FunctionCallback> callbacks): callbacks(callbacks) {}
ComdelValidator(std::vector<FunctionValidator*> validators) {
for(auto* validator: validators) {
validator->clear();
this->validators.insert(std::make_pair(validator->getName(), validator));
}
}
private:
std::map<std::string, FunctionCallback> callbacks;
std::map<std::string, FunctionValidator*> validators;
std::string populateMessage(string basicString, ValidationContext context);
std::string populateMessage(string message, ValidationContext context);
string replacePlaceholder(string basicString, const string basicString1, Value value);
string replacePlaceholder(string message, const string name, Value value);
};
}

View File

@ -67,7 +67,13 @@ Attribute Component::getAttribute(std::string attribute) {
}
bool Component::hasAttribute(std::string name, Value::ValueType type) {
for(uint i=0; i<attributes.size(); i++) {
if(attributes[i].getName() == name && attributes[i].getDefault().getType() == type) {
if(attributes[i].getName() == name && attributes[i].getDefault().getType() == type) {
return true;
}
if(attributes[i].getName() == name && (type == Value::NIL && (attributes[i].getDefault().getType() == Value::MEMORY_REFERENCE || attributes[i].getDefault().getType() == Value::WIRE_REFERENCE))) {
return true;
}
if(attributes[i].getName() == name && (type == Value::UNDEFINED && (attributes[i].getDefault().getType() == Value::MEMORY_REFERENCE || attributes[i].getDefault().getType() == Value::WIRE_REFERENCE))) {
return true;
}
}

View File

@ -3,16 +3,26 @@
namespace domain {
ConnectionInstance::ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute*> attributes, WireInstance *wire, Connection connection)
: instance(instance), attributes(attributes), connection(connection), wire(wire)
ConnectionInstance::ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, Connection connection)
: instance(instance), attributes(attributes), connection(connection)
{}
BusConnectionInstance::BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute*> attributes, BusInstance *bus, WireInstance *wire, Connection connection)
: ConnectionInstance(instance, attributes, wire, connection), bus(bus)
InstanceAttribute ConnectionInstance::getAttribute(string attribute) {
for(auto& attr: attributes) {
if(attr.name == attribute) {
return attr;
}
}
throw std::exception();
}
BusConnectionInstance::BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection)
: ConnectionInstance(instance, attributes, connection), bus(bus)
{}
DirectConnectionInstance::DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondInstance, std::vector<InstanceAttribute*> attributes, BusInstance *bus, WireInstance *wire, Connection connection)
: ConnectionInstance(instance, attributes, wire, connection), secondInstance(secondInstance), bus(bus)
DirectConnectionInstance::DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondInstance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection)
: ConnectionInstance(instance, attributes, connection), secondInstance(secondInstance), bus(bus)
{}
} // namespace domain

View File

@ -14,13 +14,14 @@ class ConnectionInstance
public:
ComponentInstance *instance;
Connection connection;
WireInstance *wire;
virtual ~ConnectionInstance() = default;
std::vector<InstanceAttribute*> attributes;
std::vector<InstanceAttribute> attributes;
ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute*> attributes, WireInstance *wire, Connection connection);
ConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, Connection connection);
InstanceAttribute getAttribute(string attribute);
};
@ -29,7 +30,7 @@ class BusConnectionInstance: public ConnectionInstance
public:
BusInstance *bus;
BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute*> attributes, BusInstance *bus, WireInstance *wire, Connection connection);
BusConnectionInstance(ComponentInstance *instance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection);
};
@ -39,7 +40,7 @@ public:
BusInstance *bus;
ComponentInstance *secondInstance;
DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance, std::vector<InstanceAttribute*> attributes, BusInstance *bus, WireInstance *wire, Connection connection);
DirectConnectionInstance(ComponentInstance *instance, ComponentInstance *secondsInstance, std::vector<InstanceAttribute> attributes, BusInstance *bus, Connection connection);
};

View File

@ -4,6 +4,8 @@
#include <QGraphicsItem>
#include <optional>
#include <ostream>
namespace domain {
namespace ui {
@ -17,6 +19,14 @@ public:
void render(QGraphicsItemGroup *group) {
group->addToGroup(new QGraphicsRectItem(x,y,w,h));
}
void comdel(std::ostream &buffer, int x, int y, int size) {
buffer << "\t\trectangle {\n";
buffer << "\t\t\tx: " << (this->x + x) << "; y: " << (this->y + y) << ";\n";
buffer << "\t\t\tw: " << w << "; h: " << h << ";\n";
buffer << "\t\t}\n\n";
}
};
class Line {
@ -28,6 +38,13 @@ public:
void render(QGraphicsItemGroup *group) {
group->addToGroup(new QGraphicsLineItem(x1, y1, x2, y2));
}
void comdel(std::ostream &buffer, int x, int y, int size) {
buffer << "\t\tline {\n";
buffer << "\t\t\tx1: " << (x1 + x) << "; y1: " << (y1 + y) << ";\n";
buffer << "\t\t\tx2: " << (x2 + x) << "; y2: " << (y2 + y) << ";\n";
buffer << "\t\t}\n\n";
}
};
enum Orientation {
@ -65,6 +82,11 @@ public:
std::optional<Rect> rect = std::nullopt;
std::optional<Line> line = std::nullopt;
std::optional<Pin> pin = std::nullopt;
void comdel(std::ostream &buffer, int x, int y, int size) {
if(rect) rect->comdel(buffer, x, y, size);
if(line) line->comdel(buffer, x, y, size);
}
};
}
@ -81,6 +103,12 @@ public:
}
}
void comdel(std::ostream &buffer, int x, int y, int size) {
for(auto &item: items) {
item.comdel(buffer, x, y, size);
}
}
private:
std::vector<ui::Item> items;
};

View File

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

View File

@ -1,5 +1,5 @@
#ifndef DOMAIN_FUNCTION_SIGNATURE_H
#define DOMAIN_FUNCTION_SIGNATURE_H
#ifndef DOMAIN_FUNCTION_VALIDATOR_H
#define DOMAIN_FUNCTION_VALIDATOR_H
#include<functional>
#include<vector>
@ -8,18 +8,46 @@
namespace domain {
typedef std::function<bool (std::vector<Value>)> FunctionCallback;
struct FunctionSignature {
class FunctionValidator {
private:
std::string name;
std::vector<Value::ValueType> params;
FunctionCallback callback;
std::vector<Value::ValueType> signature;
FunctionSignature(std::string name, std::vector<Value::ValueType> params, FunctionCallback callback): name(name), params(params), callback(callback) {}
protected:
FunctionValidator(std::string name, std::vector<Value::ValueType> signature) {
this->name = name;
this->signature = signature;
}
public:
std::string getName() {
return name;
}
std::vector<Value::ValueType> getSignature() {
return signature;
}
bool validateSignature(std::vector<Value> signature) {
if(this->signature.size() != signature.size()) {
return false;
}
for(int i=0; i<this->signature.size(); i++) {
if(this->signature[i] != signature[i].getType()) {
return false;
}
}
return true;
}
virtual bool validate(std::vector<Value> values) = 0;
virtual void clear() = 0;
};
std::vector<FunctionSignature> getSupportedFunctions();
std::vector<FunctionValidator*> getSupportedValidators();
} // namespace domain
#endif // DOMAIN_FUNCTIONSIGNATURE_H
#endif // DOMAIN_FUNCTION_VALIDATOR_H

View File

@ -2,15 +2,11 @@
namespace domain {
Instance::Instance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position)
: name(name), attributes(attributes), position(position)
{}
BusInstance::BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size)
: Instance(name, vector<InstanceAttribute*>(), position), bus(bus), size(size)
: name(name), position(position), bus(bus), size(size)
{}
ComponentInstance::ComponentInstance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position, Component component)
: Instance(name, attributes, position), component(component)
ComponentInstance::ComponentInstance(std::string name, std::vector<InstanceAttribute> attributes, std::pair<int, int> position, Component component)
: name(name), attributes(std::move(attributes)), position(position), component(component)
{}

View File

@ -12,41 +12,32 @@
namespace domain {
class Instance
class BusInstance
{
public:
std::string name;
std::vector<InstanceAttribute*> attributes;
std::pair<int, int> position;
virtual ~Instance() {};
Instance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position);
};
class BusInstance: public Instance
{
public:
Bus bus;
int size;
BusInstance(std::string name, std::pair<int, int> position, Bus bus, int size);
virtual ~BusInstance() {
Instance::~Instance();
}
virtual ~BusInstance() = default;
};
class ComponentInstance: public Instance
class ComponentInstance
{
public:
std::string name;
std::vector<InstanceAttribute> attributes;
std::pair<int, int> position;
Component component;
ComponentInstance(std::string name, std::vector<InstanceAttribute*> attributes, std::pair<int, int> position, Component component);
ComponentInstance(std::string name, std::vector<InstanceAttribute> attributes, std::pair<int, int> position, Component component);
virtual ~ComponentInstance() {
Instance::~Instance();
}
virtual ~ComponentInstance() = default;
};
} // namespace domain

View File

@ -15,10 +15,11 @@ class InstanceAttribute
public:
InstanceAttribute(std::string name, Value value, Attribute attribute);
std::string name;
std::string name = "";
Value value;
Attribute attribute;
~InstanceAttribute() = default;
};
} // namespace domain

View File

@ -2,9 +2,9 @@
namespace domain {
Library::Library(string name, string libraryInfo, string header, string componentDirectory,
Library::Library(string name, string libraryInfo, string header, string componentDirectory, std::optional<std::string> componentHeader,
vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses, vector<Connection> connections, map<string, string> messages)
: name(name), libraryInfo(libraryInfo), header(header), componentDirectory(componentDirectory), addressSpaces(addressSpaces),
: name(name), libraryInfo(libraryInfo), header(header), componentDirectory(componentDirectory), componentHeader(componentHeader), addressSpaces(addressSpaces),
components(components), buses(buses), connections(connections), messages(messages)
{}
@ -20,6 +20,9 @@ std::string Library::getHeader() {
std::string Library::getComponentDirectory() {
return componentDirectory;
}
std::optional<std::string> Library::getComponentHeader() {
return componentHeader;
}
std::vector<AddressSpace> Library::getAddressSpaces() {
return addressSpaces;

View File

@ -21,6 +21,7 @@ class Library
std::string libraryInfo;
std::string header;
std::string componentDirectory;
std::optional<std::string> componentHeader;
std::vector<AddressSpace> addressSpaces;
std::vector<Component> components;
@ -30,13 +31,14 @@ class Library
std::map<std::string, std::string> messages;
public:
Library(string name, string libraryInfo, string header, string componentDirectory,
Library(string name, string libraryInfo, string header, string componentDirectory, std::optional<string> componentHeader,
vector<AddressSpace> addressSpaces, vector<Component> components, vector<Bus> buses, vector<Connection> connection, map<string, string> messages);
std::string getName();
std::string getLibraryInfo();
std::string getHeader();
std::string getComponentDirectory();
std::optional<std::string> getComponentHeader();
std::vector<AddressSpace> getAddressSpaces();
std::vector<Component> getComponents();

View File

@ -18,7 +18,7 @@ Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection conn
: name(name), type(type), tooltip(tooltip), connection(connection), display(display), wires(wires)
{}
std::string Pin::getName() {
std::string &Pin::getName() {
return name;
}
Pin::PinType Pin::getType() {

View File

@ -14,8 +14,8 @@ class PinConnection
{
public:
enum ConnectionType {
CHECK_ONLY,
AUTOMATICALLY
REQUIRED,
OPTIONAL
};
private:
@ -50,7 +50,7 @@ private:
public:
Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, Display display, std::optional<std::vector<Value>> wires);
std::string getName();
std::string &getName();
PinType getType();
std::string getTooltip();
Display &getDisplay();

View File

@ -17,7 +17,7 @@ bool Condition::evaluate(RuleContext &context) {
request.push_back(params[i]);
}
}
bool result = context.function[function](request);
bool result = context.function[function]->validate(request);
return negated ? !result : result;
}

View File

@ -15,7 +15,7 @@ namespace domain {
struct RuleContext {
std::map<std::string, AddressSpace> addressSpaces;
std::map<std::string, Value> attributes;
std::map<std::string, FunctionCallback> function;
std::map<std::string, FunctionValidator*> function;
};
class Condition {

View File

@ -6,4 +6,23 @@ Schema::Schema()
{
}
bool Schema::hasConnection(string& component, string& pin) {
return getConnection(component, pin) != nullptr;
}
ConnectionInstance* Schema::getConnection(string& component, string& pin) {
for(auto& conn: connections) {
if(conn->instance->name == component && conn->connection.getComponent().pin == pin) {
return conn.get();
}
auto dirConn = dynamic_cast<DirectConnectionInstance*>(conn.get());
if(dirConn != nullptr) {
if(dirConn->secondInstance->name == component && conn->connection.getSecondComponent()->pin == pin) {
return dirConn;
}
}
}
return nullptr;
}
} // namespace domain

View File

@ -14,32 +14,30 @@ class Schema
public:
Schema();
std::vector<Instance*> instances;
std::vector<ConnectionInstance*> connections;
std::vector<WireInstance*> wires;
std::vector<shared_ptr<BusInstance>> busInstances;
std::vector<shared_ptr<ComponentInstance>> componentInstances;
WireInstance *getWire(std::string name) {
for(auto wire: wires) {
if (wire->name == name) {
return wire;
}
}
return nullptr;
}
std::vector<shared_ptr<ConnectionInstance>> connections;
bool hasWire(std::string name) {
return getWire(name) != NULL;
}
Instance *getInstance(std::string name) {
for(auto instance: instances) {
BusInstance *getBusInstance(std::string& name) {
for(auto& instance: busInstances) {
if (instance->name == name) {
return instance;
return instance.get();
}
}
return nullptr;
}
ComponentInstance *getComponentInstance(std::string& name) {
for(auto& instance: componentInstances) {
if (instance->name == name) {
return instance.get();
}
}
return nullptr;
}
bool hasConnection(string& component, string& pin);
ConnectionInstance* getConnection(string& component, string& pin);
};
} // namespace domain

View File

@ -1,6 +1,7 @@
#include "schemacreator.h"
#include<set>
#include <utility>
namespace domain {
@ -39,19 +40,31 @@ Value::ValueType toType(ValueNode::ValueType type) {
switch (type) {
case ValueNode::BOOL:
return Value::BOOL;
case ValueNode::MEMORY:
return Value::MEMORY_REFERENCE;
case ValueNode::WIRE:
return Value::WIRE_REFERENCE;
case ValueNode::STRING:
return Value::STRING;
case ValueNode::INT:
return Value::INT;
case ValueNode::NIL:
return Value::NIL;
default:
return Value::UNDEFINED;
}
}
Value toType(ValueNode node) {
Value toType(ValueNode node, Value::ValueType type = Value::ValueType::UNDEFINED) {
if(type == Value::MEMORY_REFERENCE) {
if(node.getType() == ValueNode::NIL) {
return Value::fromMemoryReference(nullopt);
} else {
return Value::fromMemoryReference(node.asIdentifier());
}
}
if(node.getType() == ValueNode::BOOL) {
return Value::fromBool(node.asBool());
} else if(node.getType() == ValueNode::INT) {
@ -68,6 +81,8 @@ Value toType(ValueNode node) {
Bus::BusType toType(BusNode::BusType type) {
if(type == BusNode::AUTOMATIC) {
return Bus::AUTOMATIC;
} else if(type == BusNode::SINGLE_AUTOMATIC) {
return Bus::SINGLE_AUTOMATIC;
}
return Bus::REGULAR;
}
@ -84,10 +99,10 @@ Pin::PinType toType(PinNode::PinType type) {
PinConnection::ConnectionType toType(PinConnectionNode::ConnectionType type)
{
if(type == PinConnectionNode::AUTOMATICALLY) {
return PinConnection::AUTOMATICALLY;
if(type == PinConnectionNode::OPTIONAL) {
return PinConnection::OPTIONAL;
}
return PinConnection::CHECK_ONLY;
return PinConnection::REQUIRED;
}
@ -99,22 +114,26 @@ Popup::PopupType toType(PopupNode::PopupType type)
return Popup::ON_DEMAND;
}
SchemaCreator::SchemaCreator(std::vector<FunctionSignature> signatures)
: signatures(signatures)
SchemaCreator::SchemaCreator(std::vector<FunctionValidator*> validators)
: validators(std::move(validators))
{}
std::optional<Library> SchemaCreator::loadLibrary(LibraryNode node)
{
// library fields
if(!node.name) {
errors.push_back(SourceError{node.span, "missing @name"});
errors.emplace_back(node.span, "missing @name");
return nullopt;
} else {
name = node.name->asString();
}
if(node.componentHeader.has_value()) {
componentHeader = node.componentHeader->asString();
}
if(!node.componentDirectory) {
errors.push_back(SourceError{node.span, "missing @componentDirectory"});
errors.emplace_back(node.span, "missing @componentDirectory");
return nullopt;
} else {
componentDirectory = node.componentDirectory->asString();
@ -136,29 +155,29 @@ std::optional<Library> SchemaCreator::loadLibrary(LibraryNode node)
}
}
for(uint i=0; i<node.buses.size(); i++) {
auto bus = loadBus(node.buses[i]);
for(auto& buse : node.buses) {
auto bus = loadBus(buse);
if(bus) {
buses.push_back(*bus);
}
}
for(uint i=0; i<node.connections.size(); i++) {
auto conn = loadConnection(node.connections[i]);
for(auto& connection : node.connections) {
auto conn = loadConnection(connection);
if(conn) {
connections.push_back(*conn);
}
}
for(uint i=0; i<node.messages.size(); i++) {
if(!node.messages[i].value.is(ValueNode::STRING)) {
errors.push_back(SourceError{node.messages[i].value.span, "expected `string`"});
for(auto & message : node.messages) {
if(!message.value.is(ValueNode::STRING)) {
errors.emplace_back(message.value.span, "expected `string`");
} else {
messages[node.messages[i].key.value] = node.messages[i].value.asString();
messages[message.key.value] = message.value.asString();
}
}
return Library(name, libraryInfo, header, componentDirectory, addressSpaces, components, buses, connections, messages);
return Library(name, libraryInfo, header, componentDirectory, componentHeader, addressSpaces, components, buses, connections, messages);
}
std::optional<Bus> SchemaCreator::loadBus(BusNode node)
@ -170,24 +189,24 @@ std::optional<Bus> SchemaCreator::loadBus(BusNode node)
count = std::make_pair<int, int>(node.count->first.value, node.count->second.value);
}
if(count.first > count.second || count.first < 0) {
errors.push_back(SourceError{node.count->span, "invalid @size"});
errors.emplace_back(node.count->span, "invalid @size");
return nullopt;
}
auto type = toType(node.type.value);
if(!node.tooltip && type == Bus::REGULAR) {
errors.push_back(SourceError{node.span, "missing @tooltip"});
errors.emplace_back(node.span, "missing @tooltip");
return nullopt;
}
std::string tooltip = node.tooltip->asString();
if(!node.display && type == Bus::REGULAR) {
errors.push_back(SourceError{node.span, "missing @display"});
errors.emplace_back(node.span, "missing @display");
return nullopt;
}
if(node.display && (type == Bus::AUTOMATIC || type == Bus::AUTOMATIC_SINGLE)) {
errors.push_back(SourceError{node.span, "automatic bus cannot have a @display"});
if(node.display && (type == Bus::AUTOMATIC || type == Bus::SINGLE_AUTOMATIC)) {
errors.emplace_back(node.span, "automatic bus cannot have a @display");
return nullopt;
}
@ -200,7 +219,7 @@ std::optional<Bus> SchemaCreator::loadBus(BusNode node)
}
if(node.wires.size() == 0) {
errors.push_back(SourceError{node.span, "missing @wires"});
errors.emplace_back(node.span, "missing @wires");
return nullopt;
}
std::vector<Wire> wires;
@ -211,6 +230,11 @@ std::optional<Bus> SchemaCreator::loadBus(BusNode node)
}
}
if(type == Bus::SINGLE_AUTOMATIC && wires.size() != 1) {
errors.emplace_back(node.span, "singleAutomatic bus must have exactly 1 wire defined");
return nullopt;
}
return Bus(name, tooltip, type, count, wires, display);
}
@ -222,7 +246,7 @@ std::optional<AddressSpace> SchemaCreator::loadAddressSpace(AddressSpaceNode nod
std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
{
push(ComdelContext("connection", false, true, false));
push(ComdelContext("connection", false, true, false, false));
std::string bus = node.bus.value;
auto busInstance = getBus(bus);
@ -230,6 +254,10 @@ std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
errors.emplace_back(node.span, "bus does not exist");
}
if(busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
current().inSingleAutomaticConnection = true;
}
if(busInstance->getType() == Bus::REGULAR) {
ConnectionComponent first{node.first.component.value, node.first.pin.value};
@ -284,7 +312,7 @@ std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
pop();
return Connection(first, nullopt, bus, attributes, wires, nullopt);
} else if(busInstance->getType() == Bus::AUTOMATIC || busInstance->getType() == Bus::AUTOMATIC_SINGLE) {
} else if(busInstance->getType() == Bus::AUTOMATIC || busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
ConnectionComponent first{node.first.component.value, node.first.pin.value};
if(!node.second.has_value()) {
@ -309,6 +337,10 @@ std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
current().wires.push_back(wire.getName());
}
if(node.attributes.size() != 2 && busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
errors.emplace_back(node.span, "singleAutomatic must contain 2 attributes");
}
std::vector<Attribute> attributes;
for(auto & attribute : node.attributes) {
auto attr = loadAttribute(attribute);
@ -329,7 +361,9 @@ std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
firstWires.push_back(Value::fromNull());
} else if(firstWire.is(ValueNode::INT)) {
firstWires.push_back(Value::fromInt(firstWire.asInt()));
} else if(firstWire.is(ValueNode::IDENTIFIER)) {
} else if(firstWire.is(ValueNode::STRING) && busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
firstWires.push_back(Value::fromString(firstWire.asString()));
} else if(firstWire.is(ValueNode::IDENTIFIER) && busInstance->getType() == Bus::AUTOMATIC) {
if(attributeNames.count(firstWire.asIdentifier())) {
firstWires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE));
} else if(wireNames.count(firstWire.asIdentifier())) {
@ -338,7 +372,7 @@ std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
errors.emplace_back(firstWire.span, "unknown identifier");
}
} else {
errors.emplace_back(firstWire.span, "unknown value type");
errors.emplace_back(firstWire.span, "unsupported value type");
}
}
@ -349,7 +383,9 @@ std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
secondWires.push_back(Value::fromNull());
} else if(secondWire.is(ValueNode::INT)) {
secondWires.push_back(Value::fromInt(secondWire.asInt()));
} else if(secondWire.is(ValueNode::IDENTIFIER)) {
} else if(secondWire.is(ValueNode::STRING) && busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
secondWires.push_back(Value::fromString(secondWire.asString()));
} else if(secondWire.is(ValueNode::IDENTIFIER) && busInstance->getType() == Bus::AUTOMATIC) {
if(attributeNames.count(secondWire.asIdentifier())) {
secondWires.push_back(Value::fromReference(secondWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE));
} else if(wireNames.count(secondWire.asIdentifier())) {
@ -358,7 +394,25 @@ std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
errors.emplace_back(secondWire.span, "unknown identifier");
}
} else {
errors.emplace_back(secondWire.span, "unknown value type");
errors.emplace_back(secondWire.span, "unsupported value type");
}
}
if(busInstance->getType() == Bus::SINGLE_AUTOMATIC && attributes.size() == 2) {
if(!attributes[0].getPopup().has_value()) {
errors.emplace_back(node.attributes[0].span, "@popup is required");
} else if(attributes[0].getDefault().getType() != Value::STRING) {
errors.emplace_back(node.attributes[0].span, "@attribute must be of type string");
} else {
attributes[0].getPopup()->setEnumeration(createWireEnumeration(firstWires));
}
if(!attributes[1].getPopup().has_value()) {
errors.emplace_back(node.attributes[1].span, "@popup is required");
} else if(attributes[1].getDefault().getType() != Value::STRING) {
errors.emplace_back(node.attributes[1].span, "@attribute must be of type string");
} else {
attributes[1].getPopup()->setEnumeration(createWireEnumeration(secondWires));
}
}
@ -374,19 +428,19 @@ std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
std::optional<Component> SchemaCreator::loadComponent(ComponentNode node)
{
push(ComdelContext(node.name.value, true, false, false));
push(ComdelContext(node.name.value, true, false, false, false));
std::string name = node.name.value;
if(!node.tooltip) {
errors.push_back(SourceError{node.span, "missing @tooltip"});
errors.emplace_back(node.span, "missing @tooltip");
pop();
return nullopt;
}
std::string tooltip = node.tooltip->asString();
if(!node.source) {
errors.push_back(SourceError{node.span, "missing @source"});
errors.emplace_back(node.span, "missing @source");
pop();
return nullopt;
}
@ -401,6 +455,9 @@ std::optional<Component> SchemaCreator::loadComponent(ComponentNode node)
attributes.push_back(*attribute);
}
}
if(type == Component::PROCESSOR) {
attributes.push_back(*createMemoryAttribute());
}
context[context.size() -1 ].attributes = attributes;
@ -413,7 +470,7 @@ std::optional<Component> SchemaCreator::loadComponent(ComponentNode node)
}
if(!node.instanceName) {
errors.push_back(SourceError{node.span, "missing @instanceName"});
errors.emplace_back(node.span, "missing @instanceName");
pop();
return nullopt;
}
@ -424,13 +481,13 @@ std::optional<Component> SchemaCreator::loadComponent(ComponentNode node)
count = std::make_pair<int, int>(node.count->first.value, node.count->second.value);
}
if(count.first > count.second || count.first < 0) {
errors.push_back(SourceError{node.count->first.span, "invalid @size"});
errors.emplace_back(node.count->first.span, "invalid @size");
pop();
return nullopt;
}
if(!node.display) {
errors.push_back(SourceError{node.span, "missing @display"});
errors.emplace_back(node.span, "missing @display");
pop();
return nullopt;
}
@ -441,8 +498,8 @@ std::optional<Component> SchemaCreator::loadComponent(ComponentNode node)
}
std::vector<Pin> pins;
for(uint i=0; i<node.pins.size(); i++) {
auto pin = loadPin(node.pins[i]);
for(auto &p : node.pins) {
auto pin = loadPin(p);
if(!pin) {
pop();
return nullopt;
@ -471,13 +528,13 @@ optional<Pin> SchemaCreator::loadPin(PinNode node)
Pin::PinType type = toType(node.type.value);
if(!node.tooltip) {
errors.push_back(SourceError{node.span, "missing @tooltip"});
errors.emplace_back(node.span, "missing @tooltip");
return nullopt;
}
std::string tooltip = node.tooltip->asString();
if(!node.display) {
errors.push_back(SourceError{node.span, "missing @display"});
errors.emplace_back(node.span, "missing @display");
return nullopt;
}
std::vector<Attribute> attributes;
@ -487,7 +544,7 @@ optional<Pin> SchemaCreator::loadPin(PinNode node)
}
if(!node.connection) {
errors.push_back(SourceError{node.span, "missing @connection"});
errors.emplace_back(node.span, "missing @connection");
return nullopt;
}
auto connection = loadPinConnection(*node.connection);
@ -548,7 +605,7 @@ std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node)
h = getIntProperty(item, "h");
displayItem.pin = ui::Pin(x, y, w, h);
} else {
errors.push_back(SourceError{item.type.span, "unsupported display type"});
errors.emplace_back(item.type.span, "unsupported display type");
}
items.push_back(displayItem);
}
@ -560,7 +617,7 @@ PinConnection SchemaCreator::loadPinConnection(PinConnectionNode node)
{
std::string message = node.message.asString();
PinConnection::ConnectionType type = toType(node.type.value);
return PinConnection(message, type);
return {message, type};
}
std::optional<Attribute> SchemaCreator::loadAttribute(AttributeNode node)
@ -577,23 +634,30 @@ std::optional<Attribute> SchemaCreator::loadAttribute(AttributeNode node)
} else if (node.type == ValueNode::STRING) {
value = Value::fromString(node.defaultValue->asString());
} else {
errors.push_back(SourceError{node.name.span, "unsupported type"});
errors.emplace_back(node.name.span, "unsupported type");
}
}
if(current().inConnection) { // TODO remove identifier
if(current().inConnection && !current().inSingleAutomaticConnection) { // TODO remove identifier
if (node.type == ValueNode::WIRE || node.type == ValueNode::IDENTIFIER) {
if(current().doesWireExists(node.defaultValue->asIdentifier())) {
value = Value::fromReference(node.defaultValue->asIdentifier(), Value::WIRE_REFERENCE);
} else {
value = Value::fromReference("", Value::WIRE_REFERENCE);
errors.push_back(SourceError{node.span, "unknown identifier"});
errors.emplace_back(node.span, "unknown identifier");
}
} else {
errors.push_back(SourceError{node.name.span, "unsupported type"});
errors.emplace_back(node.name.span, "unsupported type");
}
}
if(current().inSingleAutomaticConnection) {
if (node.type == ValueNode::STRING) {
value = Value::fromString(node.defaultValue->asString());
} else {
errors.emplace_back(node.name.span, "unsupported type");
}
}
current().attributes.push_back(Attribute(name, value));
current().attributes.emplace_back(name, value);
std::optional<Popup> popup;
if(node.popup) {
@ -611,16 +675,16 @@ std::optional<Popup> SchemaCreator::loadPopup(PopupNode node, std::string name,
pushAdditional(name);
current().attributes.clear();
current().attributes.push_back(Attribute(name, Value::ofType(type)));
current().attributes.emplace_back(name, Value::ofType(type));
if(!node.title) {
errors.push_back(SourceError{node.span, "missing @title"});
errors.emplace_back(node.span, "missing @title");
return nullopt;
}
std::string title = node.title->asString();
if(!node.text) {
errors.push_back(SourceError{node.span, "missing @text"});
errors.emplace_back(node.span, "missing @text");
return nullopt;
}
std::string text = node.text->asString();
@ -635,34 +699,34 @@ std::optional<Popup> SchemaCreator::loadPopup(PopupNode node, std::string name,
std::vector<Enumeration> enumeration;
if(node.enumerated) {
for(uint i=0; i<node.enumeration.size(); i++) {
for(auto& enumNode : node.enumeration) {
if(type == Value::INT || type == Value::STRING || type == Value::BOOL) {
auto value = toType(node.enumeration[i].value);
auto value = toType(enumNode.value);
if(value.getType() == type) {
enumeration.push_back(Enumeration(node.enumeration[i].key.asString(), value));
enumeration.emplace_back(enumNode.key.asString(), value);
} else {
errors.push_back(SourceError{node.enumeration[i].span, "wrong type"});
errors.emplace_back(enumNode.span, "wrong type");
}
} else if(type == Value::WIRE_REFERENCE) {
auto value = toType(node.enumeration[i].value);
auto value = toType(enumNode.value);
if(value.isType(Value::UNDEFINED)) {
if(current().doesWireExists(value.asReference())) {
value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE);
} else {
errors.push_back(SourceError{node.enumeration[i].span, "unknown wire"});
errors.emplace_back(enumNode.span, "unknown wire");
}
}
if(value.isType(Value::WIRE_REFERENCE) || value.isType(Value::INT) || value.isType(Value::NIL)) {
enumeration.push_back(Enumeration(node.enumeration[i].key.asString(), value));
enumeration.emplace_back(enumNode.key.asString(), value);
} else {
errors.push_back(SourceError{node.enumeration[i].span, "wrong type"});
errors.emplace_back(enumNode.span, "wrong type");
}
}
}
} else {
if(type == Value::WIRE_REFERENCE && !current().inConnection) {
errors.push_back(SourceError{node.span, "@enumeration is required for attributes of type wire"});
errors.emplace_back(node.span, "@enumeration is required for attributes of type wire");
}
}
@ -678,7 +742,7 @@ std::optional<Rule> SchemaCreator::loadRule(RuleNode node)
for(auto& stmt: node.statements) {
auto condition = loadCondition(stmt.condition);
if(condition) {
statements.push_back(IfStatement(*condition, Action(toType(stmt.action.type.value), stmt.action.message.asString())));
statements.emplace_back(*condition, Action(toType(stmt.action.type.value), stmt.action.message.asString()));
} else {
return nullopt;
}
@ -691,19 +755,19 @@ std::optional<Condition> SchemaCreator::loadCondition(ConditionNode node)
{
std::string function = node.functionName.value;
for(uint i=0; i<signatures.size(); i++) {
if(signatures[i].name == function) {
if(signatures[i].params.size() == node.params.size()) {
for(auto & validator : validators) {
if(validator->getName() == function) {
if(validator->getSignature().size() == node.params.size()) {
std::vector<Value> params;
for(uint j=0; j<signatures[i].params.size(); j++) {
for(uint j=0; j<validator->getSignature().size(); j++) {
bool exists = false;
auto type = toType(node.params[j]);
if (type.getType() == Value::UNDEFINED) {
if(current().doesAttributeExists(type.asReference(), signatures[i].params[j])) {
if(current().doesAttributeExists(type.asReference(), validator->getSignature()[j])) {
exists = true;
type = Value::fromReference(type.asReference(), Value::ATTRIBUTE_REFERENCE);
}
if(signatures[i].params[j] == Value::ADDRESS_SPACE) {
if(validator->getSignature()[j] == Value::ADDRESS_SPACE) {
if(hasAddressSpace(type.asReference())) {
exists = true;
type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE_REFERENCE);
@ -711,76 +775,69 @@ std::optional<Condition> SchemaCreator::loadCondition(ConditionNode node)
}
if(!exists) {
errors.push_back(SourceError{node.functionName.span, "unknown reference " + type.asReference()});
errors.emplace_back(node.functionName.span, "unknown reference " + type.asReference());
}
}
params.push_back(type);
}
return Condition(function, params, node.negated);
} else {
errors.push_back(SourceError{node.functionName.span, "wrong number of parameters"});
errors.emplace_back(node.functionName.span, "wrong number of parameters");
}
}
}
errors.push_back(SourceError{node.functionName.span, "unknown function name"});
errors.emplace_back(node.functionName.span, "unknown function name");
return nullopt;
}
Schema* SchemaCreator::loadSchema(SchemaNode node, Library &library)
{
Schema *schema = new Schema();
auto *schema = new Schema();
for(auto &instance: node.instances) {
if(library.hasComponent(instance.component.value)) {
schema->instances.push_back(loadComponentInstance(instance, library));
schema->componentInstances.push_back(loadComponentInstance(instance, library));
}
if(library.hasBus(instance.component.value)) {
schema->instances.push_back(loadBusInstance(instance, library));
}
}
for(auto &wire: node.wires) {
auto w = loadWireInstance(wire);
if(w) {
schema->wires.push_back(*w);
schema->busInstances.push_back(loadBusInstance(instance, library));
}
}
for(auto &conn: node.connections) {
auto firstComponent = dynamic_cast<ComponentInstance*>(schema->getInstance(conn.first.instance.value));
if(firstComponent == NULL) {
errors.push_back(SourceError{conn.first.instance.span, "unknown component"});
auto firstComponent = schema->getComponentInstance(conn.first.instance.value);
if(firstComponent == nullptr) {
errors.emplace_back(conn.first.instance.span, "unknown component");
continue;
}
if(!firstComponent->component.hasPin(conn.first.pin.value)) {
errors.push_back(SourceError{conn.first.pin.span, "unknown pin"});
errors.emplace_back(conn.first.pin.span, "unknown pin");
continue;
}
ComponentInstance *secondComponent = NULL;
ComponentInstance *secondComponent = nullptr;
if(conn.second.has_value()) {
secondComponent = dynamic_cast<ComponentInstance*>(schema->getInstance(conn.second->instance.value));
if(secondComponent == NULL) {
errors.push_back(SourceError{conn.second->instance.span, "unknown component"});
secondComponent = schema->getComponentInstance(conn.second->instance.value);
if(secondComponent == nullptr) {
errors.emplace_back(conn.second->instance.span, "unknown component");
continue;
}
if(!secondComponent->component.hasPin(conn.second->pin.value)) {
errors.push_back(SourceError{conn.second->pin.span, "unknown pin"});
errors.emplace_back(conn.second->pin.span, "unknown pin");
continue;
}
}
auto bus = dynamic_cast<BusInstance*>(schema->getInstance(conn.bus.value));
if(bus == NULL) {
errors.push_back(SourceError{conn.bus.span, "unknown bus"});
auto bus = schema->getBusInstance(conn.bus.value);
if(bus == nullptr) {
errors.emplace_back(conn.bus.span, "unknown bus");
continue;
}
std::optional<Connection> connection = std::nullopt;
if(secondComponent != NULL) {
if(secondComponent != nullptr) {
ConnectionComponent firstConn{firstComponent->component.getName(), conn.first.pin.value};
ConnectionComponent secondConn{secondComponent->component.getName(), conn.second->pin.value};
@ -789,7 +846,7 @@ Schema* SchemaCreator::loadSchema(SchemaNode node, Library &library)
secondConn)) {
connection = *library.getConnection(firstConn, bus->bus.getName(), secondConn);
} else {
errors.push_back(SourceError{conn.span, "unknown connection"});
errors.emplace_back(conn.span, "unknown connection");
continue;
}
} else {
@ -799,23 +856,12 @@ Schema* SchemaCreator::loadSchema(SchemaNode node, Library &library)
bus->bus.getName())) {
connection = *library.getConnection(firstConn, bus->bus.getName());
} else {
errors.push_back(SourceError{conn.span, "unknown connection"});
errors.emplace_back(conn.span, "unknown connection");
continue;
}
}
if(!conn.wire) {
errors.push_back(SourceError{conn.span, "missing @wire"});
continue;
}
if(!schema->hasWire(conn.wire->value)) {
errors.push_back(SourceError{conn.wire->span, "unknown wire"});
continue;
}
auto wire = schema->getWire(conn.wire->value);
std::vector<InstanceAttribute*> attributes;
std::vector<InstanceAttribute> attributes;
for(auto& attr: conn.attributes) {
if(connection->hasAttribute(attr.name.value)) {
auto attribute = connection->getAttribute(attr.name.value);
@ -827,26 +873,26 @@ Schema* SchemaCreator::loadSchema(SchemaNode node, Library &library)
}
}
if(value.isType(Value::UNDEFINED)) {
errors.push_back(SourceError{attr.span, "invalid value"});
errors.emplace_back(attr.span, "invalid value");
}
attributes.push_back(new InstanceAttribute(attribute.getName(), toType(attr.value), attribute));
attributes.emplace_back(attribute.getName(), toType(attr.value), attribute);
} else {
errors.push_back(SourceError(attr.name.span, "unknown attribute"));
errors.emplace_back(attr.name.span, "unknown attribute");
}
}
if(secondComponent == NULL) {
schema->connections.push_back(new BusConnectionInstance(firstComponent, attributes, bus, wire, *connection));
if(secondComponent == nullptr) {
schema->connections.push_back(std::make_shared<BusConnectionInstance>(firstComponent, attributes, bus, *connection));
} else {
schema->connections.push_back(new DirectConnectionInstance(firstComponent, secondComponent, attributes, bus, wire, *connection));
schema->connections.push_back(std::make_shared<DirectConnectionInstance>(firstComponent, secondComponent, attributes, bus, *connection));
}
}
return schema;
}
ComponentInstance *SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) {
shared_ptr<ComponentInstance> SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) {
auto name = instance.name.value;
auto position = std::make_pair(instance.position->first.value, instance.position->second.value);
@ -854,19 +900,27 @@ ComponentInstance *SchemaCreator::loadComponentInstance(InstanceNode instance, L
auto component = library.getComponent(instance.component.value);
// validate attributes
std::vector<InstanceAttribute*> attributes;
std::vector<InstanceAttribute> attributes;
for(auto& attr: instance.attributes) {
if(component.hasAttribute(attr.name.value, toType(attr.value.getType()))) {
auto attribute = component.getAttribute(attr.name.value);
attributes.push_back(new InstanceAttribute(attribute.getName(), toType(attr.value), attribute));
attributes.emplace_back(attribute.getName(), toType(attr.value, attribute.getDefault().getType()), attribute);
} else {
errors.push_back(SourceError(attr.name.span, "unknown attribute"));
errors.emplace_back(SourceError(attr.name.span, "unknown attribute"));
}
}
return new ComponentInstance(name, attributes, position, component);
if(attributes.size() < component.getAttributes().size()) {
for(auto& attr: component.getAttributes()) {
if(std::count_if(attributes.begin(), attributes.end(), [&attr](InstanceAttribute& attribute){ return attr.getName() == attribute.name; }) == 0) {
errors.emplace_back(SourceError(instance.span, "missing attribute '" + attr.getName() + "'"));
}
}
}
return std::make_shared<ComponentInstance>(name, attributes, position, component);
}
BusInstance *SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) {
std::shared_ptr<BusInstance> SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) {
auto name = instance.name.value;
auto position = std::make_pair(instance.position->first.value, instance.position->second.value);
@ -878,25 +932,25 @@ BusInstance *SchemaCreator::loadBusInstance(InstanceNode instance, Library &libr
size = instance.size->value;
}
return new BusInstance(name, position, bus, size);
return std::make_shared<BusInstance>(name, position, bus, static_cast<int>(size));
}
std::optional<WireInstance*> SchemaCreator::loadWireInstance(WireInstanceNode node) {
if(!node.display) {
errors.push_back(SourceError{node.span, "missing @text"});
return nullopt;
vector<Enumeration> SchemaCreator::createWireEnumeration(vector<Value> wireValues) {
vector<Enumeration> wires;
for(auto& wire: wireValues) {
if(wire.isType(Value::STRING)) {
wires.emplace_back(wire.asString(), wire);
}
}
auto display = loadDisplay(*node.display);
if(!display) {
return nullopt;
}
std::pair<int, int> position = std::make_pair(0, 0);
if(node.position) {
position = std::make_pair(node.position->first.value, node.position->second.value);
}
return std::optional<WireInstance*>(new WireInstance(node.name.value, *display, position));
return wires;
}
std::optional<Attribute> SchemaCreator::createMemoryAttribute() {
return Attribute("_memory", Value::fromMemoryReference(nullopt), createMemoryPopup());
}
std::optional<Popup> SchemaCreator::createMemoryPopup() {
return Popup("Postavi memoriju", "Postavi memoriju za izabrani procesor", Popup::AUTOMATIC, vector<Rule>{}, vector<Enumeration>{});
}
} // namespace domain

View File

@ -18,10 +18,11 @@ struct ComdelContext {
std::string name;
bool inComponent;
bool inConnection;
bool inSingleAutomaticConnection;
bool inBus;
ComdelContext(std::string name, bool inComponent, bool inConnection, bool inBus)
: name(name), inComponent(inComponent), inConnection(inConnection), inBus(inBus)
ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus)
: name(name), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection), inBus(inBus)
{}
bool doesAttributeExists(std::string name, Value::ValueType type) {
@ -52,6 +53,7 @@ class SchemaCreator
std::string libraryInfo;
std::string header;
std::string componentDirectory;
std::optional<std::string> componentHeader = nullopt;
std::vector<AddressSpace> addressSpaces;
std::vector<Component> components;
std::vector<Bus> buses;
@ -60,7 +62,7 @@ class SchemaCreator
std::vector<SourceError> errors;
std::vector<FunctionSignature> signatures;
std::vector<FunctionValidator*> validators;
std::optional<AddressSpace> loadAddressSpace(AddressSpaceNode node);
std::optional<Component> loadComponent(ComponentNode node);
@ -75,9 +77,10 @@ class SchemaCreator
std::optional<Connection> loadConnection(ConnectionNode node);
std::optional<Bus> loadBus(BusNode node);
ComponentInstance *loadComponentInstance(InstanceNode instance, Library &library);
BusInstance *loadBusInstance(InstanceNode instance, Library &library);
std::optional<WireInstance*> loadWireInstance(WireInstanceNode node);
std::shared_ptr<ComponentInstance> loadComponentInstance(InstanceNode instance, Library &library);
std::shared_ptr<BusInstance> loadBusInstance(InstanceNode instance, Library &library);
std::optional<Attribute> createMemoryAttribute();
std::optional<Bus> getBus(std::string name) {
for(auto &bus: buses) {
@ -114,11 +117,11 @@ class SchemaCreator
this->context.push_back(context);
}
void pushAdditional(std::string name) {
if(this->context.size() > 0) {
if(!this->context.empty()) {
this->context.push_back(current());
current().name = name;
} else {
ComdelContext con(name, false, false, false);
ComdelContext con(name, false, false, false, false);
push(con);
}
}
@ -130,7 +133,7 @@ class SchemaCreator
}
public:
SchemaCreator(std::vector<FunctionSignature> signatures);
SchemaCreator(std::vector<FunctionValidator*> validators);
std::vector<SourceError> getErrors() {
return errors;
@ -139,6 +142,10 @@ public:
std::optional<Library> loadLibrary(LibraryNode node);
Schema* loadSchema(SchemaNode node, Library &library);
vector <Enumeration> createWireEnumeration(vector<Value> vector1);
std::optional<Popup> createMemoryPopup();
};
} // namespace domain

View File

@ -68,6 +68,16 @@ std::string Value::asReference() {
throw std::exception();
}
std::optional<std::string> Value::asMemoryReference() {
return memoryReference;
}
domain::ComponentInstance *Value::asMemory() {
return memory;
}
void Value::setInt(long long value) {
if(isType(Value::INT)) {
this->intValue = value;
@ -124,11 +134,11 @@ Value Value::fromReference(std::string value, Value::ValueType type) {
val.reference = value;
return val;
}
Value Value::ofType(Value::ValueType type) {
Value val;
val.type = type;
return val;
}
Value Value::fromNull() {
@ -151,9 +161,29 @@ std::string Value::stringify() {
case ADDRESS_SPACE_REFERENCE:
case ATTRIBUTE_REFERENCE:
return reference;
case MEMORY_REFERENCE:
if(memoryReference->empty()) {
return "null";
} else {
return memoryReference.value();
}
default:
throw std::exception();
}
}
Value Value::fromMemoryReference(std::optional<std::string> value) {
Value val;
val.type = MEMORY_REFERENCE;
val.memoryReference = value;
return val;
}
Value Value::fromMemory(domain::ComponentInstance *memory) {
Value val;
val.type = MEMORY;
val.memory = memory;
return val;
}
} // namespace domain

View File

@ -9,6 +9,8 @@
namespace domain {
class ComponentInstance;
class Value
{
public:
@ -19,6 +21,8 @@ public:
ADDRESS_SPACE,
ADDRESS_SPACE_REFERENCE,
ATTRIBUTE_REFERENCE,
MEMORY_REFERENCE,
MEMORY,
WIRE_REFERENCE,
NIL,
UNDEFINED,
@ -30,6 +34,9 @@ private:
bool boolValue;
std::optional<AddressSpace> addressSpace;
std::string reference;
domain::ComponentInstance *memory;
std::optional<std::string> memoryReference;
ValueType type;
@ -39,6 +46,33 @@ public:
this->type = UNDEFINED;
}
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();
ValueType getType();
@ -48,6 +82,8 @@ public:
std::string asString();
bool asBool();
std::string asReference();
std::optional<std::string> asMemoryReference();
domain::ComponentInstance* asMemory();
AddressSpace asAddressSpace();
void setInt(long long intValue);
@ -64,6 +100,8 @@ public:
static Value fromAddressSpace(AddressSpace addressSpace);
static Value fromReference(std::string value, ValueType type);
static Value ofType(ValueType type);
static Value fromMemoryReference(std::optional<std::string> memoryReference);
static Value fromMemory(domain::ComponentInstance *memory);
};
} // namespace domain

View File

@ -94,9 +94,16 @@ ValueNode ValueNode::ofNull() {
return value;
}
ValueNode ValueNode::ofWire(std::string _value) {
ValueNode ValueNode::ofWire(std::optional<std::string> _value) {
ValueNode value;
value.type = EnumNode(WIRE);
value.identifierValue = std::optional<std::string>(_value);
value.identifierValue = _value;
return value;
}
ValueNode ValueNode::ofMemory(std::optional<std::string> _value) {
ValueNode value;
value.type = EnumNode(MEMORY);
value.identifierValue = _value;
return value;
}

View File

@ -77,6 +77,7 @@ public:
BOOL,
WIRE,
IDENTIFIER,
MEMORY,
NIL,
};
@ -88,7 +89,7 @@ private:
std::optional<std::string> identifierValue;
public:
ValueNode() = default;;
ValueNode() = default;
ValueType getType() {
return type.value;
@ -104,8 +105,9 @@ public:
static ValueNode ofInt(long long _value);
static ValueNode ofString(std::string _value);
static ValueNode ofIdentifier(std::string _value);
static ValueNode ofMemory(std::optional<std::string> _value);
static ValueNode ofNull();
static ValueNode ofWire(std::string _value);
static ValueNode ofWire(std::optional<std::string> _value);
};
struct ConditionNode
@ -181,8 +183,8 @@ struct DisplayNode: public AstNode
struct PinConnectionNode: public AstNode
{
enum ConnectionType {
CHECK_ONLY,
AUTOMATICALLY
REQUIRED,
OPTIONAL
};
StringNode message;
@ -217,7 +219,7 @@ struct WireNode: public AstNode
IdentifierNode name;
NumberNode size;
bool hidden;
bool hidden = false;
bool hasTerminateWith;
ValueNode terminateWith;
@ -273,7 +275,8 @@ struct BusNode: public AstNode
{
enum BusType {
AUTOMATIC,
REGULAR
REGULAR,
SINGLE_AUTOMATIC
};
EnumNode<BusType> type;
@ -291,6 +294,7 @@ struct LibraryNode: public AstNode
std::optional<StringNode> libraryInfo;
std::optional<StringNode> header;
std::optional<StringNode> componentDirectory;
std::optional<StringNode> componentHeader;
std::vector<AddressSpaceNode> addressSpaces;
@ -302,13 +306,6 @@ struct LibraryNode: public AstNode
};
// SCHEMA models
struct WireInstanceNode: public AstNode
{
IdentifierNode name;
std::optional<CountNode> position;
std::optional<DisplayNode> display;
};
struct InstanceAttributeNode: public AstNode
{
IdentifierNode name;
@ -338,7 +335,6 @@ struct ConnectionInstanceNode: public AstNode
std::optional<ConnectionComponentInstance> second;
IdentifierNode bus;
std::optional<IdentifierNode> wire;
std::vector<InstanceAttributeNode> attributes;
};
@ -349,7 +345,6 @@ struct SchemaNode: public AstNode
std::optional<StringNode> source;
std::vector<InstanceNode> instances;
std::vector<WireInstanceNode> wires;
std::vector<ConnectionInstanceNode> connections;
std::optional<LibraryNode> library;

View File

@ -243,6 +243,9 @@ std::optional<LibraryNode> ComdelParser::parse()
} else if(check(TokenType::KW_HEADER)) {
bump();
ASSIGN_OR_SET_ERR(library.header, parseString());
} else if(check(TokenType::KW_COMPONENT_HEADER)) {
bump();
ASSIGN_OR_SET_ERR(library.componentHeader, parseString());
} else if(check(TokenType::KW_DIRECTORY)) {
bump();
ASSIGN_OR_SET_ERR(library.componentDirectory, parseString());
@ -438,7 +441,7 @@ PResult<ComponentNode> ComdelParser::parseComponent()
ASSIGN_OR_RETURN_IF_ERR(component.name, parseIdentifier());
auto type = parseComponentType();
ASSIGN_OR_RETURN_IF_ERR(component.type, parseComponentType());
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
@ -465,6 +468,7 @@ PResult<ComponentNode> ComdelParser::parseComponent()
APPEND_OR_SET_ERR(component.rules, parseRule());
} else {
err = unexpected();
bump();
}
if(!err.has_value()) {
errors.push_back(err.error());
@ -583,6 +587,7 @@ PResult<BusNode> ComdelParser::parseBus() {
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
} else {
err = unexpected();
bump();
}
if(!err.has_value()) {
errors.push_back(err.error());
@ -607,11 +612,13 @@ PResult<EnumNode<BusNode::BusType>> ComdelParser::parseBusType() {
type = EnumNode(BusNode::AUTOMATIC);
} else if(tokenType.value().value == "regular") {
type = EnumNode(BusNode::REGULAR);
} else if(tokenType.value().value == "singleAutomatic") {
type = EnumNode(BusNode::SINGLE_AUTOMATIC);
} else {
type = PError(SourceError{current().span, "expected 'automatic' or 'regular'"});
type = PError(SourceError{current().span, "expected 'automatic', 'singleAutomatic' or 'regular'"});
}
} else {
type = PError(SourceError{current().span, "expected 'automatic' or 'regular'"});
type = PError(SourceError{current().span, "expected 'automatic', 'singleAutomatic' or 'regular'"});
}
return type;
}
@ -728,6 +735,7 @@ PResult<PinNode> ComdelParser::parsePin() {
pin.wires = *wires;
} else {
err = unexpected();
bump();
}
if(!err.has_value()) {
errors.push_back(err.error());
@ -771,15 +779,15 @@ PResult<EnumNode<PinConnectionNode::ConnectionType>> ComdelParser::parseConnecti
if(check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier();
if(identifier.value().value == "check_only") {
type = EnumNode(PinConnectionNode::CHECK_ONLY);
} else if(identifier.value().value == "automatically") {
type = EnumNode(PinConnectionNode::AUTOMATICALLY);
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 identifiers 'check_only' or 'automatically'"});
return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"});
}
} else {
return PError(SourceError{current().span, "expected identifiers 'check_only' or 'automatically'"});
return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"});
}
return spanner(type);
@ -848,13 +856,23 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
} else {
return unexpected();
}
} else if(attribute.type == ValueNode::MEMORY) {
if(check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier();
attribute.defaultValue = ValueNode::ofMemory(identifier->value);
} else if(check(TokenType::NIL)) {
bump();
attribute.defaultValue = ValueNode::ofMemory(std::nullopt);
} else {
return unexpected();
}
} else if(attribute.type == ValueNode::WIRE) {
if(check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier();
attribute.defaultValue = ValueNode::ofWire(identifier->value);
} else if(check(TokenType::NIL)) {
bump();
attribute.defaultValue = ValueNode::ofNull();
attribute.defaultValue = ValueNode::ofWire(std::nullopt);
} else {
return unexpected();
}
@ -948,6 +966,7 @@ PResult<PopupNode> ComdelParser::parsePopup() {
);
} else {
err = unexpected();
bump();
}
if(!err.has_value()) {
errors.push_back(err.error());
@ -965,7 +984,7 @@ PResult<PopupNode> ComdelParser::parsePopup() {
/****************************************************************************
*
* ConnectionNode := "@connection (" + COMPONENT + "." + PIN + "," + BUS) {" + CONNECTION + "}"
* ConnectionNode := "@connection (" + COMPONENT + "." + PIN + "," + BUS [ + "," + COMPONENT2 + "." + "PIN2"] + ") {" + CONNECTION + "}"
*
****************************************************************************/
PResult<ConnectionNode> ComdelParser::parseConnection() {
@ -984,7 +1003,6 @@ PResult<ConnectionNode> ComdelParser::parseConnection() {
if(check(TokenType::COMMA)) {
auto conn = ConnectionComponentNode{};
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(conn.component, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(conn.pin, parseIdentifier());
@ -1016,6 +1034,7 @@ PResult<ConnectionNode> ComdelParser::parseConnection() {
wireCount++;
} else {
err = unexpected();
bump();
}
if(!err.has_value()) {
errors.push_back(err.error());
@ -1170,8 +1189,6 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
PResult<poly<AstNode>> err;
if(check(TokenType::KW_INSTANCE)){
APPEND_OR_SET_ERR(schema.instances, parseInstance());
} else if(check(TokenType::KW_WIRE)) {
APPEND_OR_SET_ERR(schema.wires, parseWireInstance());
} else if(check(TokenType::KW_CONNECTION)) {
APPEND_OR_SET_ERR(schema.connections, parseConnectionInstance());
} else {
@ -1181,6 +1198,10 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
if(!err.has_value()) {
errors.push_back(err.error());
skipUntilNextKeyword();
if(check(TokenType::END_OF_FILE)) {
errors.emplace_back(current().span, "expected `}` reached EOF");
return std::nullopt;
}
}
}
if(!check(TokenType::RBRACE)) {
@ -1199,38 +1220,6 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
return spanner(schema);
}
PResult<WireInstanceNode> ComdelParser::parseWireInstance() {
auto spanner = getSpanner();
WireInstanceNode wireInstance;
RETURN_IF_NOT_TOKEN(TokenType::KW_WIRE);
ASSIGN_OR_RETURN_IF_ERR(wireInstance.name, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while(!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if(check(TokenType::KW_POSITION)) {
ASSIGN_OR_SET_ERR(wireInstance.position, parsePosition());
} else if(check(TokenType::KW_DISPLAY)) {
ASSIGN_OR_SET_ERR(wireInstance.display, parseDisplay());
} else {
err = unexpected();
}
if(!err.has_value()) {
errors.push_back(err.error());
skipUntilNextKeyword();
if(check(TokenType::END_OF_FILE)) {
return PError({Span(spanner.lo), "Reached EOF"});
}
}
}
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
return spanner(wireInstance);
}
/****************************************************************************
*
@ -1281,6 +1270,7 @@ PResult<InstanceNode> ComdelParser::parseInstance() {
instance.size = *number;
} else {
err = unexpected();
bump();
}
if(!err.has_value()) {
errors.push_back(err.error());
@ -1333,13 +1323,11 @@ PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
while(!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if(check(TokenType::KW_WIRE)) {
bump();
ASSIGN_OR_SET_ERR(connection.wire, parseIdentifier());
} else if(check(TokenType::KW_ATTRIBUTE)) {
if(check(TokenType::KW_ATTRIBUTE)) {
APPEND_OR_SET_ERR(connection.attributes, parseInstanceAttribute());
} else {
err = unexpected();
bump();
}
if(!err.has_value()) {
errors.push_back(err.error());
@ -1356,13 +1344,16 @@ PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
}
PResult<ValueNode> ComdelParser::parseConnectionWire() {
auto spanner = getSpanner();
if(check(TokenType::NUMBER)) {
return ValueNode::ofInt(parseNumber()->value);
return spanner(ValueNode::ofInt(parseNumber()->value));
} else if(check(TokenType::NIL)) {
bump();
return ValueNode::ofNull();
return spanner(ValueNode::ofNull());
} else if(check(TokenType::STRING)) {
return spanner(ValueNode::ofString(parseString()->value));
} else if(check(TokenType::IDENTIFIER)) {
return ValueNode::ofIdentifier(parseIdentifier()->value);
return spanner(ValueNode::ofIdentifier(parseIdentifier()->value));
} else {
return unexpected();
}

View File

@ -88,7 +88,6 @@ private:
PResult<ValueNode> parseValue();
PResult<WireInstanceNode> parseWireInstance();
PResult<CountNode> parsePosition();
PResult<InstanceNode> parseInstance();
PResult<InstanceAttributeNode> parseInstanceAttribute();

View File

@ -72,6 +72,7 @@ enum class TokenType {
KW_NAME,
KW_INFO,
KW_HEADER,
KW_COMPONENT_HEADER,
KW_DIRECTORY,
KW_LIBRARY,
KW_ADDRESS,

View File

@ -83,6 +83,7 @@ TokenTables::TokenTables() {
add( TokenType::KW_NAME, "@name", TOKENIZABLE | KEYWORD_NAME),
add( TokenType::KW_INFO, "@info", TOKENIZABLE | KEYWORD_NAME),
add( TokenType::KW_HEADER, "@header", TOKENIZABLE | KEYWORD_NAME),
add( TokenType::KW_COMPONENT_HEADER, "@componentHeader", TOKENIZABLE | KEYWORD_NAME),
add( TokenType::KW_DIRECTORY, "@directory", TOKENIZABLE | KEYWORD_NAME),
add( TokenType::KW_LIBRARY, "@library", TOKENIZABLE | KEYWORD_NAME),
add( TokenType::KW_ADDRESS, "@address", TOKENIZABLE | KEYWORD_NAME),

View File

@ -1,6 +1,8 @@
@name "Jednostavni FRISC"
@info "Ova biblioteka omogućuje kreiranje sustava s procesorom FRISC s pojednostavljenim načinom spajanja bez potrebe da se spajaju pojedine linije sabirnice."
@directory "libraries\frisc\vjezba1"
@header "// Version 0.0.1"
@componentHeader " clock 100MHz;"
@address glavniAS(0,0xFFFFFFFF)
@address pomocniAS(0xFFFF0000,0xFFFFFFFF)
@ -17,7 +19,7 @@
@component FRISC processor {
@instanceName "procesor"
@tooltip "procesor FRISC, mora postojati jedan"
@tooltip "Procesor FRISC, mora postojati jedan"
@count (1, 1)
@source "FRISC.cdl"
@display {
@ -51,7 +53,7 @@
}
@pin glavniPin inOut {
@tooltip "pin za spajanje na glavnu sabirnicu"
@connection check_only("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu")
@connection required("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu")
@display {
/*
pin {
@ -75,6 +77,27 @@
@tooltip "Memorijska komponenta, mora postojati barem jedna"
@count (1,1000)
@source "memory.cdl"
@attribute sinkroniziran bool default false {
@popup automatic {
@title "Postavite sinkroniziranost"
@text "Zadajte sinkronizaciju"
}
}
@attribute brzina int default 1 {
@popup automatic {
@title "Postavite brzinu memorije"
@text "Zadajte brzinu memorije"
@enumerated {
"Spora" = 1,
"Srednja" = 5,
"Brza" = 25,
}
}
}
@attribute kapacitet int default 65536 {
@popup automatic {
@title "Kapacitet memorije"
@ -146,7 +169,7 @@
@pin glavniPin inOut {
@tooltip "pin za spajanje na glavnu sabirnicu"
@connection check_only("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu")
@connection required("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu")
@display {
/*
pin {
@ -171,6 +194,7 @@
@tooltip "DMA-kontroler"
@count (1,1000)
@source "dma.cdl"
@attribute pocetnaAdresa int default 0 {
@popup automatic {
@title "Početna adresa DMA-kontrolera"
@ -214,7 +238,7 @@
@pin glavniPin in {
@tooltip "pin za spajanje na glavnu sabirnicu"
@connection check_only("COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu")
@connection required("COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu")
@display {
/*
pin {
@ -235,7 +259,7 @@
@pin dodatnaPoveznica in {
@tooltip "pin za spajanje na pomocnu sabirnicu"
@connection check_only("COMDEL se ne može stvoriti. DMA nije spojen na nesto!")
@connection optional("COMDEL se ne može stvoriti. DMA nije spojen na nesto!")
@display {
pin {
x: 0; y: 0; w: 0; h: 0;
@ -273,9 +297,9 @@
INT2 wired_and,
INT3 wired_and,
SIZE<3>,
IACK,
BREQ,
BACK
IACK hidden,
BREQ hidden,
BACK hidden
}
}
@bus PIOSabirnica automatic {
@ -285,6 +309,14 @@
STROBE
}
}
@bus Test singleAutomatic {
@tooltip "sabirnica za spajanje FRISC a s memorijama i UI/jedinicama"
@count (1,1)
@wires {
CONNECTOR,
}
}
@connection (FRISC.glavniPin, glavnaSabirnica) {
@wires{ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, IACK, 1, null}
@ -307,4 +339,28 @@
}
}
@wires{ADR, DATA, READ, WRITE, SIZE, WAIT, interupt, BREQ, BACK}
}
@connection (DMA.glavniPin, PIOSabirnica, FRISC.glavniPin) {
@wires{PIO_DATA, READY, STROBE}
@wires{PIO_DATA, READY, STROBE}
}
@connection (FRISC.glavniPin, Test, Memorija.glavniPin) {
@wires{null, "READY", null}
@wires{"PIO_DATA", null, null}
@attribute dmaPoveznica string default "" {
@popup automatic {
@title "Spoji DMA kraj"
@text "Odaberite poveznicu za dma kraja"
}
}
@attribute mmaPoveznica string default "" {
@popup automatic {
@title "Spoji MMA kraj"
@text "Odaberite poveznicu za mma kraja"
}
}
}

View File

@ -3,10 +3,13 @@
@schema {
@instance proc FRISC {
@position (0, 0)
@attribute _memory null
}
@instance mem Memorija {
@position (0, 250)
@attribute sinkroniziran false
@attribute brzina 1
@attribute kapacitet 1024
@attribute size 8
@attribute pocetnaAdresa 1023
@ -17,39 +20,14 @@
@size 100
}
@wire wire_001 {
@position (50, 116)
@display {
/*
line {
color: blue;
points: 100;
}*/
line {
x1: 0; y1: 0; x2: 0; y2: 84;
}
}
}
@instance testBus Test {}
@wire wire_002 {
@position (50, 220)
@display {
/*
line {
color: blue;
points: 100;
}*/
line {
x1: 0; y1: 0; x2: 0; y2: 14;
}
}
}
@connection (proc.glavniPin, bus) {}
@connection (proc.glavniPin, bus) {
@wire wire_001
}
@connection (mem.glavniPin, bus) {}
@connection (mem.glavniPin, bus) {
@wire wire_002
@connection (proc.glavniPin, testBus, mem.glavniPin) {
@attribute dmaPoveznica "READY"
@attribute mmaPoveznica "PIO_DATA"
}
}

View File

@ -3,10 +3,13 @@
@schema {
@instance proc FRISC {
@position (0, 0)
@attribute _memory mem
}
@instance mem Memorija {
@position (0, 250)
@attribute sinkroniziran false
@attribute brzina 1
@attribute kapacitet 1024
@attribute size 8
@attribute pocetnaAdresa 1023
@ -17,18 +20,17 @@
@size 100
}
@wire wire_001 {
@position (50, 116)
@display {}
}
@wire wire_002 {
@position (50, 220)
@display {}
@instance testBus Test {
@position (0, 200)
@size 0
}
@connection (proc.glavniPin, bus) {
@wire wire_001
}
@connection (mem.glavniPin, bus) {
@wire wire_002
}
@connection (proc.glavniPin, testBus, mem.glavniPin) {
@attribute dmaPoveznica "READY"
@attribute mmaPoveznica "PIO_DATA"
}
}

View File

@ -10,20 +10,26 @@
#include <iostream>
#include <QPlainTextEdit>
#include <sstream>
#include <comdel/domain/comdelvalidator.h>
#include <fstream>
#include <comdel/domain/comdel_generator.h>
std::optional<domain::Library> MainWindow::library;
domain::Schema* MainWindow::schema;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
schema = nullptr;
library = std::nullopt;
ui->setupUi(this);
setupUi();
// define allowed methods
signatures = domain::getSupportedFunctions();
validators = domain::getSupportedValidators();
}
void MainWindow::setupUi()
@ -37,6 +43,7 @@ void MainWindow::setupUi()
ui->toolBar->addAction("Load library", this, &MainWindow::onLoadLibrary);
ui->toolBar->addAction("Load schema", this, &MainWindow::onLoadSchema);
ui->toolBar->addAction("Save schema", this, &MainWindow::onStoreScheme);
ui->toolBar->addAction("Generate system", this, &MainWindow::onGenerateComdel);
connect(ui->actionValidate, &QAction::triggered, this, &MainWindow::onValidateSchema);
@ -77,7 +84,7 @@ void MainWindow::onLoadLibrary() {
ParseContext parseContext;
auto libraryNode = loadLibraryFromFile(&parseContext, filename.toStdString().c_str(), buffer);
if(libraryNode) {
domain::SchemaCreator generator(signatures);
domain::SchemaCreator generator(validators);
library = generator.loadLibrary(*libraryNode);
for (auto& error : generator.getErrors()) {
@ -115,7 +122,7 @@ void MainWindow::onLoadSchema() {
auto schemaNode = loadSchemaFromFile(&parseContext, filename.toStdString().c_str(), buffer);
if(schemaNode) {
domain::SchemaCreator generator(signatures);
domain::SchemaCreator generator(validators);
library = generator.loadLibrary(*schemaNode->library);
librarySource = schemaNode->source->value;
@ -129,7 +136,11 @@ void MainWindow::onLoadSchema() {
for (auto& error : generator.getErrors()) {
parseContext.formatError(error, buffer, "ERROR: ");
delete schema;
schema = nullptr;
}
} else {
library = std::nullopt;
}
if(generator.getErrors().empty()) {
@ -152,72 +163,39 @@ void MainWindow::onStoreScheme() {
std::ostringstream buffer;
buffer << "@source " << this->librarySource << std::endl << std::endl;
buffer << "@schema {" << std::endl;
for(auto &instance: schema->instances) {
auto componentInstance = dynamic_cast<domain::ComponentInstance*>(instance);
if(componentInstance != nullptr) {
buffer << "\t" << "@instance " << componentInstance->name << " " << componentInstance->component.getName() << " {" << std::endl;
buffer << "\t\t" << "@position (" << componentInstance->position.first << ", " << componentInstance->position.second << ")" << std::endl;
for(auto &attribute: instance->attributes) {
buffer << "\t\t" << "@attribute " << attribute->name << " " << attribute->value.stringify() << std::endl;
}
buffer << "\t}" << std::endl << std::endl;
}
auto busInstance = dynamic_cast<domain::BusInstance*>(instance);
if(busInstance != nullptr) {
buffer << "\t" << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {" << std::endl;
buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second << ")" << std::endl;
buffer << "\t\t" << "@size " << busInstance->size << std::endl;
buffer << "\t}" << std::endl << std::endl;
}
}
for(auto &wire: schema->wires) {
buffer << "\t" << "@wire " << wire->name << " {" << std::endl;
buffer << "\t\t" << "@position (" << wire->position.first << ", " << wire->position.second << ")" << std::endl;
buffer << "\t\t" << "@display {}" << std::endl;
buffer << "\t" << "}" << std::endl;
}
for(auto &conn: schema->connections) {
auto busConn = dynamic_cast<domain::BusConnectionInstance*>(conn);
if(busConn) {
buffer << "\t" << "@connection (" << busConn->instance->name << "." << busConn->connection.getComponent().pin << ", " << busConn->bus->name << ") {" << std::endl;
buffer << "\t\t"<< "@wire " << busConn->wire->name << std::endl;
buffer << "\t" << "}" << std::endl;
}
}
buffer << "}" << std::endl;
auto value = buffer.str();
domain::generateSchemaFile(librarySource, schema, buffer);
std::ofstream out(filename.toStdString(), std::ios::out | std::ios::binary);
out<<buffer.str();
out.close();
}
void MainWindow::onGenerateComdel() {
if(schema == nullptr) {
return;
}
auto filename = QFileDialog::getSaveFileName(this,
tr("Save schema"), "/home", tr("Comdel system (*.system)"));
std::ostringstream buffer;
domain::generateComdelFile(schema, library.value(), buffer);
std::ofstream out(filename.toStdString(), std::ios::out | std::ios::binary);
out<<buffer.str();
out.close();
}
void MainWindow::onValidateSchema(bool /*toggled*/) {
if(schema == nullptr) {
return;
}
this->validationErrors.clear();
std::map<std::string, domain::FunctionCallback> callbacks;
auto functions = domain::getSupportedFunctions();
for(auto &func: functions) {
callbacks[func.name] = func.callback;
}
domain::ComdelValidator validator{callbacks};
domain::ComdelValidator validator{validators};
domain::ValidationContext context;
context.instance = nullptr;
@ -258,7 +236,10 @@ void MainWindow::onValidateSchema(bool /*toggled*/) {
void MainWindow::clear() {
validationErrors.clear();
schema = nullptr;
if(schema != nullptr) {
delete schema;
schema = nullptr;
}
library = std::nullopt;
libraryDisplay->setLibrary(library);

View File

@ -27,24 +27,35 @@ public:
display::Library *libraryDisplay;
display::Schema *schemaDisplay;
std::optional<domain::Library> library = std::nullopt;
domain::Schema* schema = nullptr;
static std::optional<domain::Library> library;
static domain::Schema* schema;
std::vector<domain::FunctionSignature> signatures;
std::vector<domain::FunctionValidator*> validators;
void setupUi();
void clear();
static domain::Schema* getSchema() {
return schema;
}
static std::optional<domain::Library> getLibrary() {
return library;
}
private slots:
void onLoadLibrary();
void onLoadSchema();
void onValidateSchema(bool toggled);
void onStoreScheme();
void onGenerateComdel();
private:
std::string librarySource;
Ui::MainWindow *ui;
QPlainTextEdit *log;
std::vector<domain::ValidationError> validationErrors;
};
#endif // MAIN_WINDOW_H