Added comments and cleaned up ast nodes and parser

This commit is contained in:
Borna Rajković 2022-06-13 00:48:12 +02:00
parent ae2a3c64ef
commit 1ec0433cfe
17 changed files with 747 additions and 667 deletions

View File

@ -37,5 +37,5 @@ add_executable(SchemeEditor
comdel/parser/comdel_lexer.cpp
main.cpp
mainwindow.ui
comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/single_automatic_dialog.cpp comdel/display/single_automatic_dialog.h comdel/parser/color.cpp comdel/parser/color.h)
comdel/domain/comdel_validator.cpp comdel/domain/comdel_validator.h comdel/display/attribute_dialog.cpp comdel/display/attribute_dialog.h comdel/display/name_dialog.cpp comdel/display/name_dialog.h comdel/domain/comdel_generator.cpp comdel/domain/comdel_generator.h comdel/display/library_list.cpp comdel/display/library_list.h application.cpp application.h comdel/display/single_automatic_dialog.cpp comdel/display/single_automatic_dialog.h comdel/parser/color.h)
target_link_libraries(SchemeEditor Qt5::Core Qt5::Gui Qt5::Widgets)

View File

@ -90,7 +90,7 @@ std::pair<bool, std::vector<domain::ValidationError>> Application::loadSchema(st
}
} else {
errorOutput << "Failed parsing library" << std::endl;
errorOutput << "Failed schema library" << std::endl;
return {false, errors};
}

View File

@ -82,11 +82,11 @@ namespace domain {
for (auto &inst: schema.componentInstances) {
for (auto &pin: inst->component.getPins()) {
if (pin.getConnection().getType() == PinConnection::REQUIRED) {
if (pin.getConnection().has_value()) {
if (!connectionExists(schema, inst, pin)) {
context.instance = inst.get();
context.attributes["instanceName"] = Value::fromString(inst->name);
auto message = populateMessage(pin.getConnection().getMessage(), context);
auto message = populateMessage(pin.getConnection().value(), context);
errors.emplace_back(Action::ERROR, message);
}
}

View File

@ -2,19 +2,7 @@
namespace domain {
PinConnection::PinConnection(std::string message, ConnectionType type)
: message(message), type(type) {}
PinConnection::ConnectionType PinConnection::getType() {
return type;
}
std::string PinConnection::getMessage() {
return message;
}
Pin::Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin,
Pin::Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin,
std::optional<std::vector<Value>> wires)
: name(name), type(type), tooltip(tooltip), connection(connection), displayPin(pin), wires(wires) {}
@ -34,7 +22,7 @@ namespace domain {
return displayPin;
}
PinConnection &Pin::getConnection() {
std::optional<std::string> Pin::getConnection() {
return connection;
}

View File

@ -9,25 +9,6 @@
namespace domain {
class PinConnection {
public:
enum ConnectionType {
REQUIRED,
OPTIONAL
};
private:
std::string message;
ConnectionType type;
public:
PinConnection(std::string message, ConnectionType type);
ConnectionType getType();
std::string getMessage();
};
class Pin {
public:
enum PinType {
@ -40,13 +21,13 @@ namespace domain {
std::string name;
PinType type;
std::string tooltip;
PinConnection connection;
std::optional<std::string> connection;
domain::ui::Pin displayPin;
std::optional<std::vector<Value>> wires;
public:
Pin(std::string name, PinType type, std::string tooltip, PinConnection connection, domain::ui::Pin pin,
Pin(std::string name, PinType type, std::string tooltip, std::optional<std::string> connection, domain::ui::Pin pin,
std::optional<std::vector<Value>> wires);
std::string &getName();
@ -57,7 +38,7 @@ namespace domain {
ui::Pin &getDisplayPin();
PinConnection &getConnection();
std::optional<std::string> getConnection();
std::optional<std::vector<Value>> &getWires();
};

View File

@ -81,20 +81,20 @@ namespace domain {
Value toType(ValueNode node, Value::ValueType type = Value::ValueType::UNDEFINED) {
if (type == Value::MEMORY_REFERENCE) {
if (node.getType() == ValueNode::NIL) {
if (node.is(ValueNode::NIL)) {
return Value::fromMemoryReference(nullopt);
} else {
return Value::fromMemoryReference(node.asIdentifier());
}
}
if (node.getType() == ValueNode::BOOL) {
if (node.is(ValueNode::BOOL)) {
return Value::fromBool(node.asBool());
} else if (node.getType() == ValueNode::INT) {
} else if (node.is(ValueNode::INT)) {
return Value::fromInt(node.asInt());
} else if (node.getType() == ValueNode::STRING) {
} else if (node.is(ValueNode::STRING)) {
return Value::fromString(node.asString());
} else if (node.getType() == ValueNode::NIL) {
} else if (node.is(ValueNode::NIL)) {
return Value::fromNull();
}
return Value::fromReference(node.asIdentifier(), Value::UNDEFINED);
@ -120,14 +120,6 @@ namespace domain {
return Pin::IN_OUT;
}
PinConnection::ConnectionType toType(PinConnectionNode::ConnectionType type) {
if (type == PinConnectionNode::OPTIONAL) {
return PinConnection::OPTIONAL;
}
return PinConnection::REQUIRED;
}
Popup::PopupType toType(PopupNode::PopupType type) {
if (type == PopupNode::AUTOMATIC) {
return Popup::AUTOMATIC;
@ -274,7 +266,7 @@ namespace domain {
std::optional<AddressSpace> SchemaCreator::loadAddressSpace(AddressSpaceNode node) {
return AddressSpace(node.name.value, node.start.value, node.end.value);
return AddressSpace(node.name.value, node.range.first.value, node.range.second.value);
}
std::optional<Connection> SchemaCreator::loadConnection(ConnectionNode node) {
@ -584,12 +576,10 @@ namespace domain {
}
ui::Pin displayPin = *display->getItems()[0].pin;
if (!node.connection) {
errors.emplace_back(node.span, "missing @connection");
return nullopt;
std::optional<std::string> connection = std::nullopt;
if (node.connection) {
connection = node.connection->asString();
}
auto connection = loadPinConnection(*node.connection);
std::optional<std::vector<Value>> wiresOpt = std::nullopt;
if (node.wires.has_value()) {
@ -610,47 +600,74 @@ namespace domain {
return Pin(pinName, type, tooltip, connection, displayPin, wiresOpt);
}
Color readColor(std::vector<SourceError>& errors, DisplayItemNode& item, std::string property, Color _default) {
auto color = item.asColor(property, _default);
if(!color.has_value()) {
errors.emplace_back(item.span, "expected color");
return _default;
}
return *color;
}
std::string readString(std::vector<SourceError>& errors, DisplayItemNode& item, std::string property, std::string _default = "") {
auto value = item.asString(property, _default);
if(!value.has_value()) {
errors.emplace_back(item.span, "expected string");
return _default;
}
return *value;
}
long long int readInt(std::vector<SourceError>& errors, DisplayItemNode& item, std::string property, long long int _default = 0) {
auto value = item.asInt(property, _default);
if(!value.has_value()) {
errors.emplace_back(item.span, "expected int");
return _default;
}
return *value;
}
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;
auto fillColor = item.asColor(&errors, "fillColor", Color(255, 255, 255, 255));
auto lineColor = item.asColor(&errors, "lineColor", Color(0, 0, 0, 255));
auto fillColor = readColor(errors, item, "fillColor", Color(255, 255, 255, 255));
auto lineColor = readColor(errors, item, "lineColor", Color(0, 0, 0, 255));
if (type == "text") {
long long int x, y, w, h;
std::string text;
auto color = item.asColor(&errors, "color", Color(0, 0, 0, 255));
x = item.asInt(&errors, "x");
y = item.asInt(&errors, "y");
w = item.asInt(&errors, "w");
h = item.asInt(&errors, "h");
text = item.asString(&errors, "text");
auto color = readColor(errors, item, "color", Color(0, 0, 0, 255));
x = readInt(errors, item, "x");
y = readInt(errors, item, "y");
w = readInt(errors, item, "w");
h = readInt(errors, item, "h");
text = readString(errors, item, "text");
displayItem.text = ui::Text(x, y, w, h, text, color);
} else if (type == "rect") {
long long int x, y, w, h;
x = item.asInt(&errors, "x");
y = item.asInt(&errors, "y");
w = item.asInt(&errors, "w");
h = item.asInt(&errors, "h");
x = readInt(errors, item, "x");
y = readInt(errors, item, "y");
w = readInt(errors, item, "w");
h = readInt(errors, item, "h");
displayItem.rect = ui::Rect(x, y, w, h, {lineColor, fillColor});
} else if (type == "line") {
long long int x1, y1, x2, y2;
x1 = item.asInt(&errors, "x1");
y1 = item.asInt(&errors, "y1");
x2 = item.asInt(&errors, "x2");
y2 = item.asInt(&errors, "y2");
x1 = readInt(errors, item, "x1");
y1 = readInt(errors, item, "y1");
x2 = readInt(errors, item, "x2");
y2 = readInt(errors, item, "y2");
displayItem.line = ui::Line(x1, y1, x2, y2, {lineColor, fillColor});
} else if (type == "pin") {
long long int x, y, w, h;
x = item.asInt(&errors, "x");
y = item.asInt(&errors, "y");
w = item.asInt(&errors, "w");
h = item.asInt(&errors, "h");
std::string _orientation = item.asString(&errors, "orientation", "bottom");
std::string _pinType = item.asString(&errors, "type", "out");
x = readInt(errors, item, "x");
y = readInt(errors, item, "y");
w = readInt(errors, item, "w");
h = readInt(errors, item, "h");
std::string _orientation = readString(errors, item, "orientation", "bottom");
std::string _pinType = readString(errors, item, "type", "out");
ui::PinOrientation orientation;
if (_orientation == "left") {
@ -679,11 +696,11 @@ namespace domain {
displayItem.pin = ui::Pin(x, y, w, h, orientation, pinType, {lineColor, fillColor});
} else if (type == "bus") {
long long int x, y, w, h;
x = item.asInt(&errors, "x");
y = item.asInt(&errors, "y");
w = item.asInt(&errors, "w");
h = item.asInt(&errors, "h");
std::string _orientation = item.asString(&errors, "orientation", "bottom");
x = readInt(errors, item, "x");
y = readInt(errors, item, "y");
w = readInt(errors, item, "w");
h = readInt(errors, item, "h");
std::string _orientation = readString(errors, item, "orientation", "bottom");
ui::BusOrientation orientation;
if (_orientation == "horizontal") {
@ -703,13 +720,6 @@ namespace domain {
return Display(items);
}
PinConnection SchemaCreator::loadPinConnection(PinConnectionNode node) {
std::string message = node.message.asString();
PinConnection::ConnectionType type = toType(node.type.value);
return {message, type};
}
std::optional<Attribute> SchemaCreator::loadAttribute(AttributeNode node) {
std::string name = node.name.value;
pushAdditional(name);

View File

@ -58,8 +58,6 @@ namespace domain {
std::optional<Wire> loadWire(WireNode node);
std::optional<Pin> loadPin(PinNode pins);
PinConnection loadPinConnection(PinConnectionNode node);
std::optional<Connection> loadConnection(ConnectionNode node);
std::optional<Bus> loadBus(BusNode node);

View File

@ -1,9 +1,5 @@
#include "ast_nodes.h"
/*************************** AST NODE ********************************/
AstNode::~AstNode() = default;
/*************************** NUMBER NODE ********************************/
NumberNode::NumberNode(const std::string &expression) {
@ -41,7 +37,11 @@ std::string StringNode::asString() {
/*************************** VALUE NODE ********************************/
long long ValueNode::asInt() {
ValueNode::ValueType ValueNode::getType() const {
return type.value;
}
long long int ValueNode::asInt() {
if (is(INT)) {
return intValue.value();
}
@ -135,3 +135,38 @@ ValueNode ValueNode::ofMemory(std::optional<std::string> _value) {
value.identifierValue = _value;
return value;
}
/*************************** DisplayItem NODE ********************************/
std::optional<long long int> DisplayItemNode::asInt(const std::string &property, long long int _default) {
auto prop = getProperty(property);
if(prop.has_value()) {
return prop->value.is(ValueNode::INT) ? std::optional(prop->value.asInt()) : std::nullopt;
}
return _default;
}
std::optional<Color> DisplayItemNode::asColor(const std::string &property, Color _default) {
auto prop = getProperty(property);
if(prop.has_value()) {
return prop->value.is(ValueNode::COLOR) ? std::optional(prop->value.asColor()) : std::nullopt;
}
return _default;
}
std::optional<std::string> DisplayItemNode::asString(const std::string &property, std::string _default) {
auto prop = getProperty(property);
if(prop.has_value()) {
return prop->value.is(ValueNode::STRING) ? std::optional(prop->value.asString()) : std::nullopt;
}
return _default;
}
std::optional<PropertyNode> DisplayItemNode::getProperty(const std::string &property) {
for(auto &prop: values) {
if(prop.key.value == property) {
return prop;
}
}
return std::nullopt;
}

View File

@ -8,28 +8,30 @@
#include <utility>
#include <vector>
/*****************************************************************************
* BASE TYPES *
*****************************************************************************/
/**
* AST base class, all AST node classes extend this class. Class contains basic
* information about nodes location in file.
*/
class AstNode {
public:
/** Contains information about where in source file given node is located */
Span span;
AstNode() = default;
virtual ~AstNode();
AstNode(AstNode &&) = default;
AstNode &operator=(AstNode &&) = default;
AstNode(const AstNode &) = default;
AstNode &operator=(const AstNode &) = default;
};
/**
* AST base enum class,
* Used to represent AST enums
* */
template<typename T>
struct EnumNode : public AstNode {
EnumNode() = default;
@ -39,284 +41,416 @@ struct EnumNode : public AstNode {
T value;
};
/** Represents string
* value contains quote-marks ("" or '' depending on string type)
* */
struct StringNode : public AstNode {
/** String including quote-marks*/
std::string value;
/** Returns string without quote-marks */
std::string asString();
};
/** Represents identifiers */
struct IdentifierNode : public AstNode {
std::string value;
};
/** Represents all numbers used
* All numbers must fit into long long int
* */
struct NumberNode : public AstNode {
long long int value;
long long int value = 0;
explicit NumberNode(const std::string &expression);
NumberNode() : value(0) {}
NumberNode() = default;
};
/** Represents color
* color comes in two formats #RRGGBB or #RRGGBBAA (AA representing opacity)
* */
struct ColorNode : public AstNode {
Color color;
explicit ColorNode(const std::string &expression);
ColorNode() {}
ColorNode() = default;
};
struct CountNode : public AstNode {
/** Represents ordered number pair */
struct NumberPairNode : public AstNode {
NumberNode first;
NumberNode second;
CountNode(NumberNode first, NumberNode second) : first(std::move(first)), second(std::move(second)) {}
NumberPairNode(NumberNode first, NumberNode second) : first(first), second(second) {}
CountNode() = default;
};
struct AddressSpaceNode : public AstNode {
IdentifierNode name;
NumberNode start;
NumberNode end;
NumberPairNode() = default;
};
/** Represents generic value
* Because attributes can contain different value types,
* this allows us to use one generic type for all attributes
* */
class ValueNode : public AstNode {
public:
enum ValueType {
/** Stores same content as NumberNode */
INT,
/** Stores same content as StringNode */
STRING,
/** Stores true or false */
BOOL,
/** Stores wire nam or null */
WIRE,
/** Default type assigned when node value is of type IdentifierNode and more correct type is assigned later */
IDENTIFIER,
/** Stores memory name or null */
MEMORY,
/** Stores null */
NIL,
/** Store same content as ColorNode */
COLOR,
};
private:
EnumNode<ValueType> type;
std::optional<long long> intValue;
std::optional<std::string> stringValue;
std::optional<bool> boolValue;
std::optional<std::string> identifierValue;
std::optional<Color> colorValue;
/** Type determines what is stored inside ValueNode */
EnumNode<ValueType> type = EnumNode(NIL);
/** All possible values for ValueNode are stored inside optionals */
std::optional<long long> intValue = std::nullopt;
std::optional<std::string> stringValue = std::nullopt;
std::optional<bool> boolValue = std::nullopt;
std::optional<std::string> identifierValue = std::nullopt;
std::optional<Color> colorValue = std::nullopt;
public:
ValueNode() = default;
ValueType getType() const {
return type.value;
}
long long asInt();
ValueType getType() const;
/** Checks ValueNode is of requested type and returns it or returns default value for given type*/
long long int asInt();
std::string asString();
std::string asIdentifier();
Color asColor();
bool asBool();
/** Returns true if ValueNode is of given valueType */
bool is(ValueType valueType);
/** Static methods used to generate ValueNodes of requested type */
static ValueNode ofBool(bool _value);
static ValueNode ofInt(long long _value);
static ValueNode ofString(std::string _value);
static ValueNode ofIdentifier(std::string _value);
static ValueNode ofMemory(std::optional<std::string> _value);
static ValueNode ofNull();
static ValueNode ofColor(Color color);
static ValueNode ofWire(std::optional<std::string> _value);
};
/** Represents an identifier-value pair*/
struct PropertyNode : public AstNode {
IdentifierNode key;
ValueNode value;
PropertyNode() = default;
PropertyNode(IdentifierNode key, ValueNode value): key(key), value(value) {}
};
/** Represents a string-value pair */
struct StringPropertyNode : public AstNode {
StringNode key;
ValueNode value;
StringPropertyNode() = default;
StringPropertyNode(StringNode key, ValueNode value): key(key), value(value) {}
};
/*****************************************************************************
* RULE TYPES *
*****************************************************************************/
struct IfStatementNode;
/** Represents validation rule
* Rules are made from a list of
* if - else if statements
* */
struct RuleNode : public AstNode {
std::vector<IfStatementNode> statements;
};
/** Represents condition inside if statement
* Every condition is made from optional negation operator !
* Function called and list of function parameters
* */
struct ConditionNode {
bool negated;
IdentifierNode functionName;
std::vector<ValueNode> params;
};
class ActionNode : public AstNode {
public:
/** Represents action executed inside if statement
* */
struct ActionNode : public AstNode {
/** There are two types of action determined by action type */
enum ActionType {
/** Error actions represent invalid state and cause validation to fail */
ERROR,
/** Warning actions represent states that can cause issue when simulating
* model but models created with it are still valid
* */
WARNING
};
EnumNode<ActionType> type;
/** Message used if condition is fulfilled */
StringNode message;
};
/** If statements represents one validation check inside rule */
struct IfStatementNode : public AstNode {
ConditionNode condition;
ActionNode action;
};
struct RuleNode : public AstNode {
std::vector<IfStatementNode> statements;
};
struct EnumerationNode : public AstNode {
StringNode key;
ValueNode value;
};
/*****************************************************************************
* ATTRIBUTE TYPES *
*****************************************************************************/
/** Represents popup dialog used to modified attribute inside which it is defined
* */
struct PopupNode : public AstNode {
/** Determines type of popup*/
enum PopupType {
/** Automatic popup is opened when component or connection containing it is defined */
AUTOMATIC,
/** On demand popups are opened on user request usually from context menus*/
ON_DEMAND
};
std::optional<EnumNode<PopupType>> type;
/** Title of popup */
std::optional<StringNode> title;
/** Text of popup */
std::optional<StringNode> text;
/** If popup contains an enumeration*/
bool enumerated;
std::vector<EnumerationNode> enumeration;
std::vector<StringPropertyNode> enumeration;
/** Validation rules for given popup */
std::vector<RuleNode> rules;
};
struct PropertyNode : public AstNode {
IdentifierNode key;
ValueNode value;
/** Represents component or connection attribute
* Attributes are values that can programmatically be changed
* if popup is defined
* */
struct AttributeNode : public AstNode {
/** Type of attribute */
ValueNode::ValueType type;
/** Name of attribute */
IdentifierNode name;
/** Default type of attribute */
std::optional<ValueNode> defaultValue;
/** Popup used to change attribute value */
std::optional<PopupNode> popup;
};
struct DisplayItemNode : public AstNode {
IdentifierNode type;
std::vector<PropertyNode> values;
/*****************************************************************************
* DISPLAY TYPES *
*****************************************************************************/
long long int asInt(std::vector<SourceError> *errors, const std::string &property, long long int _default = 0) {
for (auto &prop: values) {
if (prop.key.value == property) {
if (prop.value.is(ValueNode::INT)) {
return prop.value.asInt();
} else {
if (errors != nullptr) {
errors->emplace_back(prop.value.span, "expected number");
}
}
}
}
return _default;
}
Color asColor(std::vector<SourceError> *errors, const std::string &property, Color _default = Color(0, 0, 0)) {
for (auto &prop: values) {
if (prop.key.value == property) {
if (prop.value.is(ValueNode::COLOR)) {
return prop.value.asColor();
} else {
if (errors != nullptr) {
errors->emplace_back(prop.value.span, "expected number");
}
}
}
}
return _default;
}
std::string asIdentifier(std::vector<SourceError> *errors, const std::string &property, std::string _default = "") {
for (auto &prop: values) {
if (prop.key.value == property) {
if (prop.value.is(ValueNode::IDENTIFIER)) {
return prop.value.asIdentifier();
} else {
if (errors != nullptr) {
errors->emplace_back(prop.value.span, "expected identifier");
}
}
}
}
return _default;
}
std::string asString(std::vector<SourceError> *errors, const std::string &property, std::string _default = "") {
for (auto &prop: values) {
if (prop.key.value == property) {
if (prop.value.is(ValueNode::STRING)) {
return prop.value.asString();
} else {
if (errors != nullptr) {
errors->emplace_back(prop.value.span, "expected string");
}
}
}
}
return _default;
}
};
struct DisplayItemNode;
/** Represents how a component or bus is rendered
* Display is made from an list of display items
* */
struct DisplayNode : public AstNode {
std::vector<DisplayItemNode> items;
};
struct PinConnectionNode : public AstNode {
enum ConnectionType {
REQUIRED,
OPTIONAL
/** DisplayItem represents one rendered item
* in source code items are defined similar to json objects
* eg.
* @code rect {
* x: 100;
* y: 100;
* w: 100;
* h: 100;
* fillColor: #123456
* }
* */
struct DisplayItemNode : public AstNode {
/** Contains type of display item */
IdentifierNode type;
/** Contains all property nodes */
std::vector<PropertyNode> values;
/** Returns value of requested property
* If requested property doesn't exists default value is returned (eg. asInt is called but PropertyNode contains string)
* If value of requested property is different than expected nullopt is retured
* */
std::optional<long long int> asInt(const std::string &property, long long int _default = 0);
std::optional<Color> asColor(const std::string &property, Color _default = Color(0, 0, 0));
std::optional<std::string> asString(const std::string &property, std::string _default = "");
private:
std::optional<PropertyNode> getProperty(const std::string &property);
};
StringNode message;
EnumNode<ConnectionType> type;
/*****************************************************************************
* LIBRARY TYPES *
*****************************************************************************/
/** Represents AddressSpaces
* Address spaces are defined with their name and address range
* */
struct AddressSpaceNode : public AstNode {
IdentifierNode name;
/** Range represent which addresses are available for components that use memory space [first, second> */
NumberPairNode range;
};
/** Pins are used to create component-component or component-bus connections */
struct PinNode : public AstNode {
/** Determines pin type, pin types currently only affect how pins are rendered */
enum PinType {
IN_OUT,
IN,
OUT
};
/** Name of pin */
IdentifierNode name;
/** Type of pin */
EnumNode<PinType> type;
/** Tooltip content displayed on hover over pin */
std::optional<StringNode> tooltip;
std::optional<PinConnectionNode> connection;
/** If present this means pin must be connected to another component or bus to create connection
* Connection contains error message shown
* */
std::optional<StringNode> connection;
/** Determines how the pin is displayed */
std::optional<DisplayNode> display;
/** If pin connection is optional it requires list of wires used to populate comdel model */
std::optional<std::vector<ValueNode>> wires;
};
/**
* Represents COMDEL component
* */
struct ComponentNode : public AstNode {
/** Determines type of component */
enum ComponentType {
/** Generic component */
OTHER,
/** Represents processor, all processors have implicit attribute _memory if type memory
* used when generating COMDEL model to connect memories and processors
*/
PROCESSOR,
/** Represents memory, all components of type memory can be selected in _memory attribute of processor */
MEMORY
};
/** Component name */
IdentifierNode name;
/** Tooltip displayed on hover */
std::optional<StringNode> tooltip;
/** Contains path to COMDEL source containing current component */
std::optional<StringNode> source;
/** Type of component */
EnumNode<ComponentType> type;
/** List of component level rules */
std::vector<RuleNode> rules;
/** Default used to name instances */
std::optional<IdentifierNode> instanceName;
/** Count determines number of instances allowed in a schema */
std::optional<NumberPairNode> count;
/** Display determines how component is rendered */
std::optional<DisplayNode> display;
/** List of all pins */
std::vector<PinNode> pins;
/** List of all attributes */
std::vector<AttributeNode> attributes;
};
/** WireNode represents COMDEL wire
* */
struct WireNode : public AstNode {
/** Determines type of wires */
enum WireType {
/** Generic wire */
WIRE,
/** wired_and can have multiple sources, that are ANDed together */
WIRED_AND,
/** wired_and can have multiple sources, that are ORed together */
WIRED_OR,
/** r_wire can remain unconnected */
R_WIRE
};
EnumNode<WireType> type;
/** Name of wire */
IdentifierNode name;
/** Number of bits inside of a wire */
NumberNode size;
/** If wire is visible or hidden, this determines how wires are generated in COMDEL */
bool hidden = false;
/** If wire isn't connected to anything it is replaced with terminate with terminateWith value */
bool hasTerminateWith;
ValueNode terminateWith;
};
struct AttributeNode : public AstNode {
ValueNode::ValueType type;
IdentifierNode name;
std::optional<ValueNode> defaultValue;
std::optional<PopupNode> popup;
/** Buses dont exist in COMDEL but they are useful
* as they allow us to connect multiple COMDEL wires together
* */
struct BusNode : public AstNode {
enum BusType {
/** This busses connect two components */
AUTOMATIC,
/**
* This busses allow us to connect multiple component together using one bus
* */
REGULAR,
/** This busses connect two components,
* they differ from automatic as they allow us to connect same pins multiple times */
SINGLE_AUTOMATIC
};
EnumNode<BusType> type;
IdentifierNode name;
/** Default used to name instances */
std::optional<IdentifierNode> instanceName;
/** Tooltip displayed on hover */
std::optional<StringNode> tooltip;
/** Count determines number of instances allowed in a schema */
std::optional<NumberPairNode> count;
/** Display determines how component is rendered */
std::optional<DisplayNode> display;
/** List of all COMDEL wires contained in bus */
std::vector<WireNode> wires;
};
/** Represents ComponentConnection key in Connection node
* (eg. componentName.pinName)
* */
struct ConnectionComponentNode : public AstNode {
IdentifierNode component;
IdentifierNode pin;
};
/** Represents Connection node
* Connection can be between component and bus in which second is null,
* or between two components
* */
struct ConnectionNode : public AstNode {
ConnectionComponentNode first;
std::optional<ConnectionComponentNode> second;
@ -324,51 +458,22 @@ struct ConnectionNode : public AstNode {
IdentifierNode bus;
std::vector<AttributeNode> attributes;
/** If connection is of type component-component it contains two pairs of wires */
std::vector<ValueNode> firstWires;
std::optional<std::vector<ValueNode>> secondWires;
};
struct ComponentNode : public AstNode {
enum ComponentType {
OTHER,
PROCESSOR,
MEMORY
};
IdentifierNode name;
std::optional<StringNode> tooltip;
std::optional<StringNode> source;
EnumNode<ComponentType> type;
std::vector<RuleNode> rules;
std::optional<IdentifierNode> instanceName;
std::optional<CountNode> count;
std::optional<DisplayNode> display;
std::vector<PinNode> pins;
std::vector<AttributeNode> attributes;
};
struct BusNode : public AstNode {
enum BusType {
AUTOMATIC,
REGULAR,
SINGLE_AUTOMATIC
};
EnumNode<BusType> type;
IdentifierNode name;
std::optional<IdentifierNode> instanceName;
std::optional<StringNode> tooltip;
std::optional<CountNode> count;
std::optional<DisplayNode> display;
std::vector<WireNode> wires;
};
/** LibraryNode represent library instance */
struct LibraryNode : public AstNode {
/** Name of library */
std::optional<StringNode> name;
/** Library info contains generic information about library */
std::optional<StringNode> libraryInfo;
/** Contains text that is added to top of COMDEL file */
std::optional<StringNode> header;
/** Contains path to component directory */
std::optional<StringNode> componentDirectory;
/** Contains text that is added to top of System component in COMDEL file */
std::optional<StringNode> componentHeader;
std::vector<AddressSpaceNode> addressSpaces;
@ -377,46 +482,64 @@ struct LibraryNode : public AstNode {
std::vector<BusNode> buses;
std::vector<ConnectionNode> connections;
/** Contains properties used to translate dialog and error messages */
std::vector<PropertyNode> messages;
};
// SCHEMA models
/*****************************************************************************
* LIBRARY TYPES *
*****************************************************************************/
/** Represents instance of attribute in component or connection instance */
struct InstanceAttributeNode : public AstNode {
IdentifierNode name;
ValueNode value;
};
/** Represents instance of a component or a bus */
struct InstanceNode : public AstNode {
/** Contains instance name */
IdentifierNode name;
/** Contains component name */
IdentifierNode component;
std::optional<CountNode> position;
/** Contains position of component instance */
std::optional<NumberPairNode> position;
std::vector<InstanceAttributeNode> attributes;
/** Contains size of bus instances */
std::optional<NumberNode> size;
};
struct ConnectionComponentInstance : public AstNode {
/** Represents ComponentConnection of a selected instance */
struct ConnectionComponentInstanceNode : public AstNode {
/** Name of component instance */
IdentifierNode instance;
/** Name of pin */
IdentifierNode pin;
};
/** Represents Connection instance */
struct ConnectionInstanceNode : public AstNode {
ConnectionComponentInstance first;
std::optional<ConnectionComponentInstance> second;
ConnectionComponentInstanceNode first;
std::optional<ConnectionComponentInstanceNode> second;
IdentifierNode bus;
std::vector<InstanceAttributeNode> attributes;
};
/** Represent schema instance */
struct SchemaNode : public AstNode {
/** Contains path to library source */
std::optional<StringNode> source;
/** Contains list of instances */
std::vector<InstanceNode> instances;
/** Contains list of connection */
std::vector<ConnectionInstanceNode> connections;
/** Contains library */
std::optional<LibraryNode> library;
};

View File

@ -1,5 +0,0 @@
//
// Created by bbr on 12.06.22..
//
#include "color.h"

View File

@ -7,12 +7,12 @@
struct Color {
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
unsigned char r = 0;
unsigned char g = 0;
unsigned char b = 0;
unsigned char a = 255;
Color(): r(0), g(0), b(0), a(0) {}
Color() = default;
Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0): r(r), g(g), b(b), a(a) {}
};

View File

@ -11,11 +11,14 @@
#include <string>
#include <vector>
/** Contains results of tokenizing,
* if errors isn't empty tokenizing has failed */
struct LexerResult {
std::vector<Token> tokens;
std::vector<SourceError> errors;
};
/** Used to tokenize input string */
class ComdelLexer {
enum Radix {
@ -24,9 +27,11 @@ class ComdelLexer {
HEX_NUMBER = 16
};
/** Source file */
std::string source;
std::vector<Token> tokens;
std::vector<SourceError> errors;
/** Source file */
ParseContext *parseContext;
unsigned fileId;
@ -36,34 +41,32 @@ public:
LexerResult tokenize();
private:
void skipWhitespace();
unsigned takeNumberInRadix(Radix radix);
unsigned takeHexColor();
bool digitIsValid(char ch, Radix radix);
Radix takeRadix();
PResult<TokenType> nextTokenType();
/** Current parsing info */
Position tokenBegin;
Position position;
char ch;
/** Methods used to skip unused content */
void skipWhitespace();
void skipComment();
bool skipMultilineComment();
void bump(unsigned count = 1);
/** Metods used for number parsing */
unsigned takeNumberInRadix(Radix radix);
bool digitIsValid(char ch, Radix radix);
Radix takeRadix();
unsigned takeHexColor();
PResult<TokenType> nextTokenType();
PResult<TokenType> takeString();
PResult<TokenType> takeRawString();
void bump(unsigned count = 1);
char peek();
/** Checks if we reached end of file */
bool eof();
};

View File

@ -223,6 +223,22 @@ Spanner ComdelParser::getSpanner() {
*
****************************************************************************/
/****************************************************************************
*
* ComponentNode :=
* "@name" + StringNode
* "@header" + StringNode
* "@componentHeader" + StringNode
* "@directory" + StringNode
* "@info" + StringNode
* [AddressSpaceNode]{0..N}
* [ComponentNode]{0..N}
* [BusNode]{0..N}
* [ConnectionNode]{0..N}
* @messages "{" + PropertyNode{0..N} + "}"
*
****************************************************************************/
std::optional<LibraryNode> ComdelParser::parseLibrary() {
auto spanner = getSpanner();
@ -230,20 +246,15 @@ std::optional<LibraryNode> ComdelParser::parseLibrary() {
while (!check(TokenType::END_OF_FILE)) {
PResult<poly<AstNode>> err;
if (check(TokenType::KW_NAME)) {
bump();
if (consume(TokenType::KW_NAME)) {
ASSIGN_OR_SET_ERR(library.name, parseString());
} else if (check(TokenType::KW_HEADER)) {
bump();
} else if (consume(TokenType::KW_HEADER)) {
ASSIGN_OR_SET_ERR(library.header, parseString());
} else if (check(TokenType::KW_COMPONENT_HEADER)) {
bump();
} else if (consume(TokenType::KW_COMPONENT_HEADER)) {
ASSIGN_OR_SET_ERR(library.componentHeader, parseString());
} else if (check(TokenType::KW_DIRECTORY)) {
bump();
} else if (consume(TokenType::KW_DIRECTORY)) {
ASSIGN_OR_SET_ERR(library.componentDirectory, parseString());
} else if (check(TokenType::KW_INFO)) {
bump();
} else if (consume(TokenType::KW_INFO)) {
ASSIGN_OR_SET_ERR(library.libraryInfo, parseString());
} else if (check(TokenType::KW_ADDRESS)) {
APPEND_OR_SET_ERR(library.addressSpaces, parseAddress());
@ -253,8 +264,7 @@ std::optional<LibraryNode> ComdelParser::parseLibrary() {
APPEND_OR_SET_ERR(library.buses, parseBus());
} else if (check(TokenType::KW_CONNECTION)) {
APPEND_OR_SET_ERR(library.connections, parseConnection());
} else if (check(TokenType::KW_MESSAGES)) {
bump();
} else if (consume(TokenType::KW_MESSAGES)) {
ASSIGN_OR_SET_ERR(library.messages, parseList<PropertyNode>(TokenType::LBRACE,
TokenType::RBRACE,
std::nullopt,
@ -284,7 +294,7 @@ std::optional<LibraryNode> ComdelParser::parseLibrary() {
/****************************************************************************
*
* StringNode := "\"" + CONTENT + "\""
* StringNode := ('"' + TEXT + '"' | "'" + TEXT + "'")
*
****************************************************************************/
PResult<StringNode> ComdelParser::parseString() {
@ -292,17 +302,15 @@ PResult<StringNode> ComdelParser::parseString() {
if (check(TokenType::STRING)) {
StringNode node;
node.value = current().text;
node.span = current().span;
bump();
return spanner(node);
}
return unexpected();
}
/****************************************************************************
*
* ColorNode := #RRGGBB[AA]
* ColorNode := '#' + [0-9A-Fa-f]{6,8}
*
****************************************************************************/
PResult<ColorNode> ComdelParser::parseColor() {
@ -319,7 +327,7 @@ PResult<ColorNode> ComdelParser::parseColor() {
/****************************************************************************
*
* IdentifierNode := IDENTIFIER
* IdentifierNode := [_a-zA-Z][_a-zA-Z0-9]*
*
****************************************************************************/
PResult<IdentifierNode> ComdelParser::parseIdentifier() {
@ -327,7 +335,6 @@ PResult<IdentifierNode> ComdelParser::parseIdentifier() {
if (check(TokenType::IDENTIFIER)) {
IdentifierNode node;
node.value = current().text;
node.span = current().span;
bump();
return spanner(node);
}
@ -350,16 +357,14 @@ PResult<NumberNode> ComdelParser::parseNumber() {
return unexpected();
}
/****************************************************************************
*
* CountNode := "@size (" + NumberNode + "," + NumberNode + ")"
* NumberPairNode := '(' + NumberNode + ',' + NumberNode + ')'
*
****************************************************************************/
PResult<CountNode> ComdelParser::parseCount() {
auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_COUNT);
PResult<NumberPairNode> ComdelParser::parseNumberPair() {
auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
auto first = parseNumber();
if (!first.has_value()) {
@ -372,12 +377,41 @@ PResult<CountNode> ComdelParser::parseCount() {
}
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
return spanner(CountNode{first.value(), second.value()});
return spanner(NumberPairNode{*first, *second});
}
/****************************************************************************
*
* PropertyNode := key: value;
* ValueNode := (IdentifierNode | NumberNode | ColorNode | "NULL" | "true" | "false")
*
****************************************************************************/
PResult<ValueNode> ComdelParser::parseValue() {
auto spanner = getSpanner();
ValueNode value;
if (check(TokenType::IDENTIFIER)) {
value = ValueNode::ofIdentifier(parseIdentifier()->value);
} else if (check(TokenType::STRING)) {
value = ValueNode::ofString(parseString()->asString());
} else if (check(TokenType::NUMBER)) {
value = ValueNode::ofInt(parseNumber()->value);
} else if (consume(TokenType::TRUE)) {
value = ValueNode::ofBool(true);
} else if (consume(TokenType::FALSE)) {
value = ValueNode::ofBool(false);
} else if (consume(TokenType::NIL)) {
value = ValueNode::ofNull();
} else if(check(TokenType::COLOR)) {
value = ValueNode::ofColor(parseColor()->color);
} else {
return unexpected();
}
return spanner(value);
}
/****************************************************************************
*
* PropertyNode := IdentifierNode + ":" + ValueNode + ";"
*
****************************************************************************/
PResult<PropertyNode> ComdelParser::parseProperty(std::optional<TokenType> valueType = std::nullopt) {
@ -387,6 +421,7 @@ PResult<PropertyNode> ComdelParser::parseProperty(std::optional<TokenType> value
RETURN_IF_NOT_TOKEN(TokenType::COLON);
// if valueType is defined value must be of given TokenType
if (valueType.has_value()) {
if (valueType == TokenType::BOOL_TYPE) {
if (!(check(TokenType::TRUE) || check(TokenType::FALSE))) {
@ -401,16 +436,31 @@ PResult<PropertyNode> ComdelParser::parseProperty(std::optional<TokenType> value
RETURN_IF_NOT_TOKEN(TokenType::SEMICOLON);
PropertyNode node;
node.key = key;
node.value = value;
return spanner(node);
return spanner(PropertyNode(key, value));
}
/****************************************************************************
*
* AddressSpaceNode := "@address" + IDENTIFIER "(" + NUMBER + "," + NUMBER + ")"
* StringPropertyNode := StringNode + ":" + ValueNode + ";"
*
****************************************************************************/
PResult<StringPropertyNode> ComdelParser::parseStringProperty() {
auto spanner = getSpanner();
StringNode key;
ASSIGN_OR_RETURN_IF_ERR(key, parseString());
RETURN_IF_NOT_TOKEN(TokenType::EQUALS);
ValueNode value;
ASSIGN_OR_RETURN_IF_ERR(value, parseValue());
return spanner(StringPropertyNode{key, value});
}
/****************************************************************************
*
* AddressSpaceNode := "@address" + IdentifierNode + NumberPairNode
*
****************************************************************************/
PResult<AddressSpaceNode> ComdelParser::parseAddress() {
@ -421,11 +471,7 @@ PResult<AddressSpaceNode> ComdelParser::parseAddress() {
RETURN_IF_NOT_TOKEN(TokenType::KW_ADDRESS);
ASSIGN_OR_RETURN_IF_ERR(addressSpace.name, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(addressSpace.start, parseNumber());
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
ASSIGN_OR_RETURN_IF_ERR(addressSpace.end, parseNumber());
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
ASSIGN_OR_RETURN_IF_ERR(addressSpace.range, parseNumberPair());
return spanner(addressSpace);
}
@ -433,7 +479,17 @@ PResult<AddressSpaceNode> ComdelParser::parseAddress() {
/****************************************************************************
*
* ComponentNode := "@component" + IDENTIFIER + ("processor" | "memory") { COMPONENT_BLOCK }
* ComponentNode := "@component" + IdentifierNode + ComponentType + "{"
* "@instanceName" + IdentifierNode
* "@tooltip" + StringNode
* "@source" + StringNode
* "@tooltip" + StringNode
* "@count" + NumberPairNode
* DisplayNode
* [PinNode]{0..N}
* [AttributeNode]{0..N}
* [RuleNode]{0..N}
* "}"
*
****************************************************************************/
PResult<ComponentNode> ComdelParser::parseComponent() {
@ -447,20 +503,16 @@ PResult<ComponentNode> ComdelParser::parseComponent() {
ASSIGN_OR_RETURN_IF_ERR(component.type, parseComponentType());
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if (check(TokenType::KW_INSTANCE_NAME)) {
bump();
if (consume(TokenType::KW_INSTANCE_NAME)) {
ASSIGN_OR_SET_ERR(component.instanceName, parseIdentifier());
} else if (check(TokenType::KW_TOOLTIP)) {
bump();
} else if (consume(TokenType::KW_TOOLTIP)) {
ASSIGN_OR_SET_ERR(component.tooltip, parseString());
} else if (check(TokenType::KW_SOURCE)) {
bump();
} else if (consume(TokenType::KW_SOURCE)) {
ASSIGN_OR_SET_ERR(component.source, parseString());
} else if (check(TokenType::KW_COUNT)) {
ASSIGN_OR_SET_ERR(component.count, parseCount());
} else if (consume(TokenType::KW_COUNT)) {
ASSIGN_OR_SET_ERR(component.count, parseNumberPair());
} else if (check(TokenType::KW_DISPLAY)) {
ASSIGN_OR_SET_ERR(component.display, parseDisplay());
} else if (check(TokenType::KW_PIN)) {
@ -481,22 +533,25 @@ PResult<ComponentNode> ComdelParser::parseComponent() {
}
}
}
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
return spanner(component);
}
/****************************************************************************
*
* ComponentType := ["processor" | "memory"]{0,1}
*
****************************************************************************/
PResult<EnumNode<ComponentNode::ComponentType>> ComdelParser::parseComponentType() {
EnumNode<ComponentNode::ComponentType> type;
auto spanner = getSpanner();
if (check(TokenType::CT_PROCESSOR)) {
bump();
if (consume(TokenType::CT_PROCESSOR)) {
type = EnumNode(ComponentNode::PROCESSOR);
} else if (check(TokenType::CT_MEMORY)) {
bump();
} else if (consume(TokenType::CT_MEMORY)) {
type = EnumNode(ComponentNode::MEMORY);
} else {
type = EnumNode(ComponentNode::OTHER);
@ -507,7 +562,7 @@ PResult<EnumNode<ComponentNode::ComponentType>> ComdelParser::parseComponentType
/****************************************************************************
*
* DisplayNode := "@display {" + (DISPLAY_ITEM)* + "}"
* DisplayNode := "@display {" + DisplayItemNode{0..N} + "}"
*
****************************************************************************/
PResult<DisplayNode> ComdelParser::parseDisplay() {
@ -528,7 +583,7 @@ PResult<DisplayNode> ComdelParser::parseDisplay() {
/****************************************************************************
*
* DisplayItemNode := "TYPE {(KEY + ":" + VALUE + ";")*}
* DisplayItemNode := IdentifierNode + "{" + PropertyNode{0..N} + "}"
*
****************************************************************************/
PResult<DisplayItemNode> ComdelParser::parseDisplayItem() {
@ -550,7 +605,12 @@ PResult<DisplayItemNode> ComdelParser::parseDisplayItem() {
/****************************************************************************
*
* BusNode := "@bus " + NAME + TYPE + "{" + POPUP + "}"
* BusNode := "@bus " + IdentifierNode + BusType + "{"
* "@tooltip" + StringNode
* "@instanceName" + StringNode
* DisplayNode
* "@wires {" + [WireNode + ","]{0..N} + WireNode "}"
* "}"
*
****************************************************************************/
PResult<BusNode> ComdelParser::parseBus() {
@ -566,18 +626,15 @@ PResult<BusNode> ComdelParser::parseBus() {
while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if (check(TokenType::KW_TOOLTIP)) {
bump();
if (consume(TokenType::KW_TOOLTIP)) {
ASSIGN_OR_SET_ERR(bus.tooltip, parseString());
} else if (check(TokenType::KW_INSTANCE_NAME)) {
bump();
} else if (consume(TokenType::KW_INSTANCE_NAME)) {
ASSIGN_OR_SET_ERR(bus.instanceName, parseIdentifier());
} else if (check(TokenType::KW_COUNT)) {
ASSIGN_OR_SET_ERR(bus.count, parseCount());
} else if (consume(TokenType::KW_COUNT)) {
ASSIGN_OR_SET_ERR(bus.count, parseNumberPair());
} else if (check(TokenType::KW_DISPLAY)) {
ASSIGN_OR_SET_ERR(bus.display, parseDisplay());
} else if (check(TokenType::KW_WIRES)) {
bump();
} else if (consume(TokenType::KW_WIRES)) {
if(consume(TokenType::LBRACE)) {
while (check(TokenType::IDENTIFIER)) {
APPEND_OR_RETURN_IF_ERR(bus.wires, parseWire());
@ -610,6 +667,11 @@ PResult<BusNode> ComdelParser::parseBus() {
return spanner(bus);
}
/****************************************************************************
*
* BusType := ["automatic" | "regular" | "singleAutomatic"]{0,1}
*
****************************************************************************/
PResult<EnumNode<BusNode::BusType>> ComdelParser::parseBusType() {
PResult<EnumNode<BusNode::BusType>> type;
@ -630,10 +692,9 @@ PResult<EnumNode<BusNode::BusType>> ComdelParser::parseBusType() {
return type;
}
/****************************************************************************
*
* WireNode := NAME(<SIZE>){0,1} TYPE [hidden | terminated_with (#number | null)])*
* WireNode := Identifier + ["<" + NumberNode + ">"]{0,1} + WireType{0,1} + "hidden"{0,1} + ["terminated_with" + (NumberNode | NULL)]{0,1}
*
****************************************************************************/
PResult<WireNode> ComdelParser::parseWire() {
@ -653,29 +714,22 @@ PResult<WireNode> ComdelParser::parseWire() {
// default
wire.type = EnumNode(WireNode::WIRE);
if (check(TokenType::WIRE_DEFAULT)) {
bump();
if (consume(TokenType::WIRE_DEFAULT)) {
wire.type = EnumNode(WireNode::WIRE);
} else if (check(TokenType::WIRE_AND)) {
bump();
} else if (consume(TokenType::WIRE_AND)) {
wire.type = EnumNode(WireNode::WIRED_AND);
} else if (check(TokenType::WIRE_OR)) {
bump();
} else if (consume(TokenType::WIRE_OR)) {
wire.type = EnumNode(WireNode::WIRED_OR);
} else if (check(TokenType::R_WIRE)) {
bump();
} else if (consume(TokenType::R_WIRE)) {
wire.type = EnumNode(WireNode::R_WIRE);
}
while (true) {
if (check(TokenType::HIDDEN)) {
bump();
if (consume(TokenType::HIDDEN)) {
wire.hidden = true;
} else if (check(TokenType::TERMINATE_WITH)) {
bump();
} else if (consume(TokenType::TERMINATE_WITH)) {
wire.hasTerminateWith = true;
if (check(TokenType::NIL)) {
bump();
if (consume(TokenType::NIL)) {
wire.terminateWith = ValueNode::ofNull();
} else if (check(TokenType::NUMBER)) {
auto number = parseNumber();
@ -695,11 +749,12 @@ PResult<WireNode> ComdelParser::parseWire() {
/****************************************************************************
*
* PinNode := "@pin" NAME TYPE "{"
"@tooltip" MESSAGE
"@connection" TYPE "(" MESSAGE ")"
DisplayNode
}
* PinNode := "@pin" + IdentifierType + PinType + "{"
* "@tooltip" + StringNode
* "@connection" + StringNode
* DisplayNode
* "@wires {" + [ConnectionWireNode + ","]{0..N} + ConnectionWireNode + "}"
* "}"
*
****************************************************************************/
PResult<PinNode> ComdelParser::parsePin() {
@ -710,32 +765,26 @@ PResult<PinNode> ComdelParser::parsePin() {
ASSIGN_OR_RETURN_IF_ERR(pin.name, parseIdentifier());
if (check(TokenType::PIN_IN)) {
bump();
if (consume(TokenType::PIN_IN)) {
pin.type = EnumNode(PinNode::IN);
} else if (check(TokenType::PIN_OUT)) {
bump();
} else if (consume(TokenType::PIN_OUT)) {
pin.type = EnumNode(PinNode::OUT);
} else if (check(TokenType::PIN_IN_OUT)) {
bump();
} else if (consume(TokenType::PIN_IN_OUT)) {
pin.type = EnumNode(PinNode::IN_OUT);
} else {
return unexpected();
}
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if (check(TokenType::KW_TOOLTIP)) {
bump();
if (consume(TokenType::KW_TOOLTIP)) {
ASSIGN_OR_SET_ERR(pin.tooltip, parseString());
} else if (check(TokenType::KW_DISPLAY)) {
ASSIGN_OR_SET_ERR(pin.display, parseDisplay());
} else if (check(TokenType::KW_CONNECTION)) {
ASSIGN_OR_SET_ERR(pin.connection, parsePinConnection());
} else if (check(TokenType::KW_WIRES)) {
bump();
} else if (consume(TokenType::KW_CONNECTION)) {
ASSIGN_OR_SET_ERR(pin.connection, parseString());
} else if (consume(TokenType::KW_WIRES)) {
auto wires = parseList<ValueNode>(TokenType::LBRACE,
TokenType::RBRACE,
TokenType::COMMA,
@ -755,57 +804,14 @@ PResult<PinNode> ComdelParser::parsePin() {
}
}
}
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
return spanner(pin);
}
/****************************************************************************
*
* PinConnectionNode := "@connection " + ("check_only" | "automatically") + "(" + MESSAGE + ")"
*
****************************************************************************/
PResult<PinConnectionNode> ComdelParser::parsePinConnection() {
auto spanner = getSpanner();
PinConnectionNode connection{};
RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION);
ASSIGN_OR_RETURN_IF_ERR(connection.type, parseConnectionType());
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(connection.message, parseString());
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
return spanner(connection);
}
PResult<EnumNode<PinConnectionNode::ConnectionType>> ComdelParser::parseConnectionType() {
auto spanner = getSpanner();
EnumNode<PinConnectionNode::ConnectionType> type;
if (check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier();
if (identifier.value().value == "required") {
type = EnumNode(PinConnectionNode::REQUIRED);
} else if (identifier.value().value == "optional") {
type = EnumNode(PinConnectionNode::OPTIONAL);
} else {
return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"});
}
} else {
return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"});
}
return spanner(type);
}
/****************************************************************************
*
* AttributeNode := "@attribute " + NAME + TYPE ("default" + VALUE){0,1} ("{" POPUP "}"){0,1}
* AttributeNode := "@attribute " + IdentifierNode + ValueType + ("default" + ValueNode){0,1} + ("{" PopupNode "}"){0,1}
*
****************************************************************************/
PResult<AttributeNode> ComdelParser::parseAttribute() {
@ -820,27 +826,24 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
return unexpected();
}
if (check(TokenType::INT_TYPE)) {
if (consume(TokenType::INT_TYPE)) {
attribute.type = ValueNode::INT;
} else if (check(TokenType::STRING_TYPE)) {
} else if (consume(TokenType::STRING_TYPE)) {
attribute.type = ValueNode::STRING;
} else if (check(TokenType::BOOL_TYPE)) {
} else if (consume(TokenType::BOOL_TYPE)) {
attribute.type = ValueNode::BOOL;
} else if (check(TokenType::WIRE_TYPE)) {
} else if (consume(TokenType::WIRE_TYPE)) {
attribute.type = ValueNode::WIRE;
} else {
return unexpected();
}
bump();
RETURN_IF_NOT_TOKEN(TokenType::DEFAULT);
if (attribute.type == ValueNode::BOOL) {
if (check(TokenType::TRUE)) {
bump();
if (consume(TokenType::TRUE)) {
attribute.defaultValue = ValueNode::ofBool(true);
} else if (check(TokenType::FALSE)) {
bump();
} else if (consume(TokenType::FALSE)) {
attribute.defaultValue = ValueNode::ofBool(false);
} else {
return unexpected();
@ -870,8 +873,7 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
if (check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier();
attribute.defaultValue = ValueNode::ofMemory(identifier->value);
} else if (check(TokenType::NIL)) {
bump();
} else if (consume(TokenType::NIL)) {
attribute.defaultValue = ValueNode::ofMemory(std::nullopt);
} else {
return unexpected();
@ -880,8 +882,7 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
if (check(TokenType::IDENTIFIER)) {
auto identifier = parseIdentifier();
attribute.defaultValue = ValueNode::ofWire(identifier->value);
} else if (check(TokenType::NIL)) {
bump();
} else if (consume(TokenType::NIL)) {
attribute.defaultValue = ValueNode::ofWire(std::nullopt);
} else {
return unexpected();
@ -890,12 +891,11 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
if (check(TokenType::LBRACE)) {
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
PopupNode popup;
if (!check(TokenType::KW_POPUP)) {
return unexpected();
}
PopupNode popup;
ASSIGN_OR_RETURN_IF_ERR(popup, parsePopup());
attribute.popup = std::optional<PopupNode>(popup);
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
@ -906,29 +906,12 @@ PResult<AttributeNode> ComdelParser::parseAttribute() {
/****************************************************************************
*
* Enumeration
*
****************************************************************************/
PResult<EnumerationNode> ComdelParser::parseEnumeration() {
auto spanner = getSpanner();
StringNode key;
ASSIGN_OR_RETURN_IF_ERR(key, parseString());
RETURN_IF_NOT_TOKEN(TokenType::EQUALS);
ValueNode value;
ASSIGN_OR_RETURN_IF_ERR(value, parseValue());
EnumerationNode node;
node.key = key;
node.value = value;
return spanner(node);
}
/****************************************************************************
*
* PopupNode := "@popup " + ("automatic" | "on_demand") { POPUP BODY }
* PopupNode := "@popup " + ("automatic" | "on_demand") + "{"
* "@title" + StringNode
* "@text" + StringNode
* [RuleNode]{0..N}
* "@enumerated {" + [StringPropertyNode + ","]{0..N} + StringPropertyNode + "}"
* "}"
*
****************************************************************************/
PResult<PopupNode> ComdelParser::parsePopup() {
@ -954,24 +937,21 @@ PResult<PopupNode> ComdelParser::parsePopup() {
while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if (check(TokenType::KW_TITLE)) {
bump();
if (consume(TokenType::KW_TITLE)) {
ASSIGN_OR_SET_ERR(popup.title, parseString());
} else if (check(TokenType::KW_TEXT)) {
bump();
} else if (consume(TokenType::KW_TEXT)) {
ASSIGN_OR_SET_ERR(popup.text, parseString());
} else if (check(TokenType::KW_RULE)) {
APPEND_OR_SET_ERR(popup.rules, parseRule());
} else if (check(TokenType::KW_ENUMERATED)) {
bump();
} else if (consume(TokenType::KW_ENUMERATED)) {
popup.enumerated = true;
ASSIGN_OR_SET_ERR(popup.enumeration,
parseList<EnumerationNode>(
parseList<StringPropertyNode>(
TokenType::LBRACE,
TokenType::RBRACE,
TokenType::COMMA,
true,
[this] { return parseEnumeration(); }
[this] { return parseStringProperty(); }
)
);
} else {
@ -994,7 +974,26 @@ PResult<PopupNode> ComdelParser::parsePopup() {
/****************************************************************************
*
* ConnectionNode := "@connection (" + COMPONENT + "." + PIN + "," + BUS [ + "," + COMPONENT2 + "." + "PIN2"] + ") {" + CONNECTION + "}"
* ConnectionComponentNode := IdentifierNode + "." + IdentifierNode
*
****************************************************************************/
PResult<ConnectionComponentNode> ComdelParser::parseConnectionComponent() {
auto spanner = getSpanner();
ConnectionComponentNode node;
ASSIGN_OR_RETURN_IF_ERR(node.component, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(node.pin, parseIdentifier());
return spanner(node);
}
/****************************************************************************
*
* ConnectionNode := "@connection (" + ConnectionComponentNode + "," + IdentifierNode + ["," + ConnectionComponentNode]{0,1} + ") {"
* [AttributeNode]{0..N}
* ["@wires {" + [ConnectionWireNode + ","]{0..N} + ConnectionWireNode + "}"]{1,2}
* "}"
*
****************************************************************************/
PResult<ConnectionNode> ComdelParser::parseConnection() {
@ -1004,33 +1003,24 @@ PResult<ConnectionNode> ComdelParser::parseConnection() {
RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION);
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(connection.first.component, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(connection.first.pin, parseIdentifier());
ASSIGN_OR_RETURN_IF_ERR(connection.first, parseConnectionComponent());
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);
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;
ASSIGN_OR_RETURN_IF_ERR(connection.second, parseConnectionComponent());
}
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
int wireCount = 0;
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if (check(TokenType::KW_ATTRIBUTE)) {
APPEND_OR_RETURN_IF_ERR(connection.attributes, parseAttribute());
} else if (check(TokenType::KW_WIRES)) {
bump();
} else if (consume(TokenType::KW_WIRES)) {
auto wires = parseList<ValueNode>(TokenType::LBRACE, TokenType::RBRACE, TokenType::COMMA, false,
[this] { return parseConnectionWire(); });
RETURN_IF_ERR(wires);
@ -1063,7 +1053,10 @@ PResult<ConnectionNode> ComdelParser::parseConnection() {
/****************************************************************************
*
* RuleNode := "@rule {" + if-else statements + "}"
* RuleNode := "@rule {"
* IfStatementNode
* ["else" + IfStatementNode]{0..N}
* "}"
*
****************************************************************************/
PResult<RuleNode> ComdelParser::parseRule() {
@ -1090,7 +1083,9 @@ PResult<RuleNode> ComdelParser::parseRule() {
/****************************************************************************
*
* IfStatement := "if(!function(params...)) { error(MESSAGE) | warning(MESSAGE) }
* IfStatement := "if(" + "!"{0,1} + IdentifierNode + "(" + [ValueNode + ","]{0..N} + ValueNode + ")) {"
* ["error" | "warning"] + "(" + StringNode + ")"
* "}"
*
****************************************************************************/
PResult<IfStatementNode> ComdelParser::parseIfStatement() {
@ -1101,79 +1096,53 @@ PResult<IfStatementNode> ComdelParser::parseIfStatement() {
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
if (check(TokenType::NOT)) {
if (consume(TokenType::NOT)) {
ifStatement.condition.negated = true;
bump();
} else {
ifStatement.condition.negated = false;
}
ASSIGN_OR_RETURN_IF_ERR(ifStatement.condition.functionName, parseIdentifier());
ASSIGN_OR_RETURN_IF_ERR(ifStatement.condition.params, parseList<ValueNode>(TokenType::LPAREN,
TokenType::RPAREN,
TokenType::COMMA,
false,
[this] { return parseValue(); }
));
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
if (check(TokenType::ERROR)) {
if (consume(TokenType::ERROR)) {
ifStatement.action.type = EnumNode(ActionNode::ERROR);
} else if (check(TokenType::WARNING)) {
} else if (consume(TokenType::WARNING)) {
ifStatement.action.type = EnumNode(ActionNode::WARNING);
} else {
return unexpected();
}
bump();
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(ifStatement.action.message, parseString());
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
return spanner(ifStatement);
}
PResult<ValueNode> ComdelParser::parseValue() {
auto spanner = getSpanner();
ValueNode value;
if (check(TokenType::IDENTIFIER)) {
value = ValueNode::ofIdentifier(parseIdentifier()->value);
} else if (check(TokenType::STRING)) {
value = ValueNode::ofString(parseString()->asString());
} else if (check(TokenType::NUMBER)) {
value = ValueNode::ofInt(parseNumber()->value);
} else if (check(TokenType::TRUE)) {
bump();
value = ValueNode::ofBool(true);
} else if (check(TokenType::FALSE)) {
bump();
value = ValueNode::ofBool(false);
} else if (check(TokenType::NIL)) {
bump();
value = ValueNode::ofNull();
} else if(check(TokenType::COLOR)) {
value = ValueNode::ofColor(parseColor()->color);
} else {
return unexpected();
}
return spanner(value);
}
/****************************************************************************
*
* SchemaNode :=
* "@source" + StringNode
* "@schema {"
* [InstanceNode]{0..N}
* [ConnectionInstanceNode]{0..N}
* "}"
*
****************************************************************************/
std::optional<SchemaNode> ComdelParser::parseSchema() {
auto spanner = getSpanner();
SchemaNode schema{};
if (check(TokenType::KW_SOURCE)) {
bump();
if (consume(TokenType::KW_SOURCE)) {
if (check(TokenType::STRING)) {
auto source = parseString();
schema.source = *source;
@ -1186,16 +1155,14 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
return std::nullopt;
}
if (!check(TokenType::KW_SCHEMA)) {
if (!consume(TokenType::KW_SCHEMA)) {
errors.emplace_back(current().span, "expected `@schema`");
return std::nullopt;
}
bump();
if (!check(TokenType::LBRACE)) {
if (!consume(TokenType::LBRACE)) {
errors.emplace_back(current().span, "expected `{`");
return std::nullopt;
}
bump();
while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
@ -1216,11 +1183,9 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
}
}
}
if (!check(TokenType::RBRACE)) {
if (!consume(TokenType::RBRACE)) {
errors.emplace_back(current().span, "expected `}`");
return std::nullopt;
} else {
bump();
}
if (!check(TokenType::END_OF_FILE)) {
@ -1235,28 +1200,13 @@ std::optional<SchemaNode> ComdelParser::parseSchema() {
/****************************************************************************
*
* CountNode := "@position (" + NumberNode + "," + NumberNode + ")"
* InstanceNode := "@instance" + IdentifierNode + IdentifierNode "{"
* "@position" + NumberPairNode
* [InstanceAttributeNode]{0..N}
* "@size" + NumberNode
* "}"
*
****************************************************************************/
PResult<CountNode> ComdelParser::parsePosition() {
auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_POSITION);
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
auto first = parseNumber();
if (!first.has_value()) {
return PError(first.error());
}
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
auto second = parseNumber();
if (!second.has_value()) {
return PError(second.error());
}
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
return spanner(CountNode{first.value(), second.value()});
}
PResult<InstanceNode> ComdelParser::parseInstance() {
auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_INSTANCE);
@ -1270,12 +1220,11 @@ PResult<InstanceNode> ComdelParser::parseInstance() {
while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if (check(TokenType::KW_POSITION)) {
ASSIGN_OR_SET_ERR(instance.position, parsePosition());
if (consume(TokenType::KW_POSITION)) {
ASSIGN_OR_SET_ERR(instance.position, parseNumberPair());
} else if (check(TokenType::KW_ATTRIBUTE)) {
APPEND_OR_SET_ERR(instance.attributes, parseInstanceAttribute());
} else if (check(TokenType::KW_SIZE)) {
bump();
} else if (consume(TokenType::KW_SIZE)) {
auto number = parseNumber();
RETURN_IF_ERR(number);
instance.size = *number;
@ -1297,6 +1246,11 @@ PResult<InstanceNode> ComdelParser::parseInstance() {
return spanner(instance);
}
/****************************************************************************
*
* InstanceAttributeNode := "@attribute" + IdentifierNode + ValueNode
*
****************************************************************************/
PResult<InstanceAttributeNode> ComdelParser::parseInstanceAttribute() {
auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_ATTRIBUTE);
@ -1308,6 +1262,28 @@ PResult<InstanceAttributeNode> ComdelParser::parseInstanceAttribute() {
return spanner(attribute);
}
/****************************************************************************
*
* ConnectionComponentInstanceNode := IdentifierNode + "." + IdentifierNode
*
****************************************************************************/
PResult<ConnectionComponentInstanceNode> ComdelParser::parseConnectionComponentInstance() {
auto spanner = getSpanner();
ConnectionComponentInstanceNode node;
ASSIGN_OR_RETURN_IF_ERR(node.instance, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(node.pin, parseIdentifier());
return spanner(node);
}
/****************************************************************************
*
* ConnectionInstanceNode := "@connection (" + ConnectionComponentInstanceNode + "," + IdentifierNode + ["," + ConnectionComponentInstanceNode ] + ") {"
* [InstanceAttributeNode]{0..N}
* "}"
*
****************************************************************************/
PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
auto spanner = getSpanner();
RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION);
@ -1315,25 +1291,20 @@ PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
ConnectionInstanceNode connection;
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
ASSIGN_OR_RETURN_IF_ERR(connection.first.instance, parseIdentifier());
RETURN_IF_NOT_TOKEN(TokenType::DOT);
ASSIGN_OR_RETURN_IF_ERR(connection.first.pin, parseIdentifier());
ASSIGN_OR_RETURN_IF_ERR(connection.first, parseConnectionComponentInstance());
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());
ConnectionComponentInstanceNode second;
ASSIGN_OR_RETURN_IF_ERR(second, parseConnectionComponentInstance());
connection.second = second;
}
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while (!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if (check(TokenType::KW_ATTRIBUTE)) {
@ -1350,12 +1321,16 @@ PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
}
}
}
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
return spanner(connection);
}
/****************************************************************************
*
* ConnectionWireNode := [IdentifierNode | StringNode | "NULL" | NumberNode]
*
****************************************************************************/
PResult<ValueNode> ComdelParser::parseConnectionWire() {
auto spanner = getSpanner();
if (check(TokenType::NUMBER)) {
@ -1371,4 +1346,3 @@ PResult<ValueNode> ComdelParser::parseConnectionWire() {
return unexpected();
}
}

View File

@ -42,16 +42,20 @@ private:
Span &getPreviousSpan();
/** Skips current token */
void bump();
/** Checks if next token is of given type and if it is consumes it */
bool consume(TokenType tokenType);
/** Checks if next token is of given type */
bool check(TokenType tokenType);
/** Skips until next keyword on same level
* Used to continue parsing on error
* */
void skipUntilNextKeyword();
/** Retuns current token */
Token &current();
/** Throws error of unexpected types */
[[nodiscard]] PError unexpected();
template<typename T>
@ -63,73 +67,45 @@ private:
Spanner getSpanner();
// used to parse library and schema
/** Base types */
PResult<StringNode> parseString();
PResult<ColorNode> parseColor();
PResult<IdentifierNode> parseIdentifier();
PResult<NumberNode> parseNumber();
PResult<CountNode> parseCount();
PResult<NumberPairNode> parseNumberPair();
PResult<PropertyNode> parseProperty(std::optional<TokenType> valueType);
PResult<EnumerationNode> parseEnumeration();
PResult<ValueNode> parseConnectionWire();
PResult<ComponentNode> parseComponent();
PResult<AddressSpaceNode> parseAddress();
PResult<PinNode> parsePin();
PResult<DisplayNode> parseDisplay();
PResult<PinConnectionNode> parsePinConnection();
PResult<AttributeNode> parseAttribute();
PResult<PopupNode> parsePopup();
PResult<RuleNode> parseRule();
PResult<BusNode> parseBus();
PResult<WireNode> parseWire();
PResult<ConnectionNode> parseConnection();
PResult<DisplayItemNode> parseDisplayItem();
PResult<IfStatementNode> parseIfStatement();
PResult<StringPropertyNode> parseStringProperty();
PResult<ValueNode> parseValue();
// used to parse schema
PResult<CountNode> parsePosition();
PResult<InstanceNode> parseInstance();
PResult<InstanceAttributeNode> parseInstanceAttribute();
PResult<ConnectionInstanceNode> parseConnectionInstance();
/** Library types */
PResult<ValueNode> parseConnectionWire();
PResult<ComponentNode> parseComponent();
PResult<EnumNode<ComponentNode::ComponentType>> parseComponentType();
PResult<AddressSpaceNode> parseAddress();
PResult<PinNode> parsePin();
PResult<DisplayNode> parseDisplay();
PResult<AttributeNode> parseAttribute();
PResult<PopupNode> parsePopup();
PResult<RuleNode> parseRule();
PResult<BusNode> parseBus();
PResult<WireNode> parseWire();
PResult<ConnectionNode> parseConnection();
PResult<ConnectionComponentNode> parseConnectionComponent();
PResult<DisplayItemNode> parseDisplayItem();
PResult<IfStatementNode> parseIfStatement();
PResult<EnumNode<BusNode::BusType>> parseBusType();
PResult<EnumNode<PinConnectionNode::ConnectionType>> parseConnectionType();
/** Schema types */
PResult<InstanceNode> parseInstance();
PResult<InstanceAttributeNode> parseInstanceAttribute();
PResult<ConnectionInstanceNode> parseConnectionInstance();
PResult<ConnectionComponentInstanceNode> parseConnectionComponentInstance();
public:
explicit ComdelParser(std::vector<Token> tokens);
std::optional<SchemaNode> parseSchema();
std::optional<LibraryNode> parseLibrary();
const std::vector<SourceError> &getErrors();
};

View File

@ -7,6 +7,7 @@
#include <string>
#include <vector>
/*** Represent source file */
class SourceFile {
std::string fileName;
std::string source;
@ -22,7 +23,7 @@ public:
void addLineOffset(unsigned offset);
};
/*** Represent parsing context */
class ParseContext {
std::string applicationDir;
std::vector<SourceFile> fileMap;

View File

@ -101,7 +101,6 @@ enum class TokenType {
KW_SCHEMA,
KW_POSITION,
KW_SIZE,
KW_UNKNOWN,
// TYPES
INT_TYPE,

View File

@ -60,7 +60,7 @@
}
@pin glavniPin in {
@tooltip "pin za spajanje na glavnu sabirnicu"
@connection required("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu")
@connection "COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu"
@display {
pin {
x: 42; y: 100; w: 16; h:16;
@ -72,7 +72,6 @@
@pin memDirect inOut {
@tooltip "pin za izravno spajanje na RAM"
@connection optional("COMDEL se ne može stvoriti. FRISC nije spojen na sabirnicu")
@display {
pin {
x: 100; y: 42; w: 16; h:16;
@ -181,7 +180,7 @@
@pin glavniPin inOut {
@tooltip "pin za spajanje na glavnu sabirnicu"
@connection required("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu")
@connection "COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu"
@display {
/*
pin {
@ -204,7 +203,6 @@
@pin memDirect inOut {
@tooltip "pin za spajanje na procesor"
@connection optional("COMDEL se ne može stvoriti. Memorija nije spojena na sabirnicu")
@display {
/*
pin {
@ -276,7 +274,7 @@
@pin glavniPin in {
@tooltip "pin za spajanje na glavnu sabirnicu"
@connection required("COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu")
@connection "COMDEL se ne može stvoriti. DMA nije spojena na sabirnicu"
@display {
/*
pin {
@ -298,7 +296,6 @@
@pin dodatnaPoveznica in {
@tooltip "pin za spajanje na pomocnu sabirnicu"
@connection optional("COMDEL se ne može stvoriti. DMA nije spojen na nesto!")
@display {
pin {
x: 100; y: 7; w: 16; h: 16;