#include "schemacreator.h" #include #include namespace domain { Component::ComponentType toType(ComponentNode::ComponentType type) { if(type == ComponentNode::MEMORY) { return Component::MEMORY; } else if(type == ComponentNode::PROCESSOR) { return Component::PROCESSOR; } return Component::OTHER; } Action::ActionType toType(ActionNode::ActionType type) { if(type == ActionNode::ERROR) { return Action::ERROR; } return Action::WARNING; } Wire::WireType toType(WireNode::WireType type) { switch (type) { case WireNode::R_WIRE: return Wire::R_WIRE; case WireNode::WIRE: return Wire::WIRE_DEFAULT; case WireNode::WIRED_AND: return Wire::WIRED_AND; case WireNode::WIRED_OR: return Wire::WIRED_OR; default: return Wire::WIRE_DEFAULT; } } 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::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) { return Value::fromInt(node.asInt()); } else if(node.getType() == ValueNode::STRING) { return Value::fromString(node.asString()); } else if(node.getType() == ValueNode::NIL) { return Value::fromNull(); } return Value::fromReference(node.asIdentifier(), Value::UNDEFINED); } 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; } Pin::PinType toType(PinNode::PinType type) { if(type == PinNode::IN) { return Pin::IN; } else if(type == PinNode::OUT) { return Pin::OUT; } return Pin::IN_OUT; } PinConnection::ConnectionType toType(PinConnectionNode::ConnectionType type) { if(type == PinConnectionNode::OPTIONAL) { return PinConnection::OPTIONAL; } return PinConnection::REQUIRED; } Popup::PopupType toType(PopupNode::PopupType type) { if(type == PopupNode::AUTOMATIC) { return Popup::AUTOMATIC; } return Popup::ON_DEMAND; } SchemaCreator::SchemaCreator(std::vector validators) : validators(std::move(validators)) {} std::optional SchemaCreator::loadLibrary(LibraryNode node) { // library fields if(!node.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.emplace_back(node.span, "missing @componentDirectory"); return nullopt; } else { componentDirectory = node.componentDirectory->asString(); } header = node.header ? node.header->asString() : ""; libraryInfo = node.libraryInfo ? node.libraryInfo->asString() : ""; for(auto& as: node.addressSpaces) { addressSpaces.push_back(*loadAddressSpace(as)); } for(auto& comp: node.components) { std::optional component; component = loadComponent(comp); if(component) { components.push_back(*component); } } for(auto& buse : node.buses) { auto bus = loadBus(buse); if(bus) { buses.push_back(*bus); } } for(auto& connection : node.connections) { auto conn = loadConnection(connection); if(conn) { connections.push_back(*conn); } } for(auto & message : node.messages) { if(!message.value.is(ValueNode::STRING)) { errors.emplace_back(message.value.span, "expected `string`"); } else { messages[message.key.value] = message.value.asString(); } } return Library(name, libraryInfo, header, componentDirectory, componentHeader, addressSpaces, components, buses, connections, messages); } std::optional SchemaCreator::loadBus(BusNode node) { std::string name = node.name.value; auto count = std::make_pair(1, 1); if(node.count) { count = std::make_pair(node.count->first.value, node.count->second.value); } if(count.first > count.second || count.first < 0) { errors.emplace_back(node.count->span, "invalid @size"); return nullopt; } auto type = toType(node.type.value); if(!node.tooltip && type == Bus::REGULAR) { errors.emplace_back(node.span, "missing @tooltip"); return nullopt; } std::string tooltip = node.tooltip->asString(); if(!node.display && type == Bus::REGULAR) { errors.emplace_back(node.span, "missing @display"); return nullopt; } if(node.display && (type == Bus::AUTOMATIC || type == Bus::SINGLE_AUTOMATIC)) { errors.emplace_back(node.span, "automatic bus cannot have a @display"); return nullopt; } optional displayBus; if(type == Bus::REGULAR) { auto display = loadDisplay(*node.display); if(!display) { return nullopt; } if(display->getItems().size() != 1 || !display->getItems()[0].bus.has_value()) { errors.emplace_back(node.span, "@display must contain only exactly one bus definition"); return nullopt; } displayBus = *display->getItems()[0].bus; } if(node.wires.size() == 0) { errors.emplace_back(node.span, "missing @wires"); return nullopt; } std::vector wires; for(auto& _wire: node.wires) { auto wire = loadWire(_wire); if(wire) { wires.push_back(*wire); } } 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, displayBus); } std::optional SchemaCreator::loadAddressSpace(AddressSpaceNode node) { return AddressSpace(node.name.value, node.start.value, node.end.value); } std::optional SchemaCreator::loadConnection(ConnectionNode node) { push(ComdelContext("connection", false, true, false, false)); std::string bus = node.bus.value; auto busInstance = getBus(bus); if(!busInstance) { 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}; auto componentInstance = getComponentPin(first.component, first.pin); if(!componentInstance) { errors.emplace_back(node.span, "pin does not exist"); } if(node.second.has_value()) { errors.emplace_back(node.span, "regular bus doesn't allow direct connections"); } std::set wireNames; for(auto &wire: busInstance->getWires()) { wireNames.insert(wire.getName()); current().wires.push_back(wire.getName()); } std::vector attributes; for(auto & attribute : node.attributes) { auto attr = loadAttribute(attribute); if(!attr) { return nullopt; } attributes.push_back(*attr); } std::set attributeNames; for(auto attribute: attributes) { attributeNames.insert(attribute.getName()); } std::vector wires; for(auto & firstWire : node.firstWires) { if(firstWire.is(ValueNode::NIL)) { wires.push_back(Value::fromNull()); } else if(firstWire.is(ValueNode::INT)) { wires.push_back(Value::fromInt(firstWire.asInt())); } else if(firstWire.is(ValueNode::IDENTIFIER)) { if(attributeNames.count(firstWire.asIdentifier())) { wires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::ATTRIBUTE_REFERENCE)); } else if(wireNames.count(firstWire.asIdentifier())) { wires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::WIRE_REFERENCE)); } else { errors.emplace_back(firstWire.span, "unknown identifier"); } } else { errors.emplace_back(firstWire.span, "unknown value type"); } } pop(); return Connection(first, nullopt, bus, attributes, wires, nullopt); } 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()) { errors.emplace_back(node.span, "missing second component"); } ConnectionComponent second{node.second->component.value, node.second->pin.value}; auto firstComponentInstance = getComponentPin(first.component, first.pin); if(!firstComponentInstance) { errors.emplace_back(node.span, "pin does not exist"); } auto secondComponentInstance = getComponentPin(second.component, second.pin); if(!secondComponentInstance) { errors.emplace_back(node.span, "pin does not exist"); } std::set wireNames; for(auto &wire: busInstance->getWires()) { wireNames.insert(wire.getName()); 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 attributes; for(auto & attribute : node.attributes) { auto attr = loadAttribute(attribute); if(!attr) { return nullopt; } attributes.push_back(*attr); } std::set attributeNames; for(auto attribute: attributes) { attributeNames.insert(attribute.getName()); } std::vector firstWires; for(auto & firstWire : node.firstWires) { if(firstWire.is(ValueNode::NIL)) { firstWires.push_back(Value::fromNull()); } else if(firstWire.is(ValueNode::INT)) { firstWires.push_back(Value::fromInt(firstWire.asInt())); } 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())) { firstWires.push_back(Value::fromReference(firstWire.asIdentifier(), Value::WIRE_REFERENCE)); } else { errors.emplace_back(firstWire.span, "unknown identifier"); } } else { errors.emplace_back(firstWire.span, "unsupported value type"); } } std::vector secondWires; for(auto & secondWire : *node.secondWires) { if(secondWire.is(ValueNode::NIL)) { secondWires.push_back(Value::fromNull()); } else if(secondWire.is(ValueNode::INT)) { secondWires.push_back(Value::fromInt(secondWire.asInt())); } 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())) { secondWires.push_back(Value::fromReference(secondWire.asIdentifier(), Value::WIRE_REFERENCE)); } else { errors.emplace_back(secondWire.span, "unknown identifier"); } } else { 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)); } } pop(); return Connection(first, second, bus, attributes, firstWires, secondWires); } pop(); errors.emplace_back(node.span, "unsupported connection type"); return std::nullopt; } std::optional SchemaCreator::loadComponent(ComponentNode node) { push(ComdelContext(node.name.value, true, false, false, false)); std::string name = node.name.value; if(!node.tooltip) { errors.emplace_back(node.span, "missing @tooltip"); pop(); return nullopt; } std::string tooltip = node.tooltip->asString(); if(!node.source) { errors.emplace_back(node.span, "missing @source"); pop(); return nullopt; } std::string source = node.source->asString(); Component::ComponentType type = toType(node.type.value); std::vector attributes; for(auto& a: node.attributes) { std::optional attribute = loadAttribute(a); if(attribute) { attributes.push_back(*attribute); } } if(type == Component::PROCESSOR) { attributes.push_back(*createMemoryAttribute()); } context[context.size() -1 ].attributes = attributes; std::vector rules; for(auto& r: node.rules) { std::optional rule = loadRule(r); if(rule) { rules.push_back(*rule); } } if(!node.instanceName) { errors.emplace_back(node.span, "missing @instanceName"); pop(); return nullopt; } std::string instanceName = node.instanceName->asString(); auto count = std::make_pair(1, 1); if(node.count) { count = std::make_pair(node.count->first.value, node.count->second.value); } if(count.first > count.second || count.first < 0) { errors.emplace_back(node.count->first.span, "invalid @size"); pop(); return nullopt; } if(!node.display) { errors.emplace_back(node.span, "missing @display"); pop(); return nullopt; } optional display = loadDisplay(*node.display); if(!display) { pop(); return nullopt; } std::vector pins; for(auto &p : node.pins) { auto pin = loadPin(p); if(!pin) { pop(); return nullopt; } pins.push_back(*pin); } pop(); return Component(name, tooltip, source, type, rules, instanceName, count, *display, pins, attributes); } std::optional SchemaCreator::loadWire(WireNode node) { return Wire( node.name.value, toType(node.type.value), node.size.value, node.hidden, node.hasTerminateWith, toType(node.terminateWith) ); } optional SchemaCreator::loadPin(PinNode node) { std::string name = node.name.value; Pin::PinType type = toType(node.type.value); if(!node.tooltip) { errors.emplace_back(node.span, "missing @tooltip"); return nullopt; } std::string tooltip = node.tooltip->asString(); if(!node.display) { errors.emplace_back(node.span, "missing @display"); return nullopt; } std::vector attributes; optional display = loadDisplay(*node.display); if(!display) { return nullopt; } if(display->getItems().size() != 1 || !display->getItems()[0].pin.has_value()) { errors.emplace_back(node.span, "@display must contain only exactly one pin definition"); return nullopt; } ui::Pin displayPin = *display->getItems()[0].pin; if(!node.connection) { errors.emplace_back(node.span, "missing @connection"); return nullopt; } auto connection = loadPinConnection(*node.connection); std::optional> wiresOpt = std::nullopt; if(node.wires.has_value()) { auto nodeWires = node.wires.value(); std::vector wires; for(auto &nodeWire : nodeWires) { if(nodeWire.is(ValueNode::NIL)) { wires.push_back(Value::fromNull()); } else if(nodeWire.is(ValueNode::INT)) { wires.push_back(Value::fromInt(nodeWire.asInt())); } else { errors.emplace_back(node.span, "unknown value type"); } } wiresOpt = wires; } return Pin(name, type, tooltip, connection, displayPin, wiresOpt); } std::optional SchemaCreator::loadDisplay(DisplayNode node) { std::vector items; for(auto &item: node.items) { ui::Item displayItem; std::string type = item.type.value; if(type == "rect") { long long int x, y, w, h; x = item.asInt(&errors, "x"); y = item.asInt(&errors, "y"); w = item.asInt(&errors, "w"); h = item.asInt(&errors, "h"); displayItem.rect = ui::Rect(x, y, w, h); } else if(type == "line") { long long int x1, y1, x2, y2; x1 = item.asInt(&errors, "x1"); y1 = item.asInt(&errors, "y1"); x2 = item.asInt(&errors, "x2"); y2 = item.asInt(&errors, "y2"); displayItem.line = ui::Line(x1, y1, x2, y2); } else if(type == "pin") { long long int x, y, w, h; x = item.asInt(&errors, "x"); y = item.asInt(&errors, "y"); w = item.asInt(&errors, "w"); h = item.asInt(&errors, "h"); std::string _orientation = item.asString(&errors, "orientation", "bottom"); std::string _pinType = item.asString(&errors, "type", "out"); ui::PinOrientation orientation; if(_orientation == "left") { orientation = ui::PinOrientation::LEFT; } else if(_orientation == "right") { orientation = ui::PinOrientation::RIGHT; } else if(_orientation == "top") { orientation = ui::PinOrientation::TOP; } else if(_orientation == "bottom") { orientation = ui::PinOrientation::BOTTOM; } else { errors.emplace_back(item.span, "unknown pin orientation type '" + _orientation + "'"); } ui::PinType pinType; if(_pinType == "in") { pinType = ui::PinType::IN; } else if(_pinType == "out") { pinType = ui::PinType::OUT; } else if(_pinType == "in_out") { pinType = ui::PinType::IN_OUT; } else { errors.emplace_back(item.span, "unknown pin type '" + _pinType + "'"); } displayItem.pin = ui::Pin(x, y, w, h, orientation, pinType); } else if(type == "bus") { long long int x, y, w, h; x = item.asInt(&errors, "x"); y = item.asInt(&errors, "y"); w = item.asInt(&errors, "w"); h = item.asInt(&errors, "h"); std::string _orientation = item.asString(&errors, "orientation", "bottom"); ui::BusOrientation orientation; if(_orientation == "horizontal") { orientation = ui::BusOrientation::HORIZONTAL; } else if(_orientation == "vertical") { orientation = ui::BusOrientation::VERTICAL; } else { errors.emplace_back(item.span, "unknown bus orientation type '" + _orientation + "'"); } displayItem.bus = ui::Bus(x, y, w, h, orientation); } else { errors.emplace_back(item.type.span, "unsupported display type"); } items.push_back(displayItem); } return Display(items); } PinConnection SchemaCreator::loadPinConnection(PinConnectionNode node) { std::string message = node.message.asString(); PinConnection::ConnectionType type = toType(node.type.value); return {message, type}; } std::optional SchemaCreator::loadAttribute(AttributeNode node) { std::string name = node.name.value; pushAdditional(name); Value value; if(current().inComponent) { if(node.type == ValueNode::INT) { value = Value::fromInt(node.defaultValue->asInt()); } else if (node.type == ValueNode::BOOL) { value = Value::fromBool(node.defaultValue->asBool()); } else if (node.type == ValueNode::STRING) { value = Value::fromString(node.defaultValue->asString()); } else { errors.emplace_back(node.name.span, "unsupported type"); } } 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.emplace_back(node.span, "unknown identifier"); } } else { 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.emplace_back(name, value); std::optional popup; if(node.popup) { popup = loadPopup(*node.popup, name, value.getType()); } pop(); return Attribute(name, value, popup); } std::optional SchemaCreator::loadPopup(PopupNode node, std::string name, Value::ValueType type) { auto popupType = toType(node.type.value().value); pushAdditional(name); current().attributes.clear(); current().attributes.emplace_back(name, Value::ofType(type)); if(!node.title) { errors.emplace_back(node.span, "missing @title"); return nullopt; } std::string title = node.title->asString(); if(!node.text) { errors.emplace_back(node.span, "missing @text"); return nullopt; } std::string text = node.text->asString(); std::vector rules; for(auto& r: node.rules) { std::optional rule = loadRule(r); if(rule) { rules.push_back(*rule); } } std::vector enumeration; if(node.enumerated) { for(auto& enumNode : node.enumeration) { if(type == Value::INT || type == Value::STRING || type == Value::BOOL) { auto value = toType(enumNode.value); if(value.getType() == type) { enumeration.emplace_back(enumNode.key.asString(), value); } else { errors.emplace_back(enumNode.span, "wrong type"); } } else if(type == Value::WIRE_REFERENCE) { 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.emplace_back(enumNode.span, "unknown wire"); } } if(value.isType(Value::WIRE_REFERENCE) || value.isType(Value::INT) || value.isType(Value::NIL)) { enumeration.emplace_back(enumNode.key.asString(), value); } else { errors.emplace_back(enumNode.span, "wrong type"); } } } } else { if(type == Value::WIRE_REFERENCE && !current().inConnection) { errors.emplace_back(node.span, "@enumeration is required for attributes of type wire"); } } pop(); return Popup(title, text, popupType, rules, enumeration); } std::optional SchemaCreator::loadRule(RuleNode node) { std::vector statements; for(auto& stmt: node.statements) { auto condition = loadCondition(stmt.condition); if(condition) { statements.emplace_back(*condition, Action(toType(stmt.action.type.value), stmt.action.message.asString())); } else { return nullopt; } } return Rule(statements); } std::optional SchemaCreator::loadCondition(ConditionNode node) { std::string function = node.functionName.value; for(auto & validator : validators) { if(validator->getName() == function) { if(validator->getSignature().size() == node.params.size()) { std::vector params; for(uint j=0; jgetSignature().size(); j++) { bool exists = false; auto type = toType(node.params[j]); if (type.getType() == Value::UNDEFINED) { if(current().doesAttributeExists(type.asReference(), validator->getSignature()[j])) { exists = true; type = Value::fromReference(type.asReference(), Value::ATTRIBUTE_REFERENCE); } if(validator->getSignature()[j] == Value::ADDRESS_SPACE) { if(hasAddressSpace(type.asReference())) { exists = true; type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE_REFERENCE); } } if(!exists) { errors.emplace_back(node.functionName.span, "unknown reference " + type.asReference()); } } params.push_back(type); } return Condition(function, params, node.negated); } else { errors.emplace_back(node.functionName.span, "wrong number of parameters"); } } } errors.emplace_back(node.functionName.span, "unknown function name"); return nullopt; } Schema* SchemaCreator::loadSchema(SchemaNode node, Library &library) { auto *schema = new Schema(); for(auto &instance: node.instances) { if(library.hasComponent(instance.component.value)) { schema->componentInstances.push_back(loadComponentInstance(instance, library)); } if(library.hasBus(instance.component.value)) { schema->busInstances.push_back(loadBusInstance(instance, library)); } } for(auto &conn: node.connections) { 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.emplace_back(conn.first.pin.span, "unknown pin"); continue; } ComponentInstance *secondComponent = nullptr; if(conn.second.has_value()) { 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.emplace_back(conn.second->pin.span, "unknown pin"); continue; } } auto bus = schema->getBusInstance(conn.bus.value); if(bus == nullptr) { errors.emplace_back(conn.bus.span, "unknown bus"); continue; } std::optional connection = std::nullopt; if(secondComponent != nullptr) { ConnectionComponent firstConn{firstComponent->component.getName(), conn.first.pin.value}; ConnectionComponent secondConn{secondComponent->component.getName(), conn.second->pin.value}; if(library.hasConnection(firstConn, bus->bus.getName(), secondConn)) { connection = *library.getConnection(firstConn, bus->bus.getName(), secondConn); } else { errors.emplace_back(conn.span, "unknown connection"); continue; } } else { ConnectionComponent firstConn{firstComponent->component.getName(), conn.first.pin.value}; if(library.hasConnection(firstConn, bus->bus.getName())) { connection = *library.getConnection(firstConn, bus->bus.getName()); } else { errors.emplace_back(conn.span, "unknown connection"); continue; } } std::vector attributes; for(auto& attr: conn.attributes) { if(connection->hasAttribute(attr.name.value)) { auto attribute = connection->getAttribute(attr.name.value); auto value = toType(attr.value); for(auto& en: attribute.getPopup()->getEnumeration()) { if(en.getValue().asReference() == value.asReference()) { value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE); } } if(value.isType(Value::UNDEFINED)) { errors.emplace_back(attr.span, "invalid value"); } attributes.emplace_back(attribute.getName(), toType(attr.value), attribute); } else { errors.emplace_back(attr.name.span, "unknown attribute"); } } if(secondComponent == nullptr) { schema->connections.push_back(std::make_shared(firstComponent, attributes, bus, *connection)); } else { schema->connections.push_back(std::make_shared(firstComponent, secondComponent, attributes, bus, *connection)); } } return schema; } shared_ptr SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) { auto name = instance.name.value; auto position = std::make_pair(instance.position->first.value, instance.position->second.value); auto component = library.getComponent(instance.component.value); // validate attributes std::vector attributes; for(auto& attr: instance.attributes) { if(component.hasAttribute(attr.name.value, toType(attr.value.getType()))) { auto attribute = component.getAttribute(attr.name.value); attributes.emplace_back(attribute.getName(), toType(attr.value, attribute.getDefault().getType()), attribute); } else { errors.emplace_back(SourceError(attr.name.span, "unknown attribute")); } } 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(name, attributes, position, component); } std::shared_ptr SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) { auto name = instance.name.value; auto position = std::make_pair(instance.position->first.value, instance.position->second.value); auto bus = library.getBus(instance.component.value); long long size = 0; if(instance.size) { size = instance.size->value; } return std::make_shared(name, position, bus, static_cast(size)); } vector SchemaCreator::createWireEnumeration(vector wireValues) { vector wires; for(auto& wire: wireValues) { if(wire.isType(Value::STRING)) { wires.emplace_back(wire.asString(), wire); } } return wires; } std::optional SchemaCreator::createMemoryAttribute() { return Attribute("_memory", Value::fromMemoryReference(std::nullopt), createMemoryPopup()); } std::optional SchemaCreator::createMemoryPopup() { return Popup("Postavi memoriju", "Postavi memoriju za izabrani procesor", Popup::AUTOMATIC, vector{}, vector{}); } } // namespace domain