446 lines
13 KiB
C++
446 lines
13 KiB
C++
|
#include "comdelgenerator.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;
|
||
|
}
|
||
|
|
||
|
Value::ValueType toType(ValueNode::ValueType type) {
|
||
|
switch (type) {
|
||
|
case ValueNode::BOOL:
|
||
|
return Value::BOOL;
|
||
|
case ValueNode::WIRE:
|
||
|
return Value::WIRE_REFERENCE;
|
||
|
case ValueNode::STRING:
|
||
|
return Value::STRING;
|
||
|
case ValueNode::INT:
|
||
|
return Value::INT;
|
||
|
default:
|
||
|
return Value::UNDEFINED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
Value toType(ValueNode node) {
|
||
|
if(node.getType() == ValueNode::BOOL) {
|
||
|
return Value::fromBool(node.asBool());
|
||
|
} else if(node.getType() == ValueNode::INT) {
|
||
|
return Value::fromInt(node.asInt());
|
||
|
} else if(node.getType() == ValueNode::STRING) {
|
||
|
return Value::fromString(node.asString());
|
||
|
}
|
||
|
return Value::fromReference(node.asIdentifier(), Value::UNDEFINED);
|
||
|
}
|
||
|
|
||
|
|
||
|
Bus::BusType toType(BusNode::BusType type) {
|
||
|
if(type == BusNode::AUTOMATIC) {
|
||
|
return Bus::AUTOMATIC;
|
||
|
}
|
||
|
return Bus::REGULAR;
|
||
|
}
|
||
|
|
||
|
|
||
|
Pin::PinType toType(PinNode::PinType type) {
|
||
|
if(type == PinNode::IN) {
|
||
|
return Pin::IN;
|
||
|
} else if(type == PinNode::OUT) {
|
||
|
return Pin::OUT;
|
||
|
}
|
||
|
return Pin::IN_OUT;
|
||
|
}
|
||
|
|
||
|
PinConnection::ConnectionType toType(PinConnectionNode::ConnectionType type)
|
||
|
{
|
||
|
if(type == PinConnectionNode::AUTOMATICALLY) {
|
||
|
return PinConnection::AUTOMATICALLY;
|
||
|
}
|
||
|
return PinConnection::CHECK_ONLY;
|
||
|
}
|
||
|
|
||
|
|
||
|
Popup::PopupType toType(PopupNode::PopupType type)
|
||
|
{
|
||
|
if(type == PopupNode::AUTOMATIC) {
|
||
|
return Popup::AUTOMATIC;
|
||
|
}
|
||
|
return Popup::ON_DEMAND;
|
||
|
}
|
||
|
|
||
|
ComdelGenerator::ComdelGenerator(std::vector<FunctionSignature> signatures)
|
||
|
: signatures(signatures)
|
||
|
{}
|
||
|
|
||
|
std::optional<Library> ComdelGenerator::loadLibrary(LibraryNode node, ParseContext* parseContext, std::ostream& stream)
|
||
|
{
|
||
|
// library fields
|
||
|
if(!node.name) {
|
||
|
errors.push_back(SourceError{node.span, "missing @name"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
std::string name = node.name->asString();
|
||
|
|
||
|
if(!node.componentDirectory) {
|
||
|
errors.push_back(SourceError{node.span, "missing @componentDirectory"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
std::string componentDirectory = node.componentDirectory->asString();
|
||
|
|
||
|
std::string header = node.header ? node.header->asString() : "";
|
||
|
|
||
|
std::string libraryInfo = node.libraryInfo ? node.libraryInfo->asString() : "";
|
||
|
|
||
|
std::vector<AddressSpace> addressSpaces;
|
||
|
for(auto& as: node.addressSpaces) {
|
||
|
addressSpaces.push_back(*loadAddressSpace(as));
|
||
|
}
|
||
|
|
||
|
std::vector<Component> components;
|
||
|
for(auto& comp: node.components) {
|
||
|
std::optional<Component> component;
|
||
|
component = loadComponent(comp);
|
||
|
if(component) {
|
||
|
components.push_back(*component);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::vector<Connection> connections;
|
||
|
for(uint i=0; i<node.connections.size(); i++) {
|
||
|
auto conn = loadConnection(node.connections[i]);
|
||
|
if(!conn) {
|
||
|
return nullopt;
|
||
|
}
|
||
|
connections.push_back(*conn);
|
||
|
}
|
||
|
|
||
|
std::map<std::string, std::string> messages;
|
||
|
for(uint i=0; i<node.messages.size(); i++) {
|
||
|
if(!node.messages[i].value.is(ValueNode::STRING)) {
|
||
|
errors.push_back(SourceError{node.messages[i].key.span, "expected `string`"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
messages[node.messages[i].key.value] = node.messages[i].value.asString();
|
||
|
}
|
||
|
|
||
|
std::vector<Bus> buses;
|
||
|
for(uint i=0; i<node.buses.size(); i++) {
|
||
|
auto bus = loadBus(node.buses[i]);
|
||
|
if(!bus) {
|
||
|
return nullopt;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Library(name, libraryInfo, header, componentDirectory, addressSpaces, components, buses, connections, messages);
|
||
|
}
|
||
|
|
||
|
std::optional<Bus> ComdelGenerator::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 (min, max) := min <= max && min >= 0"});
|
||
|
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) {
|
||
|
errors.push_back(SourceError{node.span, "automatic bus cannot have a @display"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
|
||
|
|
||
|
optional<Display> display;
|
||
|
if(Bus::REGULAR) {
|
||
|
display = loadDisplay(*node.display);
|
||
|
if(!display) {
|
||
|
return nullopt;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Bus(name, tooltip, type, count, display);
|
||
|
}
|
||
|
|
||
|
|
||
|
std::optional<AddressSpace> ComdelGenerator::loadAddressSpace(AddressSpaceNode node)
|
||
|
{
|
||
|
return AddressSpace(node.name.value, node.start.value, node.end.value);
|
||
|
}
|
||
|
|
||
|
std::optional<Connection> ComdelGenerator::loadConnection(ConnectionNode node)
|
||
|
{
|
||
|
std::string component = node.component.value;
|
||
|
std::string pin = node.pin.value;
|
||
|
std::string bus = node.bus.value;
|
||
|
|
||
|
std::vector<Attribute> attributes;
|
||
|
for(uint i=0; i<node.attributes.size(); i++) {
|
||
|
auto attr = loadAttribute(node.attributes[i]);
|
||
|
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(uint i=0; i<node.wires.size(); i++) {
|
||
|
if(attributeNames.count(node.wires[i].value)) {
|
||
|
wires.push_back(Value::fromReference(node.wires[i].value, Value::ATTRIBUTE_REFERENCE));
|
||
|
} else {
|
||
|
wires.push_back(Value::fromReference(node.wires[i].value, Value::WIRE_REFERENCE));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Connection(component, pin, bus, attributes, wires);
|
||
|
}
|
||
|
|
||
|
std::optional<Component> ComdelGenerator::loadComponent(ComponentNode node)
|
||
|
{
|
||
|
std::string name = node.name.value;
|
||
|
|
||
|
if(!node.tooltip) {
|
||
|
errors.push_back(SourceError{node.span, "missing @tooltip"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
std::string tooltip = node.tooltip->asString();
|
||
|
|
||
|
if(!node.source) {
|
||
|
errors.push_back(SourceError{node.span, "missing @source"});
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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"});
|
||
|
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"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
|
||
|
if(!node.display) {
|
||
|
errors.push_back(SourceError{node.span, "missing @display"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
optional<Display> display = loadDisplay(*node.display);
|
||
|
if(!display) {
|
||
|
return nullopt;
|
||
|
}
|
||
|
|
||
|
std::vector<Pin> pins;
|
||
|
for(uint i=0; i<node.pins.size(); i++) {
|
||
|
auto pin = loadPin(node.pins[i]);
|
||
|
if(!pin) {
|
||
|
return nullopt;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Component(name, tooltip, source, type, rules, instanceName, count, *display, pins, attributes);
|
||
|
}
|
||
|
|
||
|
optional<Pin> ComdelGenerator::loadPin(PinNode node)
|
||
|
{
|
||
|
std::string name = node.name.value;
|
||
|
Pin::PinType type = toType(node.type);
|
||
|
|
||
|
if(!node.tooltip) {
|
||
|
errors.push_back(SourceError{node.span, "missing @tooltip"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
std::string tooltip = node.tooltip->asString();
|
||
|
|
||
|
if(!node.display) {
|
||
|
errors.push_back(SourceError{node.span, "missing @display"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
std::vector<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);
|
||
|
|
||
|
return Pin(name, type, tooltip, connection, *display);
|
||
|
}
|
||
|
|
||
|
|
||
|
std::optional<Display> ComdelGenerator::loadDisplay(DisplayNode node)
|
||
|
{
|
||
|
return Display();
|
||
|
}
|
||
|
|
||
|
|
||
|
PinConnection ComdelGenerator::loadPinConnection(PinConnectionNode node)
|
||
|
{
|
||
|
std::string message = node.message.asString();
|
||
|
PinConnection::ConnectionType type = toType(node.type);
|
||
|
return PinConnection(message, type);
|
||
|
}
|
||
|
|
||
|
std::optional<Attribute> ComdelGenerator::loadAttribute(AttributeNode node)
|
||
|
{
|
||
|
std::string name = node.name.value;
|
||
|
Value value;
|
||
|
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 if (node.type == ValueNode::WIRE) {
|
||
|
value = Value::fromReference(node.defaultValue->asIdentifier(), Value::WIRE_REFERENCE);
|
||
|
}
|
||
|
|
||
|
std::optional<Popup> popup;
|
||
|
if(node.popup) {
|
||
|
popup = loadPopup(*node.popup, name, value.getType());
|
||
|
}
|
||
|
|
||
|
return Attribute(name, value, popup);
|
||
|
}
|
||
|
|
||
|
std::optional<Popup> ComdelGenerator::loadPopup(PopupNode node, std::string name, Value::ValueType type)
|
||
|
{
|
||
|
auto popupType = toType(*node.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<Attribute> attributes;
|
||
|
attributes.push_back(Attribute(name, Value::ofType(type)));
|
||
|
|
||
|
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(toType(node.enumeration[i].value.getType()) != type) {
|
||
|
errors.push_back(SourceError{node.enumeration[i].span, "wrong type"});
|
||
|
return nullopt;
|
||
|
}
|
||
|
enumeration.push_back(Enumeration(node.enumeration[i].key.asString(),
|
||
|
toType(node.enumeration[i].value)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Popup(title, text, popupType, rules, enumeration);
|
||
|
}
|
||
|
|
||
|
std::optional<Rule> ComdelGenerator::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> ComdelGenerator::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(int j=0; j<signatures[i].params[i]; j++) {
|
||
|
params.push_back(toType(node.params[i]));
|
||
|
}
|
||
|
return Condition(function,params, node.negated);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nullopt;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
} // namespace domain
|