#include "schema_creator.h" #include #include namespace domain { ComdelContext::ComdelContext(std::string name, bool inComponent, bool inConnection, bool inSingleAutomaticConnection, bool inBus) : name(std::move(name)), inComponent(inComponent), inConnection(inConnection), inSingleAutomaticConnection(inSingleAutomaticConnection), inBus(inBus) {} bool ComdelContext::doesAttributeExists(std::string name, Value::ValueType type) { for (auto &attribute: attributes) { if (attribute.getDefault().getType() == type && attribute.getName() == name) { return true; } } return false; } bool ComdelContext::doesWireExists(std::string name) { for (auto &w: wires) { if (w == name) { return true; } } return false; } 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.is(ValueNode::NIL)) { return Value::fromMemoryReference(nullopt); } else { return Value::fromMemoryReference(node.asIdentifier()); } } if (node.is(ValueNode::BOOL)) { return Value::fromBool(node.asBool()); } else if (node.is(ValueNode::INT)) { return Value::fromInt(node.asInt()); } else if (node.is(ValueNode::STRING)) { return Value::fromString(node.asString()); } else if (node.is(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; } 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) { auto 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(); } } 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); } 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.empty()) { 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(busName, instanceName, tooltip, type, count, wires, displayBus); } std::optional SchemaCreator::loadAddressSpace(AddressSpaceNode node) { return AddressSpace(node.name.value, node.range.first.value, node.range.second.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 { domain::Popup popup = *attributes[0].getPopup(); popup.setEnumeration(createWireEnumeration(firstWires)); attributes[0].setPupup(popup); } 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 { domain::Popup popup = *attributes[1].getPopup(); popup.setEnumeration(createWireEnumeration(secondWires)); attributes[1].setPupup(popup); } } 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 componentName = 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->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->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(componentName, 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 pinName = 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; std::optional connection = std::nullopt; if (node.connection) { connection = node.connection->asString(); } 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(pinName, type, tooltip, connection, displayPin, wiresOpt); } Color readColor(std::vector& errors, DisplayItemNode& item, std::string property, Color _default) { auto color = item.asColor(property, _default); if(!color.has_value()) { errors.emplace_back(item.span, "expected color"); return _default; } return *color; } std::string readString(std::vector& errors, DisplayItemNode& item, std::string property, std::string _default = "") { auto value = item.asString(property, _default); if(!value.has_value()) { errors.emplace_back(item.span, "expected string"); return _default; } return *value; } long long int readInt(std::vector& errors, DisplayItemNode& item, std::string property, long long int _default = 0) { auto value = item.asInt(property, _default); if(!value.has_value()) { errors.emplace_back(item.span, "expected int"); return _default; } return *value; } std::optional SchemaCreator::loadDisplay(DisplayNode node) { std::vector items; for (auto &item: node.items) { ui::Item displayItem; std::string type = item.type.value; auto fillColor = readColor(errors, item, "fillColor", Color(255, 255, 255, 255)); auto lineColor = readColor(errors, item, "lineColor", Color(0, 0, 0, 255)); if (type == "text") { long long int x, y, w, h; std::string text; auto color = readColor(errors, item, "color", Color(0, 0, 0, 255)); x = readInt(errors, item, "x"); y = readInt(errors, item, "y"); w = readInt(errors, item, "w"); h = readInt(errors, item, "h"); text = readString(errors, item, "text"); displayItem.text = ui::Text(x, y, w, h, text, color); } else if (type == "rect") { long long int x, y, w, h; x = readInt(errors, item, "x"); y = readInt(errors, item, "y"); w = readInt(errors, item, "w"); h = readInt(errors, item, "h"); displayItem.rect = ui::Rect(x, y, w, h, {lineColor, fillColor}); } else if (type == "line") { long long int x1, y1, x2, y2; x1 = readInt(errors, item, "x1"); y1 = readInt(errors, item, "y1"); x2 = readInt(errors, item, "x2"); y2 = readInt(errors, item, "y2"); displayItem.line = ui::Line(x1, y1, x2, y2, {lineColor, fillColor}); } else if (type == "pin") { long long int x, y, w, h; x = readInt(errors, item, "x"); y = readInt(errors, item, "y"); w = readInt(errors, item, "w"); h = readInt(errors, item, "h"); std::string _orientation = readString(errors, item, "orientation", "bottom"); std::string _pinType = readString(errors, item, "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, {lineColor, fillColor}); } else if (type == "bus") { long long int x, y, w, h; x = readInt(errors, item, "x"); y = readInt(errors, item, "y"); w = readInt(errors, item, "w"); h = readInt(errors, item, "h"); std::string _orientation = readString(errors, item, "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, {lineColor, fillColor}); } else { errors.emplace_back(item.type.span, "unsupported display type"); } items.push_back(displayItem); } return Display(items); } 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, toType(node.type)); } 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; j < validator->getSignature().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(library); 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); bool valueFound = false; // all connection attributes must be of type enumeration for (auto &en: attribute.getPopup()->getEnumeration()) { if (en.getValue().equals(value)) { valueFound = true; break; } else if(value.isType(Value::UNDEFINED)) { if(en.getValue().isType(Value::WIRE_REFERENCE) && en.getValue().asReference() == value.asReference()) { value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE); valueFound = true; break; } } } if (!valueFound) { errors.emplace_back(attr.span, "invalid value"); } attributes.emplace_back(attribute.getName(), 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)); } } if(errors.empty()) { return schema; } else { delete schema; return nullptr; } } shared_ptr SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) { auto componentInstanceName = 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(componentInstanceName, attributes, position, component); } std::shared_ptr SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) { auto busInstanceName = 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(busInstanceName, 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{}); } std::optional SchemaCreator::getBus(std::string name) { for (auto &bus: buses) { if (bus.getName() == name) { return bus; } } return std::nullopt; } std::optional SchemaCreator::getComponentPin(std::string name, std::string pin) { for (auto &c: components) { if (c.getName() == name) { for (auto &p: c.getPins()) { if (p.getName() == pin) { return p; } } } } return nullopt; } bool SchemaCreator::hasAddressSpace(std::string name) { for (auto &as: addressSpaces) { if (as.getName() == name) { return true; } } return false; } void SchemaCreator::push(ComdelContext context) { this->context.push_back(context); } void SchemaCreator::pushAdditional(std::string name) { if (!this->context.empty()) { this->context.push_back(current()); current().name = name; } else { ComdelContext con(name, false, false, false, false); push(con); } } ComdelContext &SchemaCreator::current() { return this->context[this->context.size() - 1]; } void SchemaCreator::pop() { this->context.pop_back(); } std::vector SchemaCreator::getErrors() { return errors; } } // namespace domain