schema_editor/comdel/domain/schemacreator.cpp

957 lines
32 KiB
C++
Raw Permalink Normal View History

2022-04-09 18:03:43 +00:00
#include "schemacreator.h"
2022-03-31 21:20:41 +00:00
#include<set>
2022-05-07 11:20:09 +00:00
#include <utility>
2022-03-31 21:20:41 +00:00
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;
}
2022-04-05 21:48:07 +00:00
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;
}
}
2022-03-31 21:20:41 +00:00
Value::ValueType toType(ValueNode::ValueType type) {
switch (type) {
case ValueNode::BOOL:
return Value::BOOL;
2022-05-15 21:55:03 +00:00
case ValueNode::MEMORY:
return Value::MEMORY_REFERENCE;
2022-03-31 21:20:41 +00:00
case ValueNode::WIRE:
return Value::WIRE_REFERENCE;
case ValueNode::STRING:
return Value::STRING;
case ValueNode::INT:
return Value::INT;
2022-05-15 21:55:03 +00:00
case ValueNode::NIL:
return Value::NIL;
2022-03-31 21:20:41 +00:00
default:
return Value::UNDEFINED;
}
}
2022-05-15 21:55:03 +00:00
Value toType(ValueNode node, Value::ValueType type = Value::ValueType::UNDEFINED) {
if(type == Value::MEMORY_REFERENCE) {
if(node.getType() == ValueNode::NIL) {
return Value::fromMemoryReference(nullopt);
} else {
return Value::fromMemoryReference(node.asIdentifier());
}
}
2022-03-31 21:20:41 +00:00
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();
2022-03-31 21:20:41 +00:00
}
return Value::fromReference(node.asIdentifier(), Value::UNDEFINED);
}
Bus::BusType toType(BusNode::BusType type) {
if(type == BusNode::AUTOMATIC) {
return Bus::AUTOMATIC;
} else if(type == BusNode::SINGLE_AUTOMATIC) {
return Bus::SINGLE_AUTOMATIC;
2022-03-31 21:20:41 +00:00
}
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::OPTIONAL) {
return PinConnection::OPTIONAL;
2022-03-31 21:20:41 +00:00
}
return PinConnection::REQUIRED;
2022-03-31 21:20:41 +00:00
}
Popup::PopupType toType(PopupNode::PopupType type)
{
if(type == PopupNode::AUTOMATIC) {
return Popup::AUTOMATIC;
}
return Popup::ON_DEMAND;
}
2022-05-15 09:17:05 +00:00
SchemaCreator::SchemaCreator(std::vector<FunctionValidator*> validators)
: validators(std::move(validators))
2022-03-31 21:20:41 +00:00
{}
2022-04-09 18:03:43 +00:00
std::optional<Library> SchemaCreator::loadLibrary(LibraryNode node)
2022-03-31 21:20:41 +00:00
{
// library fields
if(!node.name) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @name");
2022-03-31 21:20:41 +00:00
return nullopt;
2022-04-05 21:48:07 +00:00
} else {
name = node.name->asString();
2022-03-31 21:20:41 +00:00
}
2022-05-15 23:02:34 +00:00
if(node.componentHeader.has_value()) {
componentHeader = node.componentHeader->asString();
}
2022-03-31 21:20:41 +00:00
if(!node.componentDirectory) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @componentDirectory");
2022-03-31 21:20:41 +00:00
return nullopt;
2022-04-05 21:48:07 +00:00
} else {
componentDirectory = node.componentDirectory->asString();
2022-03-31 21:20:41 +00:00
}
2022-04-05 21:48:07 +00:00
header = node.header ? node.header->asString() : "";
2022-03-31 21:20:41 +00:00
2022-04-05 21:48:07 +00:00
libraryInfo = node.libraryInfo ? node.libraryInfo->asString() : "";
2022-03-31 21:20:41 +00:00
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);
}
}
2022-05-07 11:20:09 +00:00
for(auto& buse : node.buses) {
auto bus = loadBus(buse);
2022-04-05 21:48:07 +00:00
if(bus) {
buses.push_back(*bus);
}
}
2022-05-07 11:20:09 +00:00
for(auto& connection : node.connections) {
auto conn = loadConnection(connection);
2022-04-05 21:48:07 +00:00
if(conn) {
connections.push_back(*conn);
2022-03-31 21:20:41 +00:00
}
}
2022-05-07 11:20:09 +00:00
for(auto & message : node.messages) {
if(!message.value.is(ValueNode::STRING)) {
errors.emplace_back(message.value.span, "expected `string`");
2022-04-05 21:48:07 +00:00
} else {
2022-05-07 11:20:09 +00:00
messages[message.key.value] = message.value.asString();
2022-03-31 21:20:41 +00:00
}
}
2022-05-15 23:02:34 +00:00
return Library(name, libraryInfo, header, componentDirectory, componentHeader, addressSpaces, components, buses, connections, messages);
2022-03-31 21:20:41 +00:00
}
2022-04-09 18:03:43 +00:00
std::optional<Bus> SchemaCreator::loadBus(BusNode node)
2022-03-31 21:20:41 +00:00
{
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) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.count->span, "invalid @size");
2022-03-31 21:20:41 +00:00
return nullopt;
}
2022-04-24 20:21:45 +00:00
auto type = toType(node.type.value);
2022-03-31 21:20:41 +00:00
if(!node.tooltip && type == Bus::REGULAR) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @tooltip");
2022-03-31 21:20:41 +00:00
return nullopt;
}
std::string tooltip = node.tooltip->asString();
if(!node.display && type == Bus::REGULAR) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @display");
2022-03-31 21:20:41 +00:00
return nullopt;
}
if(node.display && (type == Bus::AUTOMATIC || type == Bus::SINGLE_AUTOMATIC)) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "automatic bus cannot have a @display");
2022-03-31 21:20:41 +00:00
return nullopt;
}
optional<Display> display;
2022-04-07 20:40:31 +00:00
if(type == Bus::REGULAR) {
2022-03-31 21:20:41 +00:00
display = loadDisplay(*node.display);
if(!display) {
return nullopt;
}
}
2022-04-05 21:48:07 +00:00
if(node.wires.size() == 0) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @wires");
2022-04-05 21:48:07 +00:00
return nullopt;
}
std::vector<Wire> wires;
for(auto& _wire: node.wires) {
auto wire = loadWire(_wire);
if(wire) {
wires.push_back(*wire);
}
}
if(type == Bus::SINGLE_AUTOMATIC && wires.size() != 1) {
errors.emplace_back(node.span, "singleAutomatic bus must have exactly 1 wire defined");
return nullopt;
}
2022-04-05 21:48:07 +00:00
return Bus(name, tooltip, type, count, wires, display);
2022-03-31 21:20:41 +00:00
}
2022-04-09 18:03:43 +00:00
std::optional<AddressSpace> SchemaCreator::loadAddressSpace(AddressSpaceNode node)
2022-03-31 21:20:41 +00:00
{
return AddressSpace(node.name.value, node.start.value, node.end.value);
}
2022-04-09 18:03:43 +00:00
std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node)
2022-03-31 21:20:41 +00:00
{
push(ComdelContext("connection", false, true, false, false));
2022-04-05 21:48:07 +00:00
2022-03-31 21:20:41 +00:00
std::string bus = node.bus.value;
2022-04-05 21:48:07 +00:00
auto busInstance = getBus(bus);
if(!busInstance) {
errors.emplace_back(node.span, "bus does not exist");
2022-04-05 21:48:07 +00:00
}
if(busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
current().inSingleAutomaticConnection = true;
}
2022-04-09 17:44:02 +00:00
if(busInstance->getType() == Bus::REGULAR) {
ConnectionComponent first{node.first.component.value, node.first.pin.value};
2022-04-05 21:48:07 +00:00
2022-04-09 17:44:02 +00:00
auto componentInstance = getComponentPin(first.component, first.pin);
if(!componentInstance) {
errors.emplace_back(node.span, "pin does not exist");
2022-03-31 21:20:41 +00:00
}
2022-04-09 17:44:02 +00:00
if(node.second.has_value()) {
errors.emplace_back(node.span, "regular bus doesn't allow direct connections");
}
2022-03-31 21:20:41 +00:00
2022-04-09 17:44:02 +00:00
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 {
2022-04-09 17:44:02 +00:00
errors.emplace_back(firstWire.span, "unknown value type");
}
2022-03-31 21:20:41 +00:00
}
2022-04-09 17:44:02 +00:00
pop();
return Connection(first, nullopt, bus, attributes, wires, nullopt);
} else if(busInstance->getType() == Bus::AUTOMATIC || busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
2022-04-09 17:44:02 +00:00
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());
}
if(node.attributes.size() != 2 && busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
errors.emplace_back(node.span, "singleAutomatic must contain 2 attributes");
}
2022-04-09 17:44:02 +00:00
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::STRING) && busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
firstWires.push_back(Value::fromString(firstWire.asString()));
} else if(firstWire.is(ValueNode::IDENTIFIER) && busInstance->getType() == Bus::AUTOMATIC) {
2022-04-09 17:44:02 +00:00
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, "unsupported value type");
2022-04-09 17:44:02 +00:00
}
}
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::STRING) && busInstance->getType() == Bus::SINGLE_AUTOMATIC) {
secondWires.push_back(Value::fromString(secondWire.asString()));
} else if(secondWire.is(ValueNode::IDENTIFIER) && busInstance->getType() == Bus::AUTOMATIC) {
2022-04-09 17:44:02 +00:00
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, "unsupported value type");
}
}
if(busInstance->getType() == Bus::SINGLE_AUTOMATIC && attributes.size() == 2) {
if(!attributes[0].getPopup().has_value()) {
errors.emplace_back(node.attributes[0].span, "@popup is required");
} else if(attributes[0].getDefault().getType() != Value::STRING) {
errors.emplace_back(node.attributes[0].span, "@attribute must be of type string");
} else {
attributes[0].getPopup()->setEnumeration(createWireEnumeration(firstWires));
}
if(!attributes[1].getPopup().has_value()) {
errors.emplace_back(node.attributes[1].span, "@popup is required");
} else if(attributes[1].getDefault().getType() != Value::STRING) {
errors.emplace_back(node.attributes[1].span, "@attribute must be of type string");
} else {
attributes[1].getPopup()->setEnumeration(createWireEnumeration(secondWires));
2022-04-09 17:44:02 +00:00
}
}
pop();
return Connection(first, second, bus, attributes, firstWires, secondWires);
}
2022-04-05 21:48:07 +00:00
pop();
2022-04-09 17:44:02 +00:00
errors.emplace_back(node.span, "unsupported connection type");
2022-04-05 21:48:07 +00:00
2022-04-09 18:03:43 +00:00
return std::nullopt;
2022-03-31 21:20:41 +00:00
}
2022-04-09 18:03:43 +00:00
std::optional<Component> SchemaCreator::loadComponent(ComponentNode node)
2022-03-31 21:20:41 +00:00
{
push(ComdelContext(node.name.value, true, false, false, false));
2022-04-05 21:48:07 +00:00
2022-03-31 21:20:41 +00:00
std::string name = node.name.value;
if(!node.tooltip) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @tooltip");
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
return nullopt;
}
std::string tooltip = node.tooltip->asString();
if(!node.source) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @source");
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
return nullopt;
}
std::string source = node.source->asString();
2022-04-24 20:21:45 +00:00
Component::ComponentType type = toType(node.type.value);
2022-03-31 21:20:41 +00:00
std::vector<Attribute> attributes;
for(auto& a: node.attributes) {
std::optional<Attribute> attribute = loadAttribute(a);
if(attribute) {
attributes.push_back(*attribute);
}
}
2022-05-15 21:55:03 +00:00
if(type == Component::PROCESSOR) {
attributes.push_back(*createMemoryAttribute());
}
2022-03-31 21:20:41 +00:00
2022-04-05 21:48:07 +00:00
context[context.size() -1 ].attributes = attributes;
2022-03-31 21:20:41 +00:00
std::vector<Rule> rules;
for(auto& r: node.rules) {
std::optional<Rule> rule = loadRule(r);
if(rule) {
rules.push_back(*rule);
}
}
if(!node.instanceName) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @instanceName");
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
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) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.count->first.span, "invalid @size");
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
return nullopt;
}
if(!node.display) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @display");
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
return nullopt;
}
optional<Display> display = loadDisplay(*node.display);
if(!display) {
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
return nullopt;
}
std::vector<Pin> pins;
2022-05-07 11:20:09 +00:00
for(auto &p : node.pins) {
auto pin = loadPin(p);
2022-03-31 21:20:41 +00:00
if(!pin) {
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
return nullopt;
}
2022-04-05 21:48:07 +00:00
pins.push_back(*pin);
2022-03-31 21:20:41 +00:00
}
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
return Component(name, tooltip, source, type, rules, instanceName, count, *display, pins, attributes);
}
2022-04-09 18:03:43 +00:00
std::optional<Wire> SchemaCreator::loadWire(WireNode node) {
2022-04-05 21:48:07 +00:00
return Wire(
node.name.value,
2022-04-24 20:21:45 +00:00
toType(node.type.value),
2022-04-05 21:48:07 +00:00
node.size.value,
node.hidden,
2022-04-24 20:21:45 +00:00
node.hasTerminateWith,
toType(node.terminateWith)
2022-04-05 21:48:07 +00:00
);
}
2022-04-09 18:03:43 +00:00
optional<Pin> SchemaCreator::loadPin(PinNode node)
2022-03-31 21:20:41 +00:00
{
std::string name = node.name.value;
2022-04-24 20:21:45 +00:00
Pin::PinType type = toType(node.type.value);
2022-03-31 21:20:41 +00:00
if(!node.tooltip) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @tooltip");
2022-03-31 21:20:41 +00:00
return nullopt;
}
std::string tooltip = node.tooltip->asString();
if(!node.display) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @display");
2022-03-31 21:20:41 +00:00
return nullopt;
}
std::vector<Attribute> attributes;
optional<Display> display = loadDisplay(*node.display);
if(!display) {
return nullopt;
}
if(!node.connection) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @connection");
2022-03-31 21:20:41 +00:00
return nullopt;
}
auto connection = loadPinConnection(*node.connection);
2022-04-09 12:10:40 +00:00
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);
2022-03-31 21:20:41 +00:00
}
2022-04-07 20:40:31 +00:00
int getIntProperty(DisplayItemNode &node, std::string property) {
2022-04-08 16:55:29 +00:00
for(auto& prop: node.values) {
2022-04-07 20:40:31 +00:00
if(prop.key.value == property) {
return prop.value.asInt();
}
}
2022-04-08 16:55:29 +00:00
throw std::exception();
2022-04-07 20:40:31 +00:00
}
2022-03-31 21:20:41 +00:00
2022-04-09 18:03:43 +00:00
std::optional<Display> SchemaCreator::loadDisplay(DisplayNode node)
2022-03-31 21:20:41 +00:00
{
2022-04-07 20:40:31 +00:00
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 {
2022-05-07 11:20:09 +00:00
errors.emplace_back(item.type.span, "unsupported display type");
2022-04-07 20:40:31 +00:00
}
items.push_back(displayItem);
}
return Display(items);
2022-03-31 21:20:41 +00:00
}
2022-04-09 18:03:43 +00:00
PinConnection SchemaCreator::loadPinConnection(PinConnectionNode node)
2022-03-31 21:20:41 +00:00
{
std::string message = node.message.asString();
2022-04-24 20:21:45 +00:00
PinConnection::ConnectionType type = toType(node.type.value);
2022-05-07 11:20:09 +00:00
return {message, type};
2022-03-31 21:20:41 +00:00
}
2022-04-09 18:03:43 +00:00
std::optional<Attribute> SchemaCreator::loadAttribute(AttributeNode node)
2022-03-31 21:20:41 +00:00
{
std::string name = node.name.value;
2022-04-05 21:48:07 +00:00
pushAdditional(name);
2022-03-31 21:20:41 +00:00
Value value;
2022-04-05 21:48:07 +00:00
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 {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.name.span, "unsupported type");
2022-04-05 21:48:07 +00:00
}
}
if(current().inConnection && !current().inSingleAutomaticConnection) { // TODO remove identifier
2022-04-05 21:48:07 +00:00
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);
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "unknown identifier");
2022-04-05 21:48:07 +00:00
}
} else {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.name.span, "unsupported type");
2022-04-05 21:48:07 +00:00
}
2022-03-31 21:20:41 +00:00
}
if(current().inSingleAutomaticConnection) {
if (node.type == ValueNode::STRING) {
value = Value::fromString(node.defaultValue->asString());
} else {
errors.emplace_back(node.name.span, "unsupported type");
}
}
2022-03-31 21:20:41 +00:00
2022-05-07 11:20:09 +00:00
current().attributes.emplace_back(name, value);
2022-04-05 21:48:07 +00:00
2022-03-31 21:20:41 +00:00
std::optional<Popup> popup;
if(node.popup) {
popup = loadPopup(*node.popup, name, value.getType());
}
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
return Attribute(name, value, popup);
}
2022-04-09 18:03:43 +00:00
std::optional<Popup> SchemaCreator::loadPopup(PopupNode node, std::string name, Value::ValueType type)
2022-03-31 21:20:41 +00:00
{
2022-04-24 20:21:45 +00:00
auto popupType = toType(node.type.value().value);
2022-03-31 21:20:41 +00:00
2022-04-05 21:48:07 +00:00
pushAdditional(name);
current().attributes.clear();
2022-05-07 11:20:09 +00:00
current().attributes.emplace_back(name, Value::ofType(type));
2022-04-05 21:48:07 +00:00
2022-03-31 21:20:41 +00:00
if(!node.title) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @title");
2022-03-31 21:20:41 +00:00
return nullopt;
}
std::string title = node.title->asString();
if(!node.text) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "missing @text");
2022-03-31 21:20:41 +00:00
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) {
2022-05-07 11:20:09 +00:00
for(auto& enumNode : node.enumeration) {
if(type == Value::INT || type == Value::STRING || type == Value::BOOL) {
2022-05-07 11:20:09 +00:00
auto value = toType(enumNode.value);
if(value.getType() == type) {
2022-05-07 11:20:09 +00:00
enumeration.emplace_back(enumNode.key.asString(), value);
} else {
2022-05-07 11:20:09 +00:00
errors.emplace_back(enumNode.span, "wrong type");
}
} else if(type == Value::WIRE_REFERENCE) {
2022-05-07 11:20:09 +00:00
auto value = toType(enumNode.value);
if(value.isType(Value::UNDEFINED)) {
if(current().doesWireExists(value.asReference())) {
value = Value::fromReference(value.asReference(), Value::WIRE_REFERENCE);
} else {
2022-05-07 11:20:09 +00:00
errors.emplace_back(enumNode.span, "unknown wire");
}
}
if(value.isType(Value::WIRE_REFERENCE) || value.isType(Value::INT) || value.isType(Value::NIL)) {
2022-05-07 11:20:09 +00:00
enumeration.emplace_back(enumNode.key.asString(), value);
} else {
2022-05-07 11:20:09 +00:00
errors.emplace_back(enumNode.span, "wrong type");
}
2022-04-05 21:48:07 +00:00
}
}
} else {
if(type == Value::WIRE_REFERENCE && !current().inConnection) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.span, "@enumeration is required for attributes of type wire");
2022-03-31 21:20:41 +00:00
}
}
2022-04-05 21:48:07 +00:00
pop();
2022-03-31 21:20:41 +00:00
return Popup(title, text, popupType, rules, enumeration);
}
2022-04-09 18:03:43 +00:00
std::optional<Rule> SchemaCreator::loadRule(RuleNode node)
2022-03-31 21:20:41 +00:00
{
std::vector<IfStatement> statements;
for(auto& stmt: node.statements) {
auto condition = loadCondition(stmt.condition);
if(condition) {
2022-05-07 11:20:09 +00:00
statements.emplace_back(*condition, Action(toType(stmt.action.type.value), stmt.action.message.asString()));
2022-03-31 21:20:41 +00:00
} else {
return nullopt;
}
}
return Rule(statements);
}
2022-04-09 18:03:43 +00:00
std::optional<Condition> SchemaCreator::loadCondition(ConditionNode node)
2022-03-31 21:20:41 +00:00
{
std::string function = node.functionName.value;
2022-05-15 09:17:05 +00:00
for(auto & validator : validators) {
if(validator->getName() == function) {
if(validator->getSignature().size() == node.params.size()) {
2022-03-31 21:20:41 +00:00
std::vector<Value> params;
2022-05-15 09:17:05 +00:00
for(uint j=0; j<validator->getSignature().size(); j++) {
2022-04-05 21:48:07 +00:00
bool exists = false;
auto type = toType(node.params[j]);
if (type.getType() == Value::UNDEFINED) {
2022-05-15 09:17:05 +00:00
if(current().doesAttributeExists(type.asReference(), validator->getSignature()[j])) {
2022-04-05 21:48:07 +00:00
exists = true;
type = Value::fromReference(type.asReference(), Value::ATTRIBUTE_REFERENCE);
}
2022-05-15 09:17:05 +00:00
if(validator->getSignature()[j] == Value::ADDRESS_SPACE) {
2022-04-05 21:48:07 +00:00
if(hasAddressSpace(type.asReference())) {
exists = true;
2022-04-10 12:23:18 +00:00
type = Value::fromReference(type.asReference(), Value::ADDRESS_SPACE_REFERENCE);
2022-04-05 21:48:07 +00:00
}
}
if(!exists) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.functionName.span, "unknown reference " + type.asReference());
2022-04-05 21:48:07 +00:00
}
}
params.push_back(type);
2022-03-31 21:20:41 +00:00
}
2022-04-05 21:48:07 +00:00
return Condition(function, params, node.negated);
} else {
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.functionName.span, "wrong number of parameters");
2022-03-31 21:20:41 +00:00
}
}
}
2022-05-07 11:20:09 +00:00
errors.emplace_back(node.functionName.span, "unknown function name");
2022-03-31 21:20:41 +00:00
return nullopt;
}
2022-04-18 09:41:02 +00:00
Schema* SchemaCreator::loadSchema(SchemaNode node, Library &library)
2022-04-05 21:48:07 +00:00
{
2022-05-07 11:20:09 +00:00
auto *schema = new Schema();
2022-04-05 21:48:07 +00:00
for(auto &instance: node.instances) {
if(library.hasComponent(instance.component.value)) {
2022-05-07 11:20:09 +00:00
schema->componentInstances.push_back(loadComponentInstance(instance, library));
2022-04-05 21:48:07 +00:00
}
if(library.hasBus(instance.component.value)) {
2022-05-07 11:20:09 +00:00
schema->busInstances.push_back(loadBusInstance(instance, library));
2022-04-05 21:48:07 +00:00
}
}
for(auto &conn: node.connections) {
2022-05-08 13:47:47 +00:00
auto firstComponent = schema->getComponentInstance(conn.first.instance.value);
2022-05-07 11:20:09 +00:00
if(firstComponent == nullptr) {
errors.emplace_back(conn.first.instance.span, "unknown component");
2022-04-05 21:48:07 +00:00
continue;
}
2022-04-09 17:44:02 +00:00
if(!firstComponent->component.hasPin(conn.first.pin.value)) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(conn.first.pin.span, "unknown pin");
2022-04-05 21:48:07 +00:00
continue;
}
2022-04-09 17:44:02 +00:00
2022-05-07 11:20:09 +00:00
ComponentInstance *secondComponent = nullptr;
2022-04-09 17:44:02 +00:00
if(conn.second.has_value()) {
2022-05-08 13:47:47 +00:00
secondComponent = schema->getComponentInstance(conn.second->instance.value);
2022-05-07 11:20:09 +00:00
if(secondComponent == nullptr) {
errors.emplace_back(conn.second->instance.span, "unknown component");
2022-04-09 17:44:02 +00:00
continue;
}
if(!secondComponent->component.hasPin(conn.second->pin.value)) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(conn.second->pin.span, "unknown pin");
2022-04-09 17:44:02 +00:00
continue;
}
}
2022-05-08 13:47:47 +00:00
auto bus = schema->getBusInstance(conn.bus.value);
2022-05-07 11:20:09 +00:00
if(bus == nullptr) {
errors.emplace_back(conn.bus.span, "unknown bus");
2022-04-05 21:48:07 +00:00
continue;
}
2022-04-09 17:44:02 +00:00
std::optional<Connection> connection = std::nullopt;
2022-05-07 11:20:09 +00:00
if(secondComponent != nullptr) {
2022-04-09 17:44:02 +00:00
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 {
2022-05-07 11:20:09 +00:00
errors.emplace_back(conn.span, "unknown connection");
2022-04-09 17:44:02 +00:00
continue;
}
} else {
2022-04-09 18:03:43 +00:00
ConnectionComponent firstConn{firstComponent->component.getName(), conn.first.pin.value};
2022-04-09 17:44:02 +00:00
if(library.hasConnection(firstConn,
bus->bus.getName())) {
connection = *library.getConnection(firstConn, bus->bus.getName());
} else {
2022-05-07 11:20:09 +00:00
errors.emplace_back(conn.span, "unknown connection");
2022-04-09 17:44:02 +00:00
continue;
}
2022-04-05 21:48:07 +00:00
}
2022-05-07 12:19:43 +00:00
std::vector<InstanceAttribute> attributes;
2022-04-05 21:48:07 +00:00
for(auto& attr: conn.attributes) {
2022-04-09 17:44:02 +00:00
if(connection->hasAttribute(attr.name.value)) {
auto attribute = connection->getAttribute(attr.name.value);
2022-04-05 21:48:07 +00:00
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)) {
2022-05-07 11:20:09 +00:00
errors.emplace_back(attr.span, "invalid value");
2022-04-05 21:48:07 +00:00
}
2022-05-07 12:19:43 +00:00
attributes.emplace_back(attribute.getName(), toType(attr.value), attribute);
2022-04-05 21:48:07 +00:00
} else {
2022-05-07 11:20:09 +00:00
errors.emplace_back(attr.name.span, "unknown attribute");
2022-04-05 21:48:07 +00:00
}
}
2022-05-07 11:20:09 +00:00
if(secondComponent == nullptr) {
2022-05-07 12:19:43 +00:00
schema->connections.push_back(std::make_shared<BusConnectionInstance>(firstComponent, attributes, bus, *connection));
2022-04-09 17:44:02 +00:00
} else {
2022-05-07 12:19:43 +00:00
schema->connections.push_back(std::make_shared<DirectConnectionInstance>(firstComponent, secondComponent, attributes, bus, *connection));
2022-04-09 17:44:02 +00:00
}
2022-04-05 21:48:07 +00:00
}
return schema;
}
2022-05-07 12:19:43 +00:00
shared_ptr<ComponentInstance> SchemaCreator::loadComponentInstance(InstanceNode instance, Library &library) {
2022-04-05 21:48:07 +00:00
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
2022-05-07 12:19:43 +00:00
std::vector<InstanceAttribute> attributes;
2022-04-05 21:48:07 +00:00
for(auto& attr: instance.attributes) {
if(component.hasAttribute(attr.name.value, toType(attr.value.getType()))) {
auto attribute = component.getAttribute(attr.name.value);
2022-05-15 21:55:03 +00:00
attributes.emplace_back(attribute.getName(), toType(attr.value, attribute.getDefault().getType()), attribute);
2022-04-05 21:48:07 +00:00
} else {
2022-05-07 11:20:09 +00:00
errors.emplace_back(SourceError(attr.name.span, "unknown attribute"));
2022-04-05 21:48:07 +00:00
}
}
2022-05-15 21:55:03 +00:00
if(attributes.size() < component.getAttributes().size()) {
for(auto& attr: component.getAttributes()) {
if(std::count_if(attributes.begin(), attributes.end(), [&attr](InstanceAttribute& attribute){ return attr.getName() == attribute.name; }) == 0) {
errors.emplace_back(SourceError(instance.span, "missing attribute '" + attr.getName() + "'"));
}
}
}
2022-05-07 12:19:43 +00:00
return std::make_shared<ComponentInstance>(name, attributes, position, component);
2022-04-05 21:48:07 +00:00
}
2022-05-07 12:19:43 +00:00
std::shared_ptr<BusInstance> SchemaCreator::loadBusInstance(InstanceNode instance, Library &library) {
2022-04-05 21:48:07 +00:00
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;
}
2022-05-07 12:19:43 +00:00
return std::make_shared<BusInstance>(name, position, bus, static_cast<int>(size));
2022-04-05 21:48:07 +00:00
}
vector<Enumeration> SchemaCreator::createWireEnumeration(vector<Value> wireValues) {
vector<Enumeration> wires;
for(auto& wire: wireValues) {
if(wire.isType(Value::STRING)) {
wires.emplace_back(wire.asString(), wire);
}
}
return wires;
}
2022-05-15 21:55:03 +00:00
std::optional<Attribute> SchemaCreator::createMemoryAttribute() {
return Attribute("_memory", Value::fromMemoryReference(nullopt), createMemoryPopup());
}
std::optional<Popup> SchemaCreator::createMemoryPopup() {
return Popup("Postavi memoriju", "Postavi memoriju za izabrani procesor", Popup::AUTOMATIC, vector<Rule>{}, vector<Enumeration>{});
}
2022-03-31 21:20:41 +00:00
} // namespace domain