#include "comdelgenerator.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()); } 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; } ComdelGenerator::ComdelGenerator(std::vector signatures) : signatures(signatures) {} std::optional ComdelGenerator::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 ComdelGenerator::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 ComdelGenerator::loadAddressSpace(AddressSpaceNode node) { return AddressSpace(node.name.value, node.start.value, node.end.value); } std::optional ComdelGenerator::loadConnection(ConnectionNode node) { push(ComdelContext("connection", false, true, false)); std::string component = node.component.value; std::string pin = node.pin.value; std::string bus = node.bus.value; auto componentInstance = getComponentPin(component, pin); if(!componentInstance) { errors.push_back(SourceError(node.span, "pin does not exist")); } auto busInstance = getBus(bus); if(!busInstance) { errors.push_back(SourceError(node.span, "bus 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(uint i=0; i attributeNames; for(auto attribute: attributes) { attributeNames.insert(attribute.getName()); } std::vector wires; for(uint i=0; i ComdelGenerator::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 ComdelGenerator::loadWire(WireNode node) { return Wire( node.name.value, toType(node.type), node.size.value, node.hidden, node.hasTermination, node.isUnterminated ); } optional ComdelGenerator::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); return Pin(name, type, tooltip, connection, *display); } 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 ComdelGenerator::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, "unsuported display type"}); } items.push_back(displayItem); } return Display(items); } PinConnection ComdelGenerator::loadPinConnection(PinConnectionNode node) { std::string message = node.message.asString(); PinConnection::ConnectionType type = toType(node.type); return PinConnection(message, type); } std::optional ComdelGenerator::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 ComdelGenerator::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 ComdelGenerator::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 ComdelGenerator::loadCondition(ConditionNode node) { std::string function = node.functionName.value; for(uint i=0; i params; for(uint j=0; j ComdelGenerator::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 component = dynamic_cast(schema.getInstance(conn.instance.value)); if(component == NULL) { errors.push_back(SourceError{conn.instance.span, "unknown component"}); continue; } if(!component->component.hasPin(conn.pin.value)) { errors.push_back(SourceError{conn.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; } if(!library.hasConnection(component->component.getName(), conn.pin.value, bus->bus.getName())) { errors.push_back(SourceError{conn.span, "unknown connection"}); continue; } auto connection = *library.getConnection(component->component.getName(), conn.pin.value, bus->bus.getName()); 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")); } } schema.connections.push_back(new BusConnectionInstance(component, attributes, bus, wire, connection)); } return schema; } ComponentInstance *ComdelGenerator::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 *ComdelGenerator::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 ComdelGenerator::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