diff --git a/comdel/domain/comdelgenerator.cpp b/comdel/domain/comdelgenerator.cpp index f42d95b..30f4792 100644 --- a/comdel/domain/comdelgenerator.cpp +++ b/comdel/domain/comdelgenerator.cpp @@ -224,62 +224,151 @@ 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.emplace_back(node.span, "pin does not exist"); - } - auto busInstance = getBus(bus); if(!busInstance) { errors.emplace_back(node.span, "bus does not exist"); } - std::set wireNames; - for(auto &wire: busInstance->getWires()) { - wireNames.insert(wire.getName()); - current().wires.push_back(wire.getName()); - } + if(busInstance->getType() == Bus::REGULAR) { + ConnectionComponent first{node.first.component.value, node.first.pin.value}; - std::vector attributes; - for(uint i=0; i attributeNames; - for(auto attribute: attributes) { - attributeNames.insert(attribute.getName()); - } + if(node.second.has_value()) { + errors.emplace_back(node.span, "regular bus doesn't allow direct connections"); + } - std::vector wires; - for(uint i=0; i 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; } - } else { - errors.emplace_back(node.wires[i].span, "unknown value type"); + 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 Connection(component, pin, bus, attributes, wires); } std::optional ComdelGenerator::loadComponent(ComponentNode node) @@ -659,25 +748,60 @@ std::optional ComdelGenerator::loadSchema(SchemaNode node, Library &libr } 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"}); + 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(!component->component.hasPin(conn.pin.value)) { - errors.push_back(SourceError{conn.pin.span, "unknown pin"}); + 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; } - if(!library.hasConnection(component->component.getName(), conn.pin.value, bus->bus.getName())) { - errors.push_back(SourceError{conn.span, "unknown connection"}); - 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->name, 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; + } } - auto connection = *library.getConnection(component->component.getName(), conn.pin.value, bus->bus.getName()); if(!conn.wire) { errors.push_back(SourceError{conn.span, "missing @wire"}); @@ -692,8 +816,8 @@ std::optional ComdelGenerator::loadSchema(SchemaNode node, Library &libr std::vector attributes; for(auto& attr: conn.attributes) { - if(connection.hasAttribute(attr.name.value)) { - auto attribute = connection.getAttribute(attr.name.value); + if(connection->hasAttribute(attr.name.value)) { + auto attribute = connection->getAttribute(attr.name.value); auto value = toType(attr.value); for(auto& en: attribute.getPopup()->getEnumeration()) { @@ -711,7 +835,11 @@ std::optional ComdelGenerator::loadSchema(SchemaNode node, Library &libr } } - schema.connections.push_back(new BusConnectionInstance(component, attributes, bus, wire, connection)); + 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; diff --git a/comdel/domain/connection.cpp b/comdel/domain/connection.cpp index eb3aaed..08b8611 100644 --- a/comdel/domain/connection.cpp +++ b/comdel/domain/connection.cpp @@ -2,20 +2,19 @@ namespace domain { -Connection::Connection(std::string component, std::string pin, std::string bus, std::vector attributes, std::vector wires) - : component(component), pin(pin), bus(bus), attributes(attributes), wires(wires) +Connection::Connection(ConnectionComponent first, std::optional second, + std::string bus, std::vector attributes, + std::vector firstWires, std::optional> secondWires) + : first(first), second(second), bus(bus), attributes(attributes), firstWires(firstWires), secondWires(secondWires) {} -bool Connection::isConnecting(std::string component, std::string pin, std::string bus) { - return this->component == component && this->pin == pin && this->bus == bus; +ConnectionComponent Connection::getComponent() { + return first; +} +std::optional Connection::getSecondComponent() { + return second; } -std::string Connection::getComponent() { - return component; -} -std::string Connection::getPin() { - return pin; -} std::string Connection::getBus() { return bus; } @@ -24,7 +23,10 @@ std::vector Connection::getAttributes() { return attributes; } std::vector Connection::getWires() { - return wires; + return firstWires; +} +std::optional> Connection::getSecondWires() { + return secondWires; } Attribute Connection::getAttribute(std::string name) { @@ -45,4 +47,20 @@ bool Connection::hasAttribute(std::string name) { return false; } +bool Connection::isConnecting(ConnectionComponent component) { + return first == component || (second.has_value() && *second == component); +} + +bool Connection::isConnecting(ConnectionComponent component, std::string bus) { + return this->bus == bus && (first == component || (second.has_value() && *second == component)); +} + +bool Connection::isConnecting(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { + if(!second.has_value()) { + return false; + } + return (this->first == component && this->bus == bus && this->second == secondComponent) || + (this->first == secondComponent && this->bus == bus && this->second == component); +} + } // namespace domain diff --git a/comdel/domain/connection.h b/comdel/domain/connection.h index edbbe30..362cd5c 100644 --- a/comdel/domain/connection.h +++ b/comdel/domain/connection.h @@ -8,25 +8,49 @@ namespace domain { -class Connection +struct ConnectionComponent { std::string component; std::string pin; + + bool operator==(const ConnectionComponent& rhs) const + { + return (component == rhs.component) && (pin == rhs.pin); + } + bool operator!=(const ConnectionComponent& rhs) const + { + return !operator==(rhs); + } +}; + +class Connection +{ + ConnectionComponent first; + std::optional second; std::string bus; - std::vector attributes; - std::vector wires; + + std::vector firstWires; + std::optional> secondWires; public: - Connection(std::string component, std::string pin, std::string bus, std::vector attributes, std::vector wires); + Connection(ConnectionComponent first, std::optional second, + std::string bus, std::vector attributes, + std::vector firstWires, std::optional> secondWires); - bool isConnecting(std::string component, std::string pin, std::string bus); + bool isConnecting(ConnectionComponent first); + bool isConnecting(ConnectionComponent first, std::string bus); + bool isConnecting(ConnectionComponent first, std::string bus, ConnectionComponent second); + + + ConnectionComponent getComponent(); + std::optional getSecondComponent(); - std::string getComponent(); - std::string getPin(); std::string getBus(); std::vector getAttributes(); + std::vector getWires(); + std::optional> getSecondWires(); Attribute getAttribute(std::string name); bool hasAttribute(std::string name); diff --git a/comdel/domain/library.cpp b/comdel/domain/library.cpp index 2fc524f..2b2a771 100644 --- a/comdel/domain/library.cpp +++ b/comdel/domain/library.cpp @@ -81,16 +81,29 @@ Bus &Library::getBus(std::string bus) { throw std::exception(); } -std::optional Library::getConnection(std::string component, std::string pin, std::string bus) { + +bool Library::hasConnection(ConnectionComponent component, std::string bus) { + return getConnection(component, bus).has_value(); +} +std::optional Library::getConnection(ConnectionComponent component, std::string bus) { for(uint i=0; i Library::getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) { + for(uint i=0; i getMessages(); AddressSpace &getAddressSpace(std::string name); Component &getComponent(std::string name); Bus &getBus(std::string bus); - std::optional getConnection(std::string component, std::string pin, std::string bus); std::string getMessage(std::string key); + bool hasConnection(ConnectionComponent component, std::string bus); + std::optional getConnection(ConnectionComponent component, std::string bus); - + bool hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent); + std::optional getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent); }; } // namespace domain diff --git a/comdel/parser/astnode.h b/comdel/parser/astnode.h index 619fb9f..80a718d 100644 --- a/comdel/parser/astnode.h +++ b/comdel/parser/astnode.h @@ -170,7 +170,7 @@ struct ConditionNode std::vector params; }; -class ActionNode: AstNode { +class ActionNode: public AstNode { public: enum ActionType { ERROR, @@ -182,27 +182,27 @@ public: }; -struct IfStatementNode: AstNode +struct IfStatementNode: public AstNode { ConditionNode condition; ActionNode action; }; -struct RuleNode: AstNode +struct RuleNode: public AstNode { std::vector statements; }; -struct EnumerationNode: AstNode +struct EnumerationNode: public AstNode { StringNode key; ValueNode value; }; -struct PopupNode: AstNode +struct PopupNode: public AstNode { enum PopupType { AUTOMATIC, @@ -226,20 +226,20 @@ struct PropertyNode: public AstNode }; -struct DisplayItemNode: AstNode +struct DisplayItemNode: public AstNode { IdentifierNode type; std::vector values; }; -struct DisplayNode: AstNode +struct DisplayNode: public AstNode { std::vector items; }; -struct PinConnectionNode: AstNode +struct PinConnectionNode: public AstNode { enum ConnectionType { CHECK_ONLY, @@ -251,7 +251,7 @@ struct PinConnectionNode: AstNode }; -struct PinNode: AstNode +struct PinNode: public AstNode { enum PinType { IN_OUT, @@ -287,7 +287,7 @@ struct WireNode: public AstNode }; -struct AttributeNode: AstNode +struct AttributeNode: public AstNode { ValueNode::ValueType type; IdentifierNode name; @@ -295,17 +295,25 @@ struct AttributeNode: AstNode std::optional popup; }; -struct ConnectionNode: AstNode +struct ConnectionComponentNode: public AstNode { IdentifierNode component; IdentifierNode pin; - IdentifierNode bus; - std::vector attributes; - std::vector wires; }; +struct ConnectionNode: public AstNode +{ + ConnectionComponentNode first; + std::optional second; -struct ComponentNode: AstNode + IdentifierNode bus; + std::vector attributes; + + std::vector firstWires; + std::optional> secondWires; +}; + +struct ComponentNode: public AstNode { enum ComponentType { OTHER, @@ -326,7 +334,7 @@ struct ComponentNode: AstNode }; -struct BusNode: AstNode +struct BusNode: public AstNode { enum BusType { AUTOMATIC, @@ -342,7 +350,7 @@ struct BusNode: AstNode std::vector wires; }; -struct LibraryNode: AstNode +struct LibraryNode: public AstNode { std::optional name; std::optional libraryInfo; @@ -361,20 +369,20 @@ struct LibraryNode: AstNode // SCHEMA models -struct WireInstanceNode: AstNode +struct WireInstanceNode: public AstNode { IdentifierNode name; std::optional position; std::optional display; }; -struct InstanceAttributeNode: AstNode +struct InstanceAttributeNode: public AstNode { IdentifierNode name; ValueNode value; }; -struct InstanceNode: AstNode +struct InstanceNode: public AstNode { IdentifierNode name; IdentifierNode component; @@ -385,11 +393,16 @@ struct InstanceNode: AstNode std::optional size; }; - -struct ConnectionInstanceNode: AstNode -{ +struct ConnectionComponentInstance { IdentifierNode instance; IdentifierNode pin; +}; + +struct ConnectionInstanceNode: public AstNode +{ + ConnectionComponentInstance first; + std::optional second; + IdentifierNode bus; std::optional wire; @@ -397,7 +410,7 @@ struct ConnectionInstanceNode: AstNode }; -struct SchemaNode: AstNode +struct SchemaNode: public AstNode { std::optional source; diff --git a/comdel/parser/comdelparser.cpp b/comdel/parser/comdelparser.cpp index 8ac38be..b8c0eb1 100644 --- a/comdel/parser/comdelparser.cpp +++ b/comdel/parser/comdelparser.cpp @@ -865,24 +865,44 @@ PResult ComdelParser::parseConnection() { RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION); RETURN_IF_NOT_TOKEN(TokenType::LPAREN); - ASSIGN_OR_RETURN_IF_ERR(connection.component, parseIdentifier()); + ASSIGN_OR_RETURN_IF_ERR(connection.first.component, parseIdentifier()); RETURN_IF_NOT_TOKEN(TokenType::DOT); - ASSIGN_OR_RETURN_IF_ERR(connection.pin, parseIdentifier()); + ASSIGN_OR_RETURN_IF_ERR(connection.first.pin, parseIdentifier()); RETURN_IF_NOT_TOKEN(TokenType::COMMA); ASSIGN_OR_RETURN_IF_ERR(connection.bus, parseIdentifier()); + + if(check(TokenType::COMMA)) { + auto conn = ConnectionComponentNode{}; + RETURN_IF_NOT_TOKEN(TokenType::COMMA); + RETURN_IF_NOT_TOKEN(TokenType::LPAREN); + ASSIGN_OR_RETURN_IF_ERR(conn.component, parseIdentifier()); + RETURN_IF_NOT_TOKEN(TokenType::DOT); + ASSIGN_OR_RETURN_IF_ERR(conn.pin, parseIdentifier()); + connection.second = conn; + } + RETURN_IF_NOT_TOKEN(TokenType::RPAREN); RETURN_IF_NOT_TOKEN(TokenType::LBRACE); + int wireCount = 0; + while(!check(TokenType::RBRACE)) { if (check(TokenType::KW_ATTRIBUTE)) { APPEND_OR_RETURN_IF_ERR(connection.attributes, parseAttribute()); } else if(check(TokenType::KW_WIRES)) { bump(); - auto wires = parseList(std::optional(TokenType::LBRACE), TokenType::RBRACE, std::optional(TokenType::COMMA), false, + auto wires = parseList(TokenType::LBRACE, TokenType::RBRACE, TokenType::COMMA, false, [this] { return parseConnectionWire(); }); RETURN_IF_ERR(wires); - connection.wires = *wires; + if(wireCount == 0) { + connection.firstWires = *wires; + } else if(wireCount == 1 && connection.second.has_value()) { + connection.secondWires = *wires; + } else { + return unexpected(); + } + wireCount++; } else { return unexpected(); } @@ -1158,11 +1178,21 @@ PResult ComdelParser::parseConnectionInstance() { ConnectionInstanceNode connection; RETURN_IF_NOT_TOKEN(TokenType::LPAREN); - ASSIGN_OR_RETURN_IF_ERR(connection.instance, parseIdentifier()); + ASSIGN_OR_RETURN_IF_ERR(connection.first.instance, parseIdentifier()); RETURN_IF_NOT_TOKEN(TokenType::DOT); - ASSIGN_OR_RETURN_IF_ERR(connection.pin, parseIdentifier()); + ASSIGN_OR_RETURN_IF_ERR(connection.first.pin, parseIdentifier()); RETURN_IF_NOT_TOKEN(TokenType::COMMA); ASSIGN_OR_RETURN_IF_ERR(connection.bus, parseIdentifier()); + + if(check(TokenType::COMMA)) { + bump(); + ConnectionComponentInstance second; + ASSIGN_OR_RETURN_IF_ERR(second.instance, parseIdentifier()); + RETURN_IF_NOT_TOKEN(TokenType::DOT); + ASSIGN_OR_RETURN_IF_ERR(second.pin, parseIdentifier()); + connection.second = second; + } + RETURN_IF_NOT_TOKEN(TokenType::RPAREN); RETURN_IF_NOT_TOKEN(TokenType::LBRACE);