From 1ec0433cfeca841c71b474535a6f48b4b21ad2a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borna=20Rajkovi=C4=87?= Date: Mon, 13 Jun 2022 00:48:12 +0200 Subject: [PATCH] Added comments and cleaned up ast nodes and parser --- CMakeLists.txt | 2 +- application.cpp | 2 +- comdel/domain/comdel_validator.cpp | 4 +- comdel/domain/pin.cpp | 16 +- comdel/domain/pin.h | 25 +- comdel/domain/schema_creator.cpp | 116 ++-- comdel/domain/schema_creator.h | 2 - comdel/parser/ast_nodes.cpp | 45 +- comdel/parser/ast_nodes.h | 473 ++++++++------ comdel/parser/color.cpp | 5 - comdel/parser/color.h | 10 +- comdel/parser/comdel_lexer.h | 35 +- comdel/parser/comdel_parser.cpp | 580 +++++++++--------- comdel/parser/comdel_parser.h | 86 +-- comdel/parser/parse_context.h | 3 +- comdel/parser/token.h | 1 - .../simplified FRISC model/frisc_library.csl | 9 +- 17 files changed, 747 insertions(+), 667 deletions(-) delete mode 100644 comdel/parser/color.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5478eb7..9d46ca2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/application.cpp b/application.cpp index 374163f..076de25 100644 --- a/application.cpp +++ b/application.cpp @@ -90,7 +90,7 @@ std::pair> Application::loadSchema(st } } else { - errorOutput << "Failed parsing library" << std::endl; + errorOutput << "Failed schema library" << std::endl; return {false, errors}; } diff --git a/comdel/domain/comdel_validator.cpp b/comdel/domain/comdel_validator.cpp index fb8b567..66a7067 100644 --- a/comdel/domain/comdel_validator.cpp +++ b/comdel/domain/comdel_validator.cpp @@ -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); } } diff --git a/comdel/domain/pin.cpp b/comdel/domain/pin.cpp index 37ec0d8..57d378c 100644 --- a/comdel/domain/pin.cpp +++ b/comdel/domain/pin.cpp @@ -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 connection, domain::ui::Pin pin, std::optional> 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 Pin::getConnection() { return connection; } diff --git a/comdel/domain/pin.h b/comdel/domain/pin.h index e39f1f6..3fa3ea4 100644 --- a/comdel/domain/pin.h +++ b/comdel/domain/pin.h @@ -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 connection; domain::ui::Pin displayPin; std::optional> 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 connection, domain::ui::Pin pin, std::optional> wires); std::string &getName(); @@ -57,7 +38,7 @@ namespace domain { ui::Pin &getDisplayPin(); - PinConnection &getConnection(); + std::optional getConnection(); std::optional> &getWires(); }; diff --git a/comdel/domain/schema_creator.cpp b/comdel/domain/schema_creator.cpp index c060f27..292bdfa 100644 --- a/comdel/domain/schema_creator.cpp +++ b/comdel/domain/schema_creator.cpp @@ -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 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 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 connection = std::nullopt; + if (node.connection) { + connection = node.connection->asString(); } - auto connection = loadPinConnection(*node.connection); std::optional> 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& 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& 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& 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 SchemaCreator::loadDisplay(DisplayNode node) { std::vector 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 SchemaCreator::loadAttribute(AttributeNode node) { std::string name = node.name.value; pushAdditional(name); diff --git a/comdel/domain/schema_creator.h b/comdel/domain/schema_creator.h index 991db77..3066361 100644 --- a/comdel/domain/schema_creator.h +++ b/comdel/domain/schema_creator.h @@ -58,8 +58,6 @@ namespace domain { std::optional loadWire(WireNode node); std::optional loadPin(PinNode pins); - PinConnection loadPinConnection(PinConnectionNode node); - std::optional loadConnection(ConnectionNode node); std::optional loadBus(BusNode node); diff --git a/comdel/parser/ast_nodes.cpp b/comdel/parser/ast_nodes.cpp index b9c88c2..23e03e3 100644 --- a/comdel/parser/ast_nodes.cpp +++ b/comdel/parser/ast_nodes.cpp @@ -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(); } @@ -134,4 +134,39 @@ ValueNode ValueNode::ofMemory(std::optional _value) { value.type = EnumNode(MEMORY); value.identifierValue = _value; return value; +} + +/*************************** DisplayItem NODE ********************************/ + +std::optional 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 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 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 DisplayItemNode::getProperty(const std::string &property) { + for(auto &prop: values) { + if(prop.key.value == property) { + return prop; + } + } + return std::nullopt; } \ No newline at end of file diff --git a/comdel/parser/ast_nodes.h b/comdel/parser/ast_nodes.h index 3ae3abd..9630f1e 100644 --- a/comdel/parser/ast_nodes.h +++ b/comdel/parser/ast_nodes.h @@ -8,28 +8,30 @@ #include #include +/***************************************************************************** + * 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 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 type; - std::optional intValue; - std::optional stringValue; - std::optional boolValue; - std::optional identifierValue; - std::optional colorValue; + /** Type determines what is stored inside ValueNode */ + EnumNode type = EnumNode(NIL); + /** All possible values for ValueNode are stored inside optionals */ + std::optional intValue = std::nullopt; + std::optional stringValue = std::nullopt; + std::optional boolValue = std::nullopt; + std::optional identifierValue = std::nullopt; + std::optional 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 _value); - static ValueNode ofNull(); - static ValueNode ofColor(Color color); - static ValueNode ofWire(std::optional _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 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 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 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 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> type; + /** Title of popup */ std::optional title; + /** Text of popup */ std::optional text; + /** If popup contains an enumeration*/ bool enumerated; - std::vector enumeration; + std::vector enumeration; + /** Validation rules for given popup */ std::vector 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 defaultValue; + /** Popup used to change attribute value */ + std::optional popup; }; -struct DisplayItemNode : public AstNode { - IdentifierNode type; - std::vector values; +/***************************************************************************** + * DISPLAY TYPES * + *****************************************************************************/ - long long int asInt(std::vector *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 *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 *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 *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 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 values; - StringNode message; - EnumNode type; + /** 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 asInt(const std::string &property, long long int _default = 0); + std::optional asColor(const std::string &property, Color _default = Color(0, 0, 0)); + std::optional asString(const std::string &property, std::string _default = ""); + +private: + std::optional getProperty(const std::string &property); }; +/***************************************************************************** + * 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 type; + /** Tooltip content displayed on hover over pin */ std::optional tooltip; - std::optional connection; + /** If present this means pin must be connected to another component or bus to create connection + * Connection contains error message shown + * */ + std::optional connection; + /** Determines how the pin is displayed */ std::optional display; + /** If pin connection is optional it requires list of wires used to populate comdel model */ std::optional> 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 tooltip; + /** Contains path to COMDEL source containing current component */ + std::optional source; + /** Type of component */ + EnumNode type; + /** List of component level rules */ + std::vector rules; + /** Default used to name instances */ + std::optional instanceName; + /** Count determines number of instances allowed in a schema */ + std::optional count; + /** Display determines how component is rendered */ + std::optional display; + /** List of all pins */ + std::vector pins; + /** List of all attributes */ + std::vector 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 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; +/** 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 type; IdentifierNode name; - std::optional defaultValue; - std::optional popup; + /** Default used to name instances */ + std::optional instanceName; + /** Tooltip displayed on hover */ + std::optional tooltip; + /** Count determines number of instances allowed in a schema */ + std::optional count; + /** Display determines how component is rendered */ + std::optional display; + + /** List of all COMDEL wires contained in bus */ + std::vector 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 second; @@ -324,51 +458,22 @@ struct ConnectionNode : public AstNode { IdentifierNode bus; std::vector attributes; + /** If connection is of type component-component it contains two pairs of wires */ std::vector firstWires; std::optional> secondWires; }; -struct ComponentNode : public AstNode { - enum ComponentType { - OTHER, - PROCESSOR, - MEMORY - }; - - IdentifierNode name; - std::optional tooltip; - std::optional source; - EnumNode type; - std::vector rules; - std::optional instanceName; - std::optional count; - std::optional display; - std::vector pins; - std::vector attributes; -}; - -struct BusNode : public AstNode { - enum BusType { - AUTOMATIC, - REGULAR, - SINGLE_AUTOMATIC - }; - - EnumNode type; - IdentifierNode name; - std::optional instanceName; - std::optional tooltip; - std::optional count; - std::optional display; - - std::vector wires; -}; - +/** LibraryNode represent library instance */ struct LibraryNode : public AstNode { + /** Name of library */ std::optional name; + /** Library info contains generic information about library */ std::optional libraryInfo; + /** Contains text that is added to top of COMDEL file */ std::optional header; + /** Contains path to component directory */ std::optional componentDirectory; + /** Contains text that is added to top of System component in COMDEL file */ std::optional componentHeader; std::vector addressSpaces; @@ -377,46 +482,64 @@ struct LibraryNode : public AstNode { std::vector buses; std::vector connections; + /** Contains properties used to translate dialog and error messages */ std::vector 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 position; + /** Contains position of component instance */ + std::optional position; std::vector attributes; + /** Contains size of bus instances */ std::optional 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 second; + ConnectionComponentInstanceNode first; + std::optional second; IdentifierNode bus; std::vector attributes; }; - +/** Represent schema instance */ struct SchemaNode : public AstNode { + /** Contains path to library source */ std::optional source; + /** Contains list of instances */ std::vector instances; + /** Contains list of connection */ std::vector connections; + /** Contains library */ std::optional library; }; diff --git a/comdel/parser/color.cpp b/comdel/parser/color.cpp deleted file mode 100644 index d8d0b21..0000000 --- a/comdel/parser/color.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by bbr on 12.06.22.. -// - -#include "color.h" diff --git a/comdel/parser/color.h b/comdel/parser/color.h index d38c9da..231aafc 100644 --- a/comdel/parser/color.h +++ b/comdel/parser/color.h @@ -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) {} }; diff --git a/comdel/parser/comdel_lexer.h b/comdel/parser/comdel_lexer.h index 0d07484..df492bc 100644 --- a/comdel/parser/comdel_lexer.h +++ b/comdel/parser/comdel_lexer.h @@ -11,11 +11,14 @@ #include #include +/** Contains results of tokenizing, + * if errors isn't empty tokenizing has failed */ struct LexerResult { std::vector tokens; std::vector 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 tokens; std::vector 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 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 nextTokenType(); PResult takeString(); - PResult takeRawString(); - void bump(unsigned count = 1); - char peek(); + /** Checks if we reached end of file */ bool eof(); }; diff --git a/comdel/parser/comdel_parser.cpp b/comdel/parser/comdel_parser.cpp index 66f9469..71c3743 100644 --- a/comdel/parser/comdel_parser.cpp +++ b/comdel/parser/comdel_parser.cpp @@ -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 ComdelParser::parseLibrary() { auto spanner = getSpanner(); @@ -230,20 +246,15 @@ std::optional ComdelParser::parseLibrary() { while (!check(TokenType::END_OF_FILE)) { PResult> 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 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(TokenType::LBRACE, TokenType::RBRACE, std::nullopt, @@ -284,7 +294,7 @@ std::optional ComdelParser::parseLibrary() { /**************************************************************************** * -* StringNode := "\"" + CONTENT + "\"" +* StringNode := ('"' + TEXT + '"' | "'" + TEXT + "'") * ****************************************************************************/ PResult ComdelParser::parseString() { @@ -292,17 +302,15 @@ PResult 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 ComdelParser::parseColor() { @@ -319,7 +327,7 @@ PResult ComdelParser::parseColor() { /**************************************************************************** * -* IdentifierNode := IDENTIFIER +* IdentifierNode := [_a-zA-Z][_a-zA-Z0-9]* * ****************************************************************************/ PResult ComdelParser::parseIdentifier() { @@ -327,7 +335,6 @@ PResult 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 ComdelParser::parseNumber() { return unexpected(); } - /**************************************************************************** * -* CountNode := "@size (" + NumberNode + "," + NumberNode + ")" +* NumberPairNode := '(' + NumberNode + ',' + NumberNode + ')' * ****************************************************************************/ -PResult ComdelParser::parseCount() { - auto spanner = getSpanner(); - RETURN_IF_NOT_TOKEN(TokenType::KW_COUNT); +PResult ComdelParser::parseNumberPair() { + auto spanner = getSpanner(); RETURN_IF_NOT_TOKEN(TokenType::LPAREN); auto first = parseNumber(); if (!first.has_value()) { @@ -372,12 +377,41 @@ PResult 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 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 ComdelParser::parseProperty(std::optional valueType = std::nullopt) { @@ -387,6 +421,7 @@ PResult ComdelParser::parseProperty(std::optional 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 ComdelParser::parseProperty(std::optional 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 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 ComdelParser::parseAddress() { @@ -421,21 +471,27 @@ PResult 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); } /**************************************************************************** -* -* 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 ComdelParser::parseComponent() { auto spanner = getSpanner(); @@ -447,20 +503,16 @@ PResult ComdelParser::parseComponent() { ASSIGN_OR_RETURN_IF_ERR(component.type, parseComponentType()); RETURN_IF_NOT_TOKEN(TokenType::LBRACE); - while (!check(TokenType::RBRACE)) { PResult> 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 ComdelParser::parseComponent() { } } } - RETURN_IF_NOT_TOKEN(TokenType::RBRACE); return spanner(component); } + +/**************************************************************************** + * + * ComponentType := ["processor" | "memory"]{0,1} + * + ****************************************************************************/ PResult> ComdelParser::parseComponentType() { EnumNode 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> ComdelParser::parseComponentType /**************************************************************************** * -* DisplayNode := "@display {" + (DISPLAY_ITEM)* + "}" +* DisplayNode := "@display {" + DisplayItemNode{0..N} + "}" * ****************************************************************************/ PResult ComdelParser::parseDisplay() { @@ -528,7 +583,7 @@ PResult ComdelParser::parseDisplay() { /**************************************************************************** * -* DisplayItemNode := "TYPE {(KEY + ":" + VALUE + ";")*} +* DisplayItemNode := IdentifierNode + "{" + PropertyNode{0..N} + "}" * ****************************************************************************/ PResult ComdelParser::parseDisplayItem() { @@ -549,9 +604,14 @@ PResult ComdelParser::parseDisplayItem() { /**************************************************************************** -* -* BusNode := "@bus " + NAME + TYPE + "{" + POPUP + "}" -* + * + * BusNode := "@bus " + IdentifierNode + BusType + "{" + * "@tooltip" + StringNode + * "@instanceName" + StringNode + * DisplayNode + * "@wires {" + [WireNode + ","]{0..N} + WireNode "}" + * "}" + * ****************************************************************************/ PResult ComdelParser::parseBus() { auto spanner = getSpanner(); @@ -566,18 +626,15 @@ PResult ComdelParser::parseBus() { while (!check(TokenType::RBRACE)) { PResult> 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 ComdelParser::parseBus() { return spanner(bus); } +/**************************************************************************** + * + * BusType := ["automatic" | "regular" | "singleAutomatic"]{0,1} + * + ****************************************************************************/ PResult> ComdelParser::parseBusType() { PResult> type; @@ -630,10 +692,9 @@ PResult> ComdelParser::parseBusType() { return type; } - /**************************************************************************** * -* WireNode := NAME(){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 ComdelParser::parseWire() { @@ -653,29 +714,22 @@ PResult 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(); @@ -694,14 +748,15 @@ PResult 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 ComdelParser::parsePin() { auto spanner = getSpanner(); @@ -710,32 +765,26 @@ PResult 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> 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(TokenType::LBRACE, TokenType::RBRACE, TokenType::COMMA, @@ -755,57 +804,14 @@ PResult ComdelParser::parsePin() { } } } - RETURN_IF_NOT_TOKEN(TokenType::RBRACE); return spanner(pin); } - /**************************************************************************** * -* PinConnectionNode := "@connection " + ("check_only" | "automatically") + "(" + MESSAGE + ")" -* -****************************************************************************/ -PResult 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> ComdelParser::parseConnectionType() { - auto spanner = getSpanner(); - - EnumNode 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 ComdelParser::parseAttribute() { @@ -820,27 +826,24 @@ PResult 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 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 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 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(popup); RETURN_IF_NOT_TOKEN(TokenType::RBRACE); @@ -905,32 +905,15 @@ PResult ComdelParser::parseAttribute() { } /**************************************************************************** -* -* Enumeration -* -****************************************************************************/ -PResult 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 ComdelParser::parsePopup() { auto spanner = getSpanner(); PopupNode popup; @@ -954,24 +937,21 @@ PResult ComdelParser::parsePopup() { while (!check(TokenType::RBRACE)) { PResult> 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( + parseList( TokenType::LBRACE, TokenType::RBRACE, TokenType::COMMA, true, - [this] { return parseEnumeration(); } + [this] { return parseStringProperty(); } ) ); } else { @@ -994,9 +974,28 @@ PResult ComdelParser::parsePopup() { /**************************************************************************** * -* ConnectionNode := "@connection (" + COMPONENT + "." + PIN + "," + BUS [ + "," + COMPONENT2 + "." + "PIN2"] + ") {" + CONNECTION + "}" +* ConnectionComponentNode := IdentifierNode + "." + IdentifierNode * ****************************************************************************/ +PResult 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 ComdelParser::parseConnection() { auto spanner = getSpanner(); ConnectionNode connection; @@ -1004,33 +1003,24 @@ PResult 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> 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(TokenType::LBRACE, TokenType::RBRACE, TokenType::COMMA, false, [this] { return parseConnectionWire(); }); RETURN_IF_ERR(wires); @@ -1062,9 +1052,12 @@ PResult ComdelParser::parseConnection() { /**************************************************************************** -* -* RuleNode := "@rule {" + if-else statements + "}" -* + * + * RuleNode := "@rule {" + * IfStatementNode + * ["else" + IfStatementNode]{0..N} + * "}" + * ****************************************************************************/ PResult ComdelParser::parseRule() { auto spanner = getSpanner(); @@ -1089,10 +1082,12 @@ PResult ComdelParser::parseRule() { /**************************************************************************** -* -* IfStatement := "if(!function(params...)) { error(MESSAGE) | warning(MESSAGE) } -* -****************************************************************************/ + * + * IfStatement := "if(" + "!"{0,1} + IdentifierNode + "(" + [ValueNode + ","]{0..N} + ValueNode + ")) {" + * ["error" | "warning"] + "(" + StringNode + ")" + * "}" + * + ****************************************************************************/ PResult ComdelParser::parseIfStatement() { auto spanner = getSpanner(); IfStatementNode ifStatement; @@ -1101,79 +1096,53 @@ PResult 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(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 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 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 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> err; @@ -1216,11 +1183,9 @@ std::optional 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)) { @@ -1234,29 +1199,14 @@ std::optional ComdelParser::parseSchema() { } /**************************************************************************** -* -* CountNode := "@position (" + NumberNode + "," + NumberNode + ")" -* -****************************************************************************/ -PResult 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()}); -} - + * + * InstanceNode := "@instance" + IdentifierNode + IdentifierNode "{" + * "@position" + NumberPairNode + * [InstanceAttributeNode]{0..N} + * "@size" + NumberNode + * "}" + * + ****************************************************************************/ PResult ComdelParser::parseInstance() { auto spanner = getSpanner(); RETURN_IF_NOT_TOKEN(TokenType::KW_INSTANCE); @@ -1270,12 +1220,11 @@ PResult ComdelParser::parseInstance() { while (!check(TokenType::RBRACE)) { PResult> 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 ComdelParser::parseInstance() { return spanner(instance); } +/**************************************************************************** + * + * InstanceAttributeNode := "@attribute" + IdentifierNode + ValueNode + * + ****************************************************************************/ PResult ComdelParser::parseInstanceAttribute() { auto spanner = getSpanner(); RETURN_IF_NOT_TOKEN(TokenType::KW_ATTRIBUTE); @@ -1308,6 +1262,28 @@ PResult ComdelParser::parseInstanceAttribute() { return spanner(attribute); } + +/**************************************************************************** +* +* ConnectionComponentInstanceNode := IdentifierNode + "." + IdentifierNode +* +****************************************************************************/ +PResult 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 ComdelParser::parseConnectionInstance() { auto spanner = getSpanner(); RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION); @@ -1315,25 +1291,20 @@ PResult 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> err; if (check(TokenType::KW_ATTRIBUTE)) { @@ -1350,12 +1321,16 @@ PResult ComdelParser::parseConnectionInstance() { } } } - RETURN_IF_NOT_TOKEN(TokenType::RBRACE); return spanner(connection); } +/**************************************************************************** + * + * ConnectionWireNode := [IdentifierNode | StringNode | "NULL" | NumberNode] + * + ****************************************************************************/ PResult ComdelParser::parseConnectionWire() { auto spanner = getSpanner(); if (check(TokenType::NUMBER)) { @@ -1370,5 +1345,4 @@ PResult ComdelParser::parseConnectionWire() { } else { return unexpected(); } -} - +} \ No newline at end of file diff --git a/comdel/parser/comdel_parser.h b/comdel/parser/comdel_parser.h index 44cb555..a50b7a3 100644 --- a/comdel/parser/comdel_parser.h +++ b/comdel/parser/comdel_parser.h @@ -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 ¤t(); + /** Throws error of unexpected types */ [[nodiscard]] PError unexpected(); template @@ -63,73 +67,45 @@ private: Spanner getSpanner(); - // used to parse library and schema + /** Base types */ PResult parseString(); - PResult parseColor(); - PResult parseIdentifier(); - PResult parseNumber(); - - PResult parseCount(); - + PResult parseNumberPair(); PResult parseProperty(std::optional valueType); - - PResult parseEnumeration(); - - PResult parseConnectionWire(); - - PResult parseComponent(); - - PResult parseAddress(); - - PResult parsePin(); - - PResult parseDisplay(); - - PResult parsePinConnection(); - - PResult parseAttribute(); - - PResult parsePopup(); - - PResult parseRule(); - - PResult parseBus(); - - PResult parseWire(); - - PResult parseConnection(); - - PResult parseDisplayItem(); - - PResult parseIfStatement(); - + PResult parseStringProperty(); PResult parseValue(); - // used to parse schema - PResult parsePosition(); - - PResult parseInstance(); - - PResult parseInstanceAttribute(); - - PResult parseConnectionInstance(); - + /** Library types */ + PResult parseConnectionWire(); + PResult parseComponent(); PResult> parseComponentType(); - + PResult parseAddress(); + PResult parsePin(); + PResult parseDisplay(); + PResult parseAttribute(); + PResult parsePopup(); + PResult parseRule(); + PResult parseBus(); + PResult parseWire(); + PResult parseConnection(); + PResult parseConnectionComponent(); + PResult parseDisplayItem(); + PResult parseIfStatement(); PResult> parseBusType(); - PResult> parseConnectionType(); + /** Schema types */ + PResult parseInstance(); + PResult parseInstanceAttribute(); + PResult parseConnectionInstance(); + PResult parseConnectionComponentInstance(); public: explicit ComdelParser(std::vector tokens); std::optional parseSchema(); - std::optional parseLibrary(); - const std::vector &getErrors(); }; diff --git a/comdel/parser/parse_context.h b/comdel/parser/parse_context.h index b7d294e..b4cc42a 100644 --- a/comdel/parser/parse_context.h +++ b/comdel/parser/parse_context.h @@ -7,6 +7,7 @@ #include #include +/*** 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 fileMap; diff --git a/comdel/parser/token.h b/comdel/parser/token.h index 18b5903..4418719 100644 --- a/comdel/parser/token.h +++ b/comdel/parser/token.h @@ -101,7 +101,6 @@ enum class TokenType { KW_SCHEMA, KW_POSITION, KW_SIZE, - KW_UNKNOWN, // TYPES INT_TYPE, diff --git a/examples/simplified FRISC model/frisc_library.csl b/examples/simplified FRISC model/frisc_library.csl index 41eb295..9ccdb59 100644 --- a/examples/simplified FRISC model/frisc_library.csl +++ b/examples/simplified FRISC model/frisc_library.csl @@ -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;