diff --git a/application.cpp b/application.cpp index 22fa292..a18824f 100644 --- a/application.cpp +++ b/application.cpp @@ -40,12 +40,12 @@ bool Application::loadLibrary(std::string& filename, std::ostream &errorOutput) } if(library.has_value()) { + errorOutput<<"Failed creating library model"< Application::addComponent(domain::Component component, std::vector attributes, int x, int y) { + std::set names; + for(const auto& c: schema->componentInstances) { + names.insert(c->name); + } + std::string name = generateName(names, component.getInstanceName()); + + schema->componentInstances.push_back(std::make_shared(name, attributes, std::make_pair(x, y), component)); + return schema->componentInstances.back(); +} + +std::shared_ptr Application::addBus(domain::Bus bus, int x, int y) { + std::set names; + for(const auto& b: schema->busInstances) { + names.insert(b->name); + } + std::string name = generateName(names, bus.getInstanceName()); + + schema->busInstances.push_back(std::make_shared(name, std::make_pair(x, y), bus)); + return schema->busInstances.back(); +} + + +std::string Application::generateName(std::set& names, std::string instanceName) { + if(names.find(instanceName) == names.end()) { + return instanceName; + } + char buffer[4]; + for(int i=0; i<1000; i++) { + sprintf(buffer, "%03d", i); + auto name = instanceName + "_" + buffer; + if(names.find(name) == names.end()) { + return name; + } + } + // return default value as this should never happen + return instanceName; +} \ No newline at end of file diff --git a/application.h b/application.h index 2a4fd56..f5443e9 100644 --- a/application.h +++ b/application.h @@ -6,6 +6,7 @@ #define SCHEMEEDITOR_APPLICATION_H +#include #include "comdel/domain/library.h" #include "comdel/domain/schema.h" #include "comdel/domain/comdel_validator.h" @@ -16,10 +17,13 @@ private: std::string libraryPath; std::optional library = std::nullopt; domain::Schema* schema = nullptr; + std::vector validators = domain::getSupportedValidators(); + + std::string generateName(std::set& names, std::string instanceName); + public: std::optional getLibrary(); domain::Schema* getSchema(); - std::vector validators = domain::getSupportedValidators(); void clear(); @@ -32,6 +36,9 @@ public: std::vector validateSchema(); std::vector generateComdel(std::ostringstream &output); + std::shared_ptr addComponent(domain::Component component, std::vector attributes, int x, int y); + std::shared_ptr addBus(domain::Bus bus, int x, int y); + static bool hasErrors(std::vector empty); ~Application() = default; diff --git a/comdel/display/component_display.cpp b/comdel/display/component_display.cpp index cb72069..bb7839b 100644 --- a/comdel/display/component_display.cpp +++ b/comdel/display/component_display.cpp @@ -7,13 +7,19 @@ #include #include #include +#include namespace display { void Component::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu menu; menu.addAction("Izmjeni ime", [this]() { - auto dialog = new NameDialog(this->instance.get()); + std::set names; + for(const auto &component: Application::instance()->getSchema()->componentInstances) { + names.insert(component->name); + } + + auto dialog = new NameDialog(this->instance.get(), names); dialog->exec(); }); menu.addSeparator(); @@ -93,7 +99,12 @@ namespace display { void Bus::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu menu; menu.addAction("Izmjeni ime", [this]() { - auto dialog = new NameDialog(this->busInstance.get()); + std::set names; + for(const auto &component: Application::instance()->getSchema()->busInstances) { + names.insert(component->name); + } + + auto dialog = new NameDialog(this->busInstance.get(), names); dialog->exec(); }); menu.exec(event->screenPos()); @@ -110,7 +121,7 @@ namespace display { QVariant BusGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if (change == ItemPositionChange && scene()) { // value is the new position. - QPointF newPos = value.toPointF(); + QPoint newPos = value.toPointF().toPoint(); busInstance->position.first = newPos.x(); busInstance->position.second = newPos.y(); @@ -136,7 +147,7 @@ namespace display { QVariant ComponentGroup::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if (change == ItemPositionChange && scene()) { // value is the new position. - QPointF newPos = value.toPointF(); + QPoint newPos = value.toPointF().toPoint(); componentInstance->position.first = newPos.x(); componentInstance->position.second = newPos.y(); diff --git a/comdel/display/name_dialog.cpp b/comdel/display/name_dialog.cpp index 29505ba..ea13936 100644 --- a/comdel/display/name_dialog.cpp +++ b/comdel/display/name_dialog.cpp @@ -2,37 +2,54 @@ // Created by bbr on 18. 04. 2022.. // +#include #include "name_dialog.h" -display::NameDialog::NameDialog(domain::ComponentInstance *instance) : componentInstance(instance) { +display::NameDialog::NameDialog(domain::ComponentInstance *instance, std::set& names) : componentInstance(instance), usedNames(names) { + usedNames.erase(instance->name); + auto *layout = new QVBoxLayout(this); layout->addWidget(new QLabel("Izmjeni ime", this)); edit = new QLineEdit(this); edit->insert(instance->name.c_str()); + connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate); layout->addWidget(edit); this->setWindowTitle("Izmjeni ime"); - auto *button = new QPushButton("Ažuriraj", this); + button = new QPushButton("Ažuriraj", this); connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange); layout->addWidget(button); this->setLayout(layout); } -display::NameDialog::NameDialog(domain::BusInstance *instance): busInstance(instance) { +display::NameDialog::NameDialog(domain::BusInstance *instance, std::set& names): busInstance(instance), usedNames(names) { + usedNames.erase(instance->name); + auto *layout = new QVBoxLayout(this); layout->addWidget(new QLabel("Izmjeni ime", this)); edit = new QLineEdit(this); edit->insert(instance->name.c_str()); + connect(edit, &QLineEdit::textChanged, this, &NameDialog::onNameUpdate); layout->addWidget(edit); this->setWindowTitle("Izmjeni ime"); - auto *button = new QPushButton("Ažuriraj", this); + button = new QPushButton("Ažuriraj", this); connect(button, &QPushButton::clicked, this, &NameDialog::onNameChange); layout->addWidget(button); this->setLayout(layout); } +void display::NameDialog::onNameUpdate(const QString &text) { + if(usedNames.find(text.toStdString()) == usedNames.end()) { + button->setDisabled(false); + } else { + button->setDisabled(true); + } +} + void display::NameDialog::onNameChange() { + + if (componentInstance != nullptr) { componentInstance->name = this->edit->text().toStdString(); } else if (busInstance != nullptr) { diff --git a/comdel/display/name_dialog.h b/comdel/display/name_dialog.h index 7e6960d..d4a8a50 100644 --- a/comdel/display/name_dialog.h +++ b/comdel/display/name_dialog.h @@ -7,24 +7,28 @@ #include #include +#include + #include namespace display { class NameDialog : public QDialog { + std::set usedNames; QLineEdit *edit = nullptr; domain::ComponentInstance *componentInstance = nullptr; domain::BusInstance *busInstance = nullptr; + QPushButton *button; public: - NameDialog(domain::ComponentInstance *instance); + NameDialog(domain::ComponentInstance *instance, std::set& names); - NameDialog(domain::BusInstance *instance); + NameDialog(domain::BusInstance *instance, std::set& names); public slots: - + void onNameUpdate(const QString& text); void onNameChange(); }; diff --git a/comdel/display/schema_display.cpp b/comdel/display/schema_display.cpp index fe2c171..8a5fc71 100644 --- a/comdel/display/schema_display.cpp +++ b/comdel/display/schema_display.cpp @@ -1,5 +1,7 @@ #include "component_display.h" #include "schema_display.h" +#include "application.h" +#include "attribute_dialog.h" #include #include @@ -86,15 +88,30 @@ namespace display { auto attributes = std::vector(); for (auto attr: component.getAttributes()) { - attributes.emplace_back(attr.getName(), attr.getDefault(), attr); + domain::InstanceAttribute attribute(attr.getName(), attr.getDefault(), attr); + if(attr.getPopup().has_value() && attr.getPopup()->getType() == domain::Popup::AUTOMATIC) { + if(attr.getDefault().isType(domain::Value::MEMORY_REFERENCE)) { + auto dialog = new MemoryDialog(&attribute, schema->componentInstances); + if(dialog->exec() == QDialog::Rejected) { + // if any dialog isn't set, whole creation is rejected + event->ignore(); + return; + } + } else { + auto dialog = new AttributeDialog(&attribute); + if(dialog->exec() == QDialog::Rejected) { + // if any dialog isn't set, whole creation is rejected + event->ignore(); + return; + } + } + } + attributes.push_back(attribute); } - auto currentPos = this->mapToScene(event->pos()); + auto currentPos = this->mapToScene(event->pos()).toPoint(); - auto instance = std::make_shared(component.getInstanceName(), attributes, - std::make_pair(currentPos.x(), currentPos.y()), - component); - schema->componentInstances.push_back(instance); + auto instance = Application::instance()->addComponent(component, attributes, currentPos.x(), currentPos.y()); auto group = new display::ComponentGroup(instance); scene.addItem(group); @@ -111,11 +128,9 @@ namespace display { if (event->mimeData()->hasFormat("comdel/bus")) { auto bus = library->getBus(event->mimeData()->data("comdel/bus").toStdString()); - auto currentPos = this->mapToScene(event->pos()); + auto currentPos = this->mapToScene(event->pos()).toPoint(); - auto instance = std::make_shared(bus.getName(), - std::make_pair(currentPos.x(), currentPos.y()), bus); - schema->busInstances.push_back(instance); + auto instance = Application::instance()->addBus(bus, currentPos.x(), currentPos.y()); auto group = new display::BusGroup(instance); scene.addItem(group); diff --git a/comdel/domain/bus.cpp b/comdel/domain/bus.cpp index 5f7c8cc..10f90e5 100644 --- a/comdel/domain/bus.cpp +++ b/comdel/domain/bus.cpp @@ -10,6 +10,11 @@ namespace domain { return name; } + std::string Bus::getInstanceName() { + return instanceName; + } + + int Wire::getWidth() { return width; } @@ -30,9 +35,9 @@ namespace domain { return type; } - Bus::Bus(std::string name, std::string tooltip, BusType type, std::pair count, std::vector wires, + Bus::Bus(std::string name, std::string instanceName, std::string tooltip, BusType type, std::pair count, std::vector wires, std::optional displayBus) - : name(name), tooltip(tooltip), type(type), count(count), wires(wires), displayBus(displayBus) {} + : name(name), instanceName(instanceName), tooltip(tooltip), type(type), count(count), wires(wires), displayBus(displayBus) {} std::string Bus::getName() { return name; @@ -57,5 +62,4 @@ namespace domain { std::optional Bus::getDisplayBus() { return displayBus; } - } // namespace domain diff --git a/comdel/domain/bus.h b/comdel/domain/bus.h index fcbd2e2..3cc02ab 100644 --- a/comdel/domain/bus.h +++ b/comdel/domain/bus.h @@ -54,6 +54,7 @@ namespace domain { }; private: std::string name; + std::string instanceName; std::string tooltip; BusType type; @@ -62,11 +63,13 @@ namespace domain { std::vector wires; public: - Bus(std::string name, std::string tooltip, BusType type, std::pair count, std::vector wires, + Bus(std::string name, std::string instanceName, std::string tooltip, BusType type, std::pair count, std::vector wires, std::optional display = std::nullopt); std::string getName(); + std::string getInstanceName(); + std::string getTooltip(); BusType getType(); diff --git a/comdel/domain/schema_creator.cpp b/comdel/domain/schema_creator.cpp index 5733839..54e0bde 100644 --- a/comdel/domain/schema_creator.cpp +++ b/comdel/domain/schema_creator.cpp @@ -167,8 +167,7 @@ namespace domain { } for (auto &comp: node.components) { - std::optional component; - component = loadComponent(comp); + auto component = loadComponent(comp); if (component) { components.push_back(*component); } @@ -196,13 +195,24 @@ namespace domain { } } - return Library(name, libraryInfo, header, componentDirectory, componentHeader, addressSpaces, components, buses, - connections, messages); + if(errors.empty()) { + return Library(name, libraryInfo, header, componentDirectory, componentHeader, addressSpaces, components, buses, + connections, messages); + } else { + return nullopt; + } + } std::optional SchemaCreator::loadBus(BusNode node) { std::string busName = node.name.value; + if (!node.instanceName) { + errors.emplace_back(node.span, "missing @instanceName"); + return nullopt; + } + std::string instanceName = node.instanceName->value; + auto count = std::make_pair(1, 1); if (node.count) { count = std::make_pair(node.count->first.value, node.count->second.value); @@ -259,7 +269,7 @@ namespace domain { return nullopt; } - return Bus(busName, tooltip, type, count, wires, displayBus); + return Bus(busName, instanceName, tooltip, type, count, wires, displayBus); } @@ -497,7 +507,7 @@ namespace domain { pop(); return nullopt; } - std::string instanceName = node.instanceName->asString(); + std::string instanceName = node.instanceName->value; auto count = std::make_pair(1, 1); if (node.count) { @@ -950,7 +960,13 @@ namespace domain { } } - return schema; + if(errors.empty()) { + return schema; + } else { + delete schema; + return nullptr; + } + } shared_ptr SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) { diff --git a/comdel/parser/ast_nodes.h b/comdel/parser/ast_nodes.h index 65f82ad..38f4f30 100644 --- a/comdel/parser/ast_nodes.h +++ b/comdel/parser/ast_nodes.h @@ -309,7 +309,7 @@ struct ComponentNode : public AstNode { std::optional source; EnumNode type; std::vector rules; - std::optional instanceName; + std::optional instanceName; std::optional count; std::optional display; std::vector pins; @@ -325,6 +325,7 @@ struct BusNode : public AstNode { EnumNode type; IdentifierNode name; + std::optional instanceName; std::optional tooltip; std::optional count; std::optional display; diff --git a/comdel/parser/comdel_parser.cpp b/comdel/parser/comdel_parser.cpp index 30c694a..fb970ad 100644 --- a/comdel/parser/comdel_parser.cpp +++ b/comdel/parser/comdel_parser.cpp @@ -438,7 +438,7 @@ PResult ComdelParser::parseComponent() { PResult> err; if (check(TokenType::KW_INSTANCE_NAME)) { bump(); - ASSIGN_OR_SET_ERR(component.instanceName, parseString()); + ASSIGN_OR_SET_ERR(component.instanceName, parseIdentifier()); } else if (check(TokenType::KW_TOOLTIP)) { bump(); ASSIGN_OR_SET_ERR(component.tooltip, parseString()); @@ -554,22 +554,30 @@ PResult ComdelParser::parseBus() { PResult> err; if (check(TokenType::KW_TOOLTIP)) { bump(); - ASSIGN_OR_RETURN_IF_ERR(bus.tooltip, parseString()); + ASSIGN_OR_SET_ERR(bus.tooltip, parseString()); + } else if (check(TokenType::KW_INSTANCE_NAME)) { + bump(); + ASSIGN_OR_SET_ERR(bus.instanceName, parseIdentifier()); } else if (check(TokenType::KW_COUNT)) { - ASSIGN_OR_RETURN_IF_ERR(bus.count, parseCount()); + ASSIGN_OR_SET_ERR(bus.count, parseCount()); } else if (check(TokenType::KW_DISPLAY)) { - ASSIGN_OR_RETURN_IF_ERR(bus.display, parseDisplay()); + ASSIGN_OR_SET_ERR(bus.display, parseDisplay()); } else if (check(TokenType::KW_WIRES)) { bump(); - RETURN_IF_NOT_TOKEN(TokenType::LBRACE); - while (check(TokenType::IDENTIFIER)) { - APPEND_OR_RETURN_IF_ERR(bus.wires, parseWire()); + if(consume(TokenType::LBRACE)) { + while (check(TokenType::IDENTIFIER)) { + APPEND_OR_RETURN_IF_ERR(bus.wires, parseWire()); - if (check(TokenType::COMMA)) { - RETURN_IF_NOT_TOKEN(TokenType::COMMA); + if (check(TokenType::COMMA)) { + RETURN_IF_NOT_TOKEN(TokenType::COMMA); + } } + } else { + err = unexpected(); + } + if(!consume(TokenType::RBRACE)) { + err = unexpected(); } - RETURN_IF_NOT_TOKEN(TokenType::RBRACE); } else { err = unexpected(); bump(); diff --git a/examples/simplified FRISC model/comdel.system b/examples/simplified FRISC model/comdel.system index 2ded265..01d2561 100644 --- a/examples/simplified FRISC model/comdel.system +++ b/examples/simplified FRISC model/comdel.system @@ -23,21 +23,19 @@ component System wire --BACK; - //directRam - wire INT; - - // components -------------------------------------------- - subcomponent Memorija mem(ADR, DATA, READ, WRITE, SIZE, WAIT, INT); - subcomponent FRISC proc(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, INT); - subcomponent FRISC procesor(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 93852075053817, 0, null, null); - subcomponent FRISC procesor(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 93852075053817, 0, null, null); + subcomponent Memorija mem(ADR, DATA, READ, WRITE, SIZE, WAIT, 94534054858378, 0, null, null); + subcomponent FRISC procesor_002(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 94534054858378, 0, null, null); + subcomponent FRISC procesor_001(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 94534054858378, 0, null, null); + subcomponent FRISC procesor_000(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 94534054858378, 0, null, null); + subcomponent FRISC procesor(ADR, DATA, READ, WRITE, SIZE, WAIT, INT0, INT1, INT2, INT3, --IACK, 1, *, 94534054858378, 0, null, null); display { - component { x: 0; y: 0; ref: "proc"; } + component { x: 0; y: 0; ref: "procesor_002"; } component { x: 0; y: 250; ref: "mem"; } - component { x: -185; y: 9; ref: "procesor"; } - component { x: -181; y: 194; ref: "procesor"; } + component { x: -89; y: 74; ref: "procesor_001"; } + component { x: -175; y: 195; ref: "procesor_000"; } + component { x: -195; y: 63; ref: "procesor"; } // bus bus @@ -47,13 +45,10 @@ component System } - // directRam bus - - line {x1:50; y1:116; x2:50; y2:210;} line {x1:50; y1:234; x2:50; y2:210;} - line {x1:-16; y1:278; x2:116; y2:50;} - line {x1:-135; y1:125; x2:50; y2:210;} - line {x1:-131; y1:310; x2:50; y2:210;} + line {x1:-39; y1:190; x2:50; y2:210;} + line {x1:-145; y1:179; x2:50; y2:210;} + line {x1:-125; y1:311; x2:50; y2:210;} } } \ No newline at end of file diff --git a/examples/simplified FRISC model/frisc_library.csl b/examples/simplified FRISC model/frisc_library.csl index 40580aa..4561efd 100644 --- a/examples/simplified FRISC model/frisc_library.csl +++ b/examples/simplified FRISC model/frisc_library.csl @@ -18,7 +18,7 @@ } @component FRISC processor { - @instanceName "procesor" + @instanceName procesor @tooltip "Procesor FRISC, mora postojati jedan" @count (1, 1) @source "FRISC.cdl" @@ -77,7 +77,7 @@ } @component Memorija memory { - @instanceName "memorija" + @instanceName memorija @tooltip "Memorijska komponenta, mora postojati barem jedna" @count (1,1000) @source "memory.cdl" @@ -219,7 +219,7 @@ } @component DMA { - @instanceName "dma" + @instanceName dma @tooltip "DMA-kontroler" @count (0,1000) @source "dma.cdl" @@ -299,6 +299,7 @@ } @bus glavnaSabirnica regular { + @instanceName glavnaSabirnica @tooltip "sabirnica za spajanje FRISC a s memorijama i UI/jedinicama" @count (1,1) @display { @@ -334,6 +335,7 @@ } } @bus PIOSabirnica automatic { + @instanceName PIOSabirnica @count (0, 20) @wires { PIO_DATA<8>, @@ -343,6 +345,7 @@ } @bus directRam automatic { + @instanceName directRam @wires { INT } diff --git a/examples/simplified FRISC model/schema2.csl b/examples/simplified FRISC model/schema2.csl index 9f26b51..79f0e84 100644 --- a/examples/simplified FRISC model/schema2.csl +++ b/examples/simplified FRISC model/schema2.csl @@ -1,7 +1,7 @@ @source "frisc_library.csl" @schema { - @instance proc FRISC { + @instance procesor_002 FRISC { @position (0, 0) @attribute _memory null } @@ -15,11 +15,28 @@ @attribute pocetnaAdresa 1024 } + @instance procesor_001 FRISC { + @position (-89, 74) + @attribute _memory null + } + + @instance procesor_000 FRISC { + @position (-175, 195) + @attribute _memory null + } + + @instance procesor FRISC { + @position (-195, 63) + @attribute _memory null + } + @instance bus glavnaSabirnica { @position (0, 200) @size 100 } + @connection (procesor_002.glavniPin, bus) { + } @connection (mem.glavniPin, bus) { } }