#include "schemacreator.h" #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::WIRE: return Value::WIRE_REFERENCE; case ValueNode::STRING: return Value::STRING; case ValueNode::INT: return Value::INT; default: return Value::UNDEFINED; } } Value toType(ValueNode node) { 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; } 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::AUTOMATICALLY) { return PinConnection::AUTOMATICALLY; } return PinConnection::CHECK_ONLY; } Popup::PopupType toType(PopupNode::PopupType type) { if(type == PopupNode::AUTOMATIC) { return Popup::AUTOMATIC; } return Popup::ON_DEMAND; } SchemaCreator::SchemaCreator(std::vector signatures) : signatures(signatures) {} std::optional SchemaCreator::loadLibrary(LibraryNode node) { // library fields if(!node.name) { errors.push_back(SourceError{node.span, "missing @name"}); return nullopt; } else { name = node.name->asString(); } if(!node.componentDirectory) { errors.push_back(SourceError{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(uint i=0; i 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.push_back(SourceError{node.count->span, "invalid @size"}); return nullopt; } auto type = toType(node.type); if(!node.tooltip && type == Bus::REGULAR) { errors.push_back(SourceError{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"}); return nullopt; } if(node.display && (type == Bus::AUTOMATIC || type == Bus::AUTOMATIC_SINGLE)) { errors.push_back(SourceError{node.span, "automatic bus cannot have a @display"}); return nullopt; } optional display; if(type == Bus::REGULAR) { display = loadDisplay(*node.display); if(!display) { return nullopt; } } if(node.wires.size() == 0) { errors.push_back(SourceError{node.span, "missing @wires"}); return nullopt; } std::vector wires; for(auto& _wire: node.wires) { auto wire = loadWire(_wire); if(wire) { wires.push_back(*wire); } } return Bus(name, tooltip, type, count, wires, display); } 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)); 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::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::AUTOMATIC_SINGLE) { 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()); } 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::IDENTIFIER)) { 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, "unknown 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::IDENTIFIER)) { 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, "unknown value type"); } } 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)); std::string name = node.name.value; if(!node.tooltip) { errors.push_back(SourceError{node.span, "missing @tooltip"}); pop(); return nullopt; } std::string tooltip = node.tooltip->asString(); if(!node.source) { errors.push_back(SourceError{node.span, "missing @source"}); pop(); return nullopt; } std::string source = node.source->asString(); Component::ComponentType type = toType(node.type); std::vector attributes; for(auto& a: node.attributes) { std::optional attribute = loadAttribute(a); if(attribute) { attributes.push_back(*attribute); } } 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.push_back(SourceError{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.push_back(SourceError{node.count->first.span, "invalid @size"}); pop(); return nullopt; } if(!node.display) { errors.push_back(SourceError{node.span, "missing @display"}); pop(); return nullopt; } optional display = loadDisplay(*node.display); if(!display) { pop(); return nullopt; } std::vector pins; for(uint i=0; i SchemaCreator::loadWire(WireNode node) { return Wire( node.name.value, toType(node.type), node.size.value, node.hidden, node.hasTermination, node.isUnterminated ); } optional SchemaCreator::loadPin(PinNode node) { std::string name = node.name.value; Pin::PinType type = toType(node.type); if(!node.tooltip) { errors.push_back(SourceError{node.span, "missing @tooltip"}); return nullopt; } std::string tooltip = node.tooltip->asString(); if(!node.display) { errors.push_back(SourceError{node.span, "missing @display"}); return nullopt; } std::vector attributes; optional display = loadDisplay(*node.display); if(!display) { return nullopt; } if(!node.connection) { errors.push_back(SourceError{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, *display, wiresOpt); } int getIntProperty(DisplayItemNode &node, std::string property) { for(auto& prop: node.values) { if(prop.key.value == property) { return prop.value.asInt(); } } throw std::exception(); } 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") { int x, y, w, h; x = getIntProperty(item, "x"); y = getIntProperty(item, "y"); w = getIntProperty(item, "w"); h = getIntProperty(item, "h"); displayItem.rect = ui::Rect(x, y, w, h); } else if(type == "line") { int x1, y1, x2, y2; x1 = getIntProperty(item, "x1"); y1 = getIntProperty(item, "y1"); x2 = getIntProperty(item, "x2"); y2 = getIntProperty(item, "y2"); displayItem.line = ui::Line(x1, y1, x2, y2); } else if(type == "pin") { int x, y, w, h; x = getIntProperty(item, "x"); y = getIntProperty(item, "y"); w = getIntProperty(item, "w"); h = getIntProperty(item, "h"); displayItem.pin = ui::Pin(x, y, w, h); } else { errors.push_back(SourceError{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); return PinConnection(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.push_back(SourceError{node.name.span, "unsupported type"}); } } if(current().inConnection) { // 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"}); } } else { errors.push_back(SourceError{node.name.span, "unsupported type"}); } } current().attributes.push_back(Attribute(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); pushAdditional(name); current().attributes.clear(); current().attributes.push_back(Attribute(name, Value::ofType(type))); if(!node.title) { errors.push_back(SourceError{node.span, "missing @title"}); return nullopt; } std::string title = node.title->asString(); if(!node.text) { errors.push_back(SourceError{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(uint i=0; i SchemaCreator::loadRule(RuleNode node) { std::vector statements; for(auto& stmt: node.statements) { auto condition = loadCondition(stmt.condition); if(condition) { statements.push_back(IfStatement(*condition, Action(toType(stmt.action.type), stmt.action.message.asString()))); } else { return nullopt; } } return Rule(statements); } std::optional SchemaCreator::loadCondition(ConditionNode node) { std::string function = node.functionName.value; for(uint i=0; i params; for(uint j=0; j SchemaCreator::loadSchema(SchemaNode node, Library &library) { Schema schema; for(auto &instance: node.instances) { if(library.hasComponent(instance.component.value)) { schema.instances.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); } } for(auto &conn: node.connections) { auto firstComponent = dynamic_cast(schema.getInstance(conn.first.instance.value)); if(firstComponent == NULL) { errors.push_back(SourceError{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"}); continue; } ComponentInstance *secondComponent = NULL; if(conn.second.has_value()) { secondComponent = dynamic_cast(schema.getInstance(conn.second->instance.value)); if(secondComponent == NULL) { errors.push_back(SourceError{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"}); continue; } } auto bus = dynamic_cast(schema.getInstance(conn.bus.value)); if(bus == NULL) { errors.push_back(SourceError{conn.bus.span, "unknown bus"}); continue; } std::optional connection = std::nullopt; if(secondComponent != NULL) { 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.push_back(SourceError{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.push_back(SourceError{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 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.push_back(SourceError{attr.span, "invalid value"}); } attributes.push_back(new InstanceAttribute(attribute.getName(), toType(attr.value), attribute)); } else { errors.push_back(SourceError(attr.name.span, "unknown attribute")); } } if(secondComponent == NULL) { schema.connections.push_back(new BusConnectionInstance(firstComponent, attributes, bus, wire, *connection)); } else { schema.connections.push_back(new DirectConnectionInstance(firstComponent, secondComponent, attributes, bus, wire, *connection)); } } return schema; } 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); 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.push_back(new InstanceAttribute(attribute.getName(), toType(attr.value), attribute)); } else { errors.push_back(SourceError(attr.name.span, "unknown attribute")); } } return new ComponentInstance(name, attributes, position, component); } 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); auto bus = library.getBus(instance.component.value); long long size = 0; if(instance.size) { size = instance.size->value; } return new BusInstance(name, position, bus, size); } std::optional SchemaCreator::loadWireInstance(WireInstanceNode node) { if(!node.display) { errors.push_back(SourceError{node.span, "missing @text"}); return nullopt; } auto display = loadDisplay(*node.display); if(!display) { return nullopt; } std::pair position = std::make_pair(0, 0); if(node.position) { position = std::make_pair(node.position->first.value, node.position->second.value); } return std::optional(new WireInstance(node.name.value, *display, position)); } } // namespace domain