903 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			903 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "schemacreator.h"
 | 
						|
 | 
						|
#include<set>
 | 
						|
 | 
						|
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<FunctionSignature> signatures)
 | 
						|
    : signatures(signatures)
 | 
						|
{}
 | 
						|
 | 
						|
std::optional<Library> 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;
 | 
						|
        component = loadComponent(comp);
 | 
						|
        if(component) {
 | 
						|
            components.push_back(*component);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for(uint i=0; i<node.buses.size(); i++) {
 | 
						|
        auto bus = loadBus(node.buses[i]);
 | 
						|
        if(bus) {
 | 
						|
            buses.push_back(*bus);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for(uint i=0; i<node.connections.size(); i++) {
 | 
						|
        auto conn = loadConnection(node.connections[i]);
 | 
						|
        if(conn) {
 | 
						|
            connections.push_back(*conn);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    for(uint i=0; i<node.messages.size(); i++) {
 | 
						|
        if(!node.messages[i].value.is(ValueNode::STRING)) {
 | 
						|
            errors.push_back(SourceError{node.messages[i].value.span, "expected `string`"});
 | 
						|
        } else {
 | 
						|
            messages[node.messages[i].key.value] = node.messages[i].value.asString();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return Library(name, libraryInfo, header, componentDirectory, addressSpaces, components, buses, connections, messages);
 | 
						|
}
 | 
						|
 | 
						|
std::optional<Bus> SchemaCreator::loadBus(BusNode node)
 | 
						|
{
 | 
						|
    std::string name = node.name.value;
 | 
						|
 | 
						|
    auto count = std::make_pair<int, int>(1, 1);
 | 
						|
    if(node.count) {
 | 
						|
        count = std::make_pair<int, int>(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> 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<Wire> 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<AddressSpace> SchemaCreator::loadAddressSpace(AddressSpaceNode node)
 | 
						|
{
 | 
						|
    return AddressSpace(node.name.value, node.start.value, node.end.value);
 | 
						|
}
 | 
						|
 | 
						|
std::optional<Connection> 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<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> 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 std::nullopt;
 | 
						|
}
 | 
						|
 | 
						|
std::optional<Component> 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<Attribute> attributes;
 | 
						|
    for(auto& a: node.attributes) {
 | 
						|
        std::optional<Attribute> attribute = loadAttribute(a);
 | 
						|
        if(attribute) {
 | 
						|
            attributes.push_back(*attribute);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    context[context.size() -1 ].attributes = attributes;
 | 
						|
 | 
						|
    std::vector<Rule> rules;
 | 
						|
    for(auto& r: node.rules) {
 | 
						|
        std::optional<Rule> 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<int, int>(1, 1);
 | 
						|
    if(node.count) {
 | 
						|
        count = std::make_pair<int, int>(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> display = loadDisplay(*node.display);
 | 
						|
    if(!display) {
 | 
						|
        pop();
 | 
						|
        return nullopt;
 | 
						|
    }
 | 
						|
 | 
						|
    std::vector<Pin> pins;
 | 
						|
    for(uint i=0; i<node.pins.size(); i++) {
 | 
						|
        auto pin = loadPin(node.pins[i]);
 | 
						|
        if(!pin) {
 | 
						|
            pop();
 | 
						|
            return nullopt;
 | 
						|
        }
 | 
						|
        pins.push_back(*pin);
 | 
						|
    }
 | 
						|
 | 
						|
    pop();
 | 
						|
    return Component(name, tooltip, source, type, rules, instanceName, count, *display, pins, attributes);
 | 
						|
}
 | 
						|
 | 
						|
std::optional<Wire> SchemaCreator::loadWire(WireNode node) {
 | 
						|
    return Wire(
 | 
						|
                node.name.value,
 | 
						|
                toType(node.type),
 | 
						|
                node.size.value,
 | 
						|
                node.hidden,
 | 
						|
                node.hasTermination,
 | 
						|
                node.isUnterminated
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
optional<Pin> 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<Attribute> attributes;
 | 
						|
    optional<Display> 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<std::vector<Value>> wiresOpt = std::nullopt;
 | 
						|
    if(node.wires.has_value()) {
 | 
						|
        auto nodeWires = node.wires.value();
 | 
						|
        std::vector<Value> 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<Display> SchemaCreator::loadDisplay(DisplayNode node)
 | 
						|
{
 | 
						|
    std::vector<ui::Item> 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<Attribute> 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> popup;
 | 
						|
    if(node.popup) {
 | 
						|
        popup = loadPopup(*node.popup, name, value.getType());
 | 
						|
    }
 | 
						|
 | 
						|
    pop();
 | 
						|
    return Attribute(name, value, popup);
 | 
						|
}
 | 
						|
 | 
						|
std::optional<Popup> 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<Rule> rules;
 | 
						|
    for(auto& r: node.rules) {
 | 
						|
        std::optional<Rule> rule = loadRule(r);
 | 
						|
        if(rule) {
 | 
						|
            rules.push_back(*rule);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    std::vector<Enumeration> enumeration;
 | 
						|
    if(node.enumerated) {
 | 
						|
        for(uint i=0; i<node.enumeration.size(); i++) {
 | 
						|
            if(type == Value::INT || type == Value::STRING || type == Value::BOOL) {
 | 
						|
                auto value = toType(node.enumeration[i].value);
 | 
						|
                if(value.getType() == type) {
 | 
						|
                    enumeration.push_back(Enumeration(node.enumeration[i].key.asString(), value));
 | 
						|
                } else {
 | 
						|
                    errors.push_back(SourceError{node.enumeration[i].span, "wrong type"});
 | 
						|
                }
 | 
						|
            } else if(type == Value::WIRE_REFERENCE) {
 | 
						|
                auto value = toType(node.enumeration[i].value);
 | 
						|
                if(value.isType(Value::UNDEFINED)) {
 | 
						|
                    if(current().doesWireExists(value.asReference())) {
 | 
						|
                        value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE);
 | 
						|
                    } else {
 | 
						|
                        errors.push_back(SourceError{node.enumeration[i].span, "unknown wire"});
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if(value.isType(Value::WIRE_REFERENCE) || value.isType(Value::INT) || value.isType(Value::NIL)) {
 | 
						|
                    enumeration.push_back(Enumeration(node.enumeration[i].key.asString(), value));
 | 
						|
                } else {
 | 
						|
                    errors.push_back(SourceError{node.enumeration[i].span, "wrong type"});
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        if(type == Value::WIRE_REFERENCE && !current().inConnection) {
 | 
						|
            errors.push_back(SourceError{node.span, "@enumeration is required for attributes of type wire"});
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    pop();
 | 
						|
 | 
						|
    return Popup(title, text, popupType, rules, enumeration);
 | 
						|
}
 | 
						|
 | 
						|
std::optional<Rule> SchemaCreator::loadRule(RuleNode node)
 | 
						|
{
 | 
						|
    std::vector<IfStatement> 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<Condition> SchemaCreator::loadCondition(ConditionNode node)
 | 
						|
{
 | 
						|
    std::string function = node.functionName.value;
 | 
						|
 | 
						|
    for(uint i=0; i<signatures.size(); i++) {
 | 
						|
        if(signatures[i].name == function) {
 | 
						|
            if(signatures[i].params.size() == node.params.size()) {
 | 
						|
                std::vector<Value> params;
 | 
						|
                for(uint j=0; j<signatures[i].params.size(); j++) {
 | 
						|
                    bool exists = false;
 | 
						|
                    auto type = toType(node.params[j]);
 | 
						|
                    if (type.getType() == Value::UNDEFINED) {
 | 
						|
                        if(current().doesAttributeExists(type.asReference(), signatures[i].params[j])) {
 | 
						|
                            exists = true;
 | 
						|
                            type = Value::fromReference(type.asReference(), Value::ATTRIBUTE_REFERENCE);
 | 
						|
                        }
 | 
						|
                        if(signatures[i].params[j] == Value::ADDRESS_SPACE) {
 | 
						|
                            if(hasAddressSpace(type.asReference())) {
 | 
						|
                                exists = true;
 | 
						|
                                type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE_REFERENCE);
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
 | 
						|
                        if(!exists) {
 | 
						|
                            errors.push_back(SourceError{node.functionName.span, "unknown reference " + type.asReference()});
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    params.push_back(type);
 | 
						|
                }
 | 
						|
                return Condition(function, params, node.negated);
 | 
						|
            } else {
 | 
						|
                errors.push_back(SourceError{node.functionName.span, "wrong number of parameters"});
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    errors.push_back(SourceError{node.functionName.span, "unknown function name"});
 | 
						|
    return nullopt;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
Schema* SchemaCreator::loadSchema(SchemaNode node, Library &library)
 | 
						|
{
 | 
						|
    Schema *schema = new 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<ComponentInstance*>(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<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;
 | 
						|
        }
 | 
						|
 | 
						|
        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->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<InstanceAttribute*> 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<InstanceAttribute*> 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<WireInstance*> 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<int, int> position = std::make_pair(0, 0);
 | 
						|
    if(node.position) {
 | 
						|
        position = std::make_pair(node.position->first.value, node.position->second.value);
 | 
						|
    }
 | 
						|
    return std::optional<WireInstance*>(new WireInstance(node.name.value, *display, position));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
} // namespace domain
 |