Added support for direct buses

This commit is contained in:
Borna Rajkovic 2022-04-09 19:44:02 +02:00
parent 7fcfb8c977
commit c65d12a2a1
7 changed files with 335 additions and 108 deletions

View File

@ -224,62 +224,151 @@ std::optional<Connection> 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<std::string> 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<Attribute> attributes;
for(uint i=0; i<node.attributes.size(); i++) {
auto attr = loadAttribute(node.attributes[i]);
if(!attr) {
return nullopt;
auto componentInstance = getComponentPin(first.component, first.pin);
if(!componentInstance) {
errors.emplace_back(node.span, "pin does not exist");
}
attributes.push_back(*attr);
}
std::set<std::string> 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<Value> wires;
for(uint i=0; i<node.wires.size(); i++) {
if(node.wires[i].is(ValueNode::NIL)) {
wires.push_back(Value::fromNull());
} else if(node.wires[i].is(ValueNode::INT)) {
wires.push_back(Value::fromInt(node.wires[i].asInt()));
} else if(node.wires[i].is(ValueNode::IDENTIFIER)) {
if(attributeNames.count(node.wires[i].asIdentifier())) {
wires.push_back(Value::fromReference(node.wires[i].asIdentifier(), Value::ATTRIBUTE_REFERENCE));
} else if(wireNames.count(node.wires[i].asIdentifier())) {
wires.push_back(Value::fromReference(node.wires[i].asIdentifier(), Value::WIRE_REFERENCE));
} else {
errors.emplace_back(node.wires[i].span, "unknown identifier");
std::set<std::string> wireNames;
for(auto &wire: busInstance->getWires()) {
wireNames.insert(wire.getName());
current().wires.push_back(wire.getName());
}
std::vector<Attribute> 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<std::string> attributeNames;
for(auto attribute: attributes) {
attributeNames.insert(attribute.getName());
}
std::vector<Value> 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<std::string> wireNames;
for(auto &wire: busInstance->getWires()) {
wireNames.insert(wire.getName());
current().wires.push_back(wire.getName());
}
std::vector<Attribute> attributes;
for(auto & attribute : node.attributes) {
auto attr = loadAttribute(attribute);
if(!attr) {
return nullopt;
}
attributes.push_back(*attr);
}
std::set<std::string> attributeNames;
for(auto attribute: attributes) {
attributeNames.insert(attribute.getName());
}
std::vector<Value> 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<Value> 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<Component> ComdelGenerator::loadComponent(ComponentNode node)
@ -659,25 +748,60 @@ std::optional<Schema> ComdelGenerator::loadSchema(SchemaNode node, Library &libr
}
for(auto &conn: node.connections) {
auto component = dynamic_cast<ComponentInstance*>(schema.getInstance(conn.instance.value));
if(component == NULL) {
errors.push_back(SourceError{conn.instance.span, "unknown component"});
auto firstComponent = dynamic_cast<ComponentInstance*>(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<ComponentInstance*>(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<BusInstance*>(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> 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<Schema> ComdelGenerator::loadSchema(SchemaNode node, Library &libr
std::vector<InstanceAttribute*> 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<Schema> 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;

View File

@ -2,20 +2,19 @@
namespace domain {
Connection::Connection(std::string component, std::string pin, std::string bus, std::vector<Attribute> attributes, std::vector<Value> wires)
: component(component), pin(pin), bus(bus), attributes(attributes), wires(wires)
Connection::Connection(ConnectionComponent first, std::optional<ConnectionComponent> second,
std::string bus, std::vector<Attribute> attributes,
std::vector<Value> firstWires, std::optional<std::vector<Value>> 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<ConnectionComponent> 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<Attribute> Connection::getAttributes() {
return attributes;
}
std::vector<Value> Connection::getWires() {
return wires;
return firstWires;
}
std::optional<std::vector<Value>> 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

View File

@ -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<ConnectionComponent> second;
std::string bus;
std::vector<Attribute> attributes;
std::vector<Value> wires;
std::vector<Value> firstWires;
std::optional<std::vector<Value>> secondWires;
public:
Connection(std::string component, std::string pin, std::string bus, std::vector<Attribute> attributes, std::vector<Value> wires);
Connection(ConnectionComponent first, std::optional<ConnectionComponent> second,
std::string bus, std::vector<Attribute> attributes,
std::vector<Value> firstWires, std::optional<std::vector<Value>> 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<ConnectionComponent> getSecondComponent();
std::string getComponent();
std::string getPin();
std::string getBus();
std::vector<Attribute> getAttributes();
std::vector<Value> getWires();
std::optional<std::vector<Value>> getSecondWires();
Attribute getAttribute(std::string name);
bool hasAttribute(std::string name);

View File

@ -81,16 +81,29 @@ Bus &Library::getBus(std::string bus) {
throw std::exception();
}
std::optional<Connection> 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<Connection> Library::getConnection(ConnectionComponent component, std::string bus) {
for(uint i=0; i<connections.size(); i++) {
if(connections[i].isConnecting(component, pin, bus)) {
if(connections[i].isConnecting(component, bus)) {
return connections[i];
}
}
return nullopt;
}
bool Library::hasConnection(std::string component, std::string pin, std::string bus) {
return getConnection(component, pin, bus).has_value();
bool Library::hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) {
return getConnection(component, bus, secondComponent).has_value();
}
std::optional<Connection> Library::getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent) {
for(uint i=0; i<connections.size(); i++) {
if(connections[i].isConnecting(component, bus, secondComponent)) {
return connections[i];
}
}
return nullopt;
}
std::string Library::getMessage(std::string key) {

View File

@ -45,18 +45,19 @@ public:
bool hasComponent(std::string name);
bool hasBus(std::string name);
bool hasConnection(std::string component, std::string pin, std::string bus);
std::map<std::string, std::string> getMessages();
AddressSpace &getAddressSpace(std::string name);
Component &getComponent(std::string name);
Bus &getBus(std::string bus);
std::optional<Connection> 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<Connection> getConnection(ConnectionComponent component, std::string bus);
bool hasConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent);
std::optional<Connection> getConnection(ConnectionComponent component, std::string bus, ConnectionComponent secondComponent);
};
} // namespace domain

View File

@ -170,7 +170,7 @@ struct ConditionNode
std::vector<ValueNode> 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<IfStatementNode> 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<PropertyNode> values;
};
struct DisplayNode: AstNode
struct DisplayNode: public AstNode
{
std::vector<DisplayItemNode> 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<PopupNode> popup;
};
struct ConnectionNode: AstNode
struct ConnectionComponentNode: public AstNode
{
IdentifierNode component;
IdentifierNode pin;
IdentifierNode bus;
std::vector<AttributeNode> attributes;
std::vector<ValueNode> wires;
};
struct ConnectionNode: public AstNode
{
ConnectionComponentNode first;
std::optional<ConnectionComponentNode> second;
struct ComponentNode: AstNode
IdentifierNode bus;
std::vector<AttributeNode> attributes;
std::vector<ValueNode> firstWires;
std::optional<std::vector<ValueNode>> 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<WireNode> wires;
};
struct LibraryNode: AstNode
struct LibraryNode: public AstNode
{
std::optional<StringNode> name;
std::optional<StringNode> libraryInfo;
@ -361,20 +369,20 @@ struct LibraryNode: AstNode
// SCHEMA models
struct WireInstanceNode: AstNode
struct WireInstanceNode: public AstNode
{
IdentifierNode name;
std::optional<CountNode> position;
std::optional<DisplayNode> 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<NumberNode> size;
};
struct ConnectionInstanceNode: AstNode
{
struct ConnectionComponentInstance {
IdentifierNode instance;
IdentifierNode pin;
};
struct ConnectionInstanceNode: public AstNode
{
ConnectionComponentInstance first;
std::optional<ConnectionComponentInstance> second;
IdentifierNode bus;
std::optional<IdentifierNode> wire;
@ -397,7 +410,7 @@ struct ConnectionInstanceNode: AstNode
};
struct SchemaNode: AstNode
struct SchemaNode: public AstNode
{
std::optional<StringNode> source;

View File

@ -865,24 +865,44 @@ PResult<ConnectionNode> 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<ValueNode>(std::optional<TokenType>(TokenType::LBRACE), TokenType::RBRACE, std::optional<TokenType>(TokenType::COMMA), false,
auto wires = parseList<ValueNode>(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<ConnectionInstanceNode> 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);