diff --git a/comdel/parser/comdelparser.cpp b/comdel/parser/comdelparser.cpp index 13e4eb7..5b1ec8f 100644 --- a/comdel/parser/comdelparser.cpp +++ b/comdel/parser/comdelparser.cpp @@ -145,6 +145,30 @@ ComdelParser::parseList(std::optional openDelim, return vec; } +void ComdelParser::skipUntilNextKeyword() { + int depth = 0; + bool enteredBlock = false; + + while(true) { + if(is_keyword(current().type) && (!enteredBlock || (enteredBlock && depth == 0))) { + break; + } + + if(check(TokenType::LBRACE)) { + enteredBlock = true; + depth++; + } else if(check(TokenType::RBRACE)) { + if(depth == 0) { + break; + } + depth--; + } else if(check(TokenType::END_OF_FILE)) { + break; + } + bump(); + } +} + const std::vector &ComdelParser::getErrors() { return errors; @@ -241,12 +265,17 @@ std::optional ComdelParser::parse() false, [this]{return parseProperty(std::optional(TokenType::STRING));} )); + if(!err.has_value()) { + skipUntilNextKeyword(); + bump(); + } } else { err = unexpected(); + bump(); } if(!err.has_value()) { errors.push_back(err.error()); - break; + skipUntilNextKeyword(); } } @@ -417,25 +446,32 @@ PResult ComdelParser::parseComponent() PResult> err; if(check(TokenType::KW_INSTANCE_NAME)) { bump(); - ASSIGN_OR_RETURN_IF_ERR(component.instanceName, parseString()); + ASSIGN_OR_SET_ERR(component.instanceName, parseString()); } else if(check(TokenType::KW_TOOLTIP)) { bump(); - ASSIGN_OR_RETURN_IF_ERR(component.tooltip, parseString()); + ASSIGN_OR_SET_ERR(component.tooltip, parseString()); } else if(check(TokenType::KW_SOURCE)) { bump(); - ASSIGN_OR_RETURN_IF_ERR(component.source, parseString()); + ASSIGN_OR_SET_ERR(component.source, parseString()); } else if(check(TokenType::KW_COUNT)) { - ASSIGN_OR_RETURN_IF_ERR(component.count, parseCount()); + ASSIGN_OR_SET_ERR(component.count, parseCount()); } else if(check(TokenType::KW_DISPLAY)) { - ASSIGN_OR_RETURN_IF_ERR(component.display, parseDisplay()); + ASSIGN_OR_SET_ERR(component.display, parseDisplay()); } else if(check(TokenType::KW_PIN)) { - APPEND_OR_RETURN_IF_ERR(component.pins, parsePin()); + APPEND_OR_SET_ERR(component.pins, parsePin()); } else if(check(TokenType::KW_ATTRIBUTE)) { - APPEND_OR_RETURN_IF_ERR(component.attributes, parseAttribute()); + APPEND_OR_SET_ERR(component.attributes, parseAttribute()); } else if(check(TokenType::KW_RULE)) { - APPEND_OR_RETURN_IF_ERR(component.rules, parseRule()); + APPEND_OR_SET_ERR(component.rules, parseRule()); } else { - return unexpected(); + err = unexpected(); + } + if(!err.has_value()) { + errors.push_back(err.error()); + skipUntilNextKeyword(); + if(check(TokenType::END_OF_FILE)) { + return PError({Span(spanner.lo), "Reached EOF"}); + } } } @@ -526,6 +562,7 @@ PResult ComdelParser::parseBus() { RETURN_IF_NOT_TOKEN(TokenType::LBRACE); while(!check(TokenType::RBRACE)) { + PResult> err; if(check(TokenType::KW_TOOLTIP)) { bump(); ASSIGN_OR_RETURN_IF_ERR(bus.tooltip, parseString()); @@ -545,7 +582,14 @@ PResult ComdelParser::parseBus() { } RETURN_IF_NOT_TOKEN(TokenType::RBRACE); } else { - return unexpected(); + err = unexpected(); + } + if(!err.has_value()) { + errors.push_back(err.error()); + skipUntilNextKeyword(); + if(check(TokenType::END_OF_FILE)) { + return PError({Span(spanner.lo), "Reached EOF"}); + } } } @@ -668,13 +712,14 @@ PResult ComdelParser::parsePin() { RETURN_IF_NOT_TOKEN(TokenType::LBRACE); while(!check(TokenType::RBRACE)) { + PResult> err; if (check(TokenType::KW_TOOLTIP)) { bump(); - ASSIGN_OR_RETURN_IF_ERR(pin.tooltip, parseString()); + ASSIGN_OR_SET_ERR(pin.tooltip, parseString()); } else if (check(TokenType::KW_DISPLAY)) { - ASSIGN_OR_RETURN_IF_ERR(pin.display, parseDisplay()); + ASSIGN_OR_SET_ERR(pin.display, parseDisplay()); } else if (check(TokenType::KW_CONNECTION)) { - ASSIGN_OR_RETURN_IF_ERR(pin.connection, parsePinConnection()); + ASSIGN_OR_SET_ERR(pin.connection, parsePinConnection()); } else if (check(TokenType::KW_WIRES)){ bump(); auto wires = parseList(std::optional(TokenType::LBRACE), TokenType::RBRACE, std::optional(TokenType::COMMA), false, @@ -682,7 +727,14 @@ PResult ComdelParser::parsePin() { RETURN_IF_ERR(wires); pin.wires = *wires; } else { - return unexpected(); + err = unexpected(); + } + if(!err.has_value()) { + errors.push_back(err.error()); + skipUntilNextKeyword(); + if(check(TokenType::END_OF_FILE)) { + return PError({Span(spanner.lo), "Reached EOF"}); + } } } @@ -873,18 +925,19 @@ PResult ComdelParser::parsePopup() { RETURN_IF_NOT_TOKEN(TokenType::LBRACE); while(!check(TokenType::RBRACE)) { + PResult> err; if(check(TokenType::KW_TITLE)) { bump(); - ASSIGN_OR_RETURN_IF_ERR(popup.title, parseString()); + ASSIGN_OR_SET_ERR(popup.title, parseString()); } else if(check(TokenType::KW_TEXT)) { bump(); - ASSIGN_OR_RETURN_IF_ERR(popup.text, parseString()); + ASSIGN_OR_SET_ERR(popup.text, parseString()); } else if(check(TokenType::KW_RULE)) { - APPEND_OR_RETURN_IF_ERR(popup.rules, parseRule()); + APPEND_OR_SET_ERR(popup.rules, parseRule()); } else if(check(TokenType::KW_ENUMERATED)) { bump(); popup.enumerated = true; - ASSIGN_OR_RETURN_IF_ERR(popup.enumeration, + ASSIGN_OR_SET_ERR(popup.enumeration, parseList( std::optional(TokenType::LBRACE), TokenType::RBRACE, @@ -894,7 +947,14 @@ PResult ComdelParser::parsePopup() { ) ); } else { - return unexpected(); + err = unexpected(); + } + if(!err.has_value()) { + errors.push_back(err.error()); + skipUntilNextKeyword(); + if(check(TokenType::END_OF_FILE)) { + return PError({Span(spanner.lo), "Reached EOF"}); + } } } @@ -938,6 +998,7 @@ PResult ComdelParser::parseConnection() { int wireCount = 0; 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)) { @@ -954,7 +1015,14 @@ PResult ComdelParser::parseConnection() { } wireCount++; } else { - return unexpected(); + err = unexpected(); + } + if(!err.has_value()) { + errors.push_back(err.error()); + skipUntilNextKeyword(); + if(check(TokenType::END_OF_FILE)) { + return PError({Span(spanner.lo), "Reached EOF"}); + } } } @@ -1108,10 +1176,11 @@ std::optional ComdelParser::parseSchema() { APPEND_OR_SET_ERR(schema.connections, parseConnectionInstance()); } else { err = unexpected(); + bump(); } if(!err.has_value()) { errors.push_back(err.error()); - break; + skipUntilNextKeyword(); } } if(!check(TokenType::RBRACE)) { @@ -1139,12 +1208,20 @@ PResult ComdelParser::parseWireInstance() { RETURN_IF_NOT_TOKEN(TokenType::LBRACE); while(!check(TokenType::RBRACE)) { + PResult> err; if(check(TokenType::KW_POSITION)) { - ASSIGN_OR_RETURN_IF_ERR(wireInstance.position, parsePosition()); + ASSIGN_OR_SET_ERR(wireInstance.position, parsePosition()); } else if(check(TokenType::KW_DISPLAY)) { - ASSIGN_OR_RETURN_IF_ERR(wireInstance.display, parseDisplay()); + ASSIGN_OR_SET_ERR(wireInstance.display, parseDisplay()); } else { - return unexpected(); + err = unexpected(); + } + if(!err.has_value()) { + errors.push_back(err.error()); + skipUntilNextKeyword(); + if(check(TokenType::END_OF_FILE)) { + return PError({Span(spanner.lo), "Reached EOF"}); + } } } @@ -1192,17 +1269,25 @@ PResult ComdelParser::parseInstance() { RETURN_IF_NOT_TOKEN(TokenType::LBRACE); while(!check(TokenType::RBRACE)) { + PResult> err; if(check(TokenType::KW_POSITION)) { - ASSIGN_OR_RETURN_IF_ERR(instance.position, parsePosition()); + ASSIGN_OR_SET_ERR(instance.position, parsePosition()); } else if(check(TokenType::KW_ATTRIBUTE)) { - APPEND_OR_RETURN_IF_ERR(instance.attributes, parseInstanceAttribute()); + APPEND_OR_SET_ERR(instance.attributes, parseInstanceAttribute()); } else if(check(TokenType::KW_SIZE)) { bump(); auto number = parseNumber(); RETURN_IF_ERR(number); instance.size = *number; } else { - return unexpected(); + err = unexpected(); + } + if(!err.has_value()) { + errors.push_back(err.error()); + skipUntilNextKeyword(); + if(check(TokenType::END_OF_FILE)) { + return PError({Span(spanner.lo), "Reached EOF"}); + } } } @@ -1247,13 +1332,21 @@ PResult ComdelParser::parseConnectionInstance() { RETURN_IF_NOT_TOKEN(TokenType::LBRACE); while(!check(TokenType::RBRACE)) { + PResult> err; if(check(TokenType::KW_WIRE)) { bump(); - ASSIGN_OR_RETURN_IF_ERR(connection.wire, parseIdentifier()); + ASSIGN_OR_SET_ERR(connection.wire, parseIdentifier()); } else if(check(TokenType::KW_ATTRIBUTE)) { - APPEND_OR_RETURN_IF_ERR(connection.attributes, parseInstanceAttribute()); + APPEND_OR_SET_ERR(connection.attributes, parseInstanceAttribute()); } else { - return unexpected(); + err = unexpected(); + } + if(!err.has_value()) { + errors.push_back(err.error()); + skipUntilNextKeyword(); + if(check(TokenType::END_OF_FILE)) { + return PError({Span(spanner.lo), "Reached EOF"}); + } } } diff --git a/comdel/parser/comdelparser.h b/comdel/parser/comdelparser.h index 55f95f5..6e75dc8 100644 --- a/comdel/parser/comdelparser.h +++ b/comdel/parser/comdelparser.h @@ -16,13 +16,14 @@ /// Spanner's call operator MOVES from the node so it should /// be always used last. class Spanner { - const Span lo; // the low end of the span, beginning of the node - // REFERENCE to the parser's prevSpan. After parsing a node this will // "point" to the span of the last token contained in the node. const Span& prevSpan; public: + const Span lo; // the low end of the span, beginning of the node + + Spanner(Span lo, Span& prevSpan) : lo(lo), prevSpan(prevSpan) {} template ::value>> @@ -48,6 +49,8 @@ private: bool consume(TokenType tokenType); bool check(TokenType tokenType); + void skipUntilNextKeyword(); + Token ¤t(); [[nodiscard]] PError unexpected(); @@ -61,7 +64,6 @@ private: Spanner getSpanner(); - PResult parseString(); PResult parseIdentifier(); PResult parseNumber(); diff --git a/comdel/parser/tokenstype.cpp b/comdel/parser/tokenstype.cpp index 3134bdc..5bbfad1 100644 --- a/comdel/parser/tokenstype.cpp +++ b/comdel/parser/tokenstype.cpp @@ -20,6 +20,7 @@ struct TokenTables { std::unordered_map keywords; TokenType tokenize(std::string value, TokenType initial); + bool is_keyword(TokenType token); void add(TokenType tokenType, const std::string& txt, unsigned short attribs = 0); @@ -41,7 +42,7 @@ void TokenTables::add (TokenType tokenType, const std::string& txt, TokenTables::TokenTables() { add( TokenType::IDENTIFIER, "identifier" ); - add( TokenType::KEYWORD, "keyword" ); + add( TokenType::KEYWORD, "keyword" , KEYWORD_NAME); // Literals (bool is not here, it has two keywords: false and true) add( TokenType::NUMBER, "number"); @@ -79,34 +80,34 @@ TokenTables::TokenTables() { add( TokenType::NIL, "null", TOKENIZABLE), // all keywords - add( TokenType::KW_NAME, "@name", TOKENIZABLE), - add( TokenType::KW_INFO, "@info", TOKENIZABLE), - add( TokenType::KW_HEADER, "@header", TOKENIZABLE), - add( TokenType::KW_DIRECTORY, "@directory", TOKENIZABLE), - add( TokenType::KW_LIBRARY, "@library", TOKENIZABLE), - add( TokenType::KW_ADDRESS, "@address", TOKENIZABLE), - add( TokenType::KW_COMPONENT, "@component", TOKENIZABLE), - add( TokenType::KW_MESSAGES, "@messages", TOKENIZABLE), - add( TokenType::KW_INSTANCE_NAME, "@instanceName", TOKENIZABLE), - add( TokenType::KW_COUNT, "@count", TOKENIZABLE), - add( TokenType::KW_DISPLAY, "@display", TOKENIZABLE), - add( TokenType::KW_PIN, "@pin", TOKENIZABLE), - add( TokenType::KW_TOOLTIP, "@tooltip", TOKENIZABLE), - add( TokenType::KW_CONNECTION, "@connection", TOKENIZABLE), - add( TokenType::KW_ATTRIBUTE, "@attribute", TOKENIZABLE), - add( TokenType::KW_SOURCE, "@source", TOKENIZABLE), - add( TokenType::KW_POPUP, "@popup", TOKENIZABLE), - add( TokenType::KW_RULE, "@rule", TOKENIZABLE), - add( TokenType::KW_TITLE, "@title", TOKENIZABLE), - add( TokenType::KW_TEXT, "@text", TOKENIZABLE), - add( TokenType::KW_BUS, "@bus", TOKENIZABLE), - add( TokenType::KW_WIRES, "@wires", TOKENIZABLE), - add( TokenType::KW_ENUMERATED, "@enumerated", TOKENIZABLE), - add( TokenType::KW_WIRE, "@wire", TOKENIZABLE), - add( TokenType::KW_INSTANCE, "@instance", TOKENIZABLE), - add( TokenType::KW_SCHEMA, "@schema", TOKENIZABLE), - add( TokenType::KW_POSITION, "@position", TOKENIZABLE), - add( TokenType::KW_SIZE, "@size", TOKENIZABLE), + add( TokenType::KW_NAME, "@name", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_INFO, "@info", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_HEADER, "@header", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_DIRECTORY, "@directory", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_LIBRARY, "@library", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_ADDRESS, "@address", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_COMPONENT, "@component", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_MESSAGES, "@messages", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_INSTANCE_NAME, "@instanceName", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_COUNT, "@count", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_DISPLAY, "@display", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_PIN, "@pin", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_TOOLTIP, "@tooltip", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_CONNECTION, "@connection", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_ATTRIBUTE, "@attribute", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_SOURCE, "@source", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_POPUP, "@popup", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_RULE, "@rule", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_TITLE, "@title", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_TEXT, "@text", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_BUS, "@bus", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_WIRES, "@wires", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_ENUMERATED, "@enumerated", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_WIRE, "@wire", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_INSTANCE, "@instance", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_SCHEMA, "@schema", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_POSITION, "@position", TOKENIZABLE | KEYWORD_NAME), + add( TokenType::KW_SIZE, "@size", TOKENIZABLE | KEYWORD_NAME), // All types add( TokenType::INT_TYPE, "int", TOKENIZABLE), @@ -156,6 +157,19 @@ TokenType TokenTables::tokenize(std::string value, TokenType initial) { return initial; } +bool TokenTables::is_keyword(TokenType token) { + for(auto& [key, param]: allTokensInfo) { + if(param.attributes & KEYWORD_NAME && key == token) { + return true; + } + } + return false; +} + TokenType from_token(std::string value, TokenType initial) { return tokenTables.tokenize(value, initial); +} + +bool is_keyword(TokenType tokenType) { + return tokenTables.is_keyword(tokenType); } \ No newline at end of file diff --git a/comdel/parser/tokenstype.h b/comdel/parser/tokenstype.h index a82efb9..30a4b68 100644 --- a/comdel/parser/tokenstype.h +++ b/comdel/parser/tokenstype.h @@ -10,4 +10,6 @@ const std::string& tokenTypeToString(TokenType tokenType); TokenType from_token(std::string value, TokenType initial); +bool is_keyword(TokenType tokenType); + #endif // TOKENS_TYPE_H diff --git a/mainwindow.cpp b/mainwindow.cpp index 3926463..f1bbb5d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -93,7 +93,7 @@ void MainWindow::onLoadLibrary() { } } else { - buffer<<"Bad request"<instances) { auto componentInstance = dynamic_cast(instance); - if(componentInstance != NULL) { + if(componentInstance != nullptr) { buffer << "\t" << "@instance " << componentInstance->name << " " << componentInstance->component.getName() << " {" << std::endl; buffer << "\t\t" << "@position (" << componentInstance->position.first << ", " << componentInstance->position.second << ")" << std::endl; @@ -170,7 +170,7 @@ void MainWindow::onStoreScheme() { } auto busInstance = dynamic_cast(instance); - if(busInstance != NULL) { + if(busInstance != nullptr) { buffer << "\t" << "@instance " << busInstance->name << " " << busInstance->bus.getName() << " {" << std::endl; buffer << "\t\t" << "@position (" << busInstance->position.first << ", " << busInstance->position.second << ")" << std::endl; buffer << "\t\t" << "@size " << busInstance->size << std::endl; @@ -236,10 +236,10 @@ void MainWindow::onValidateSchema(bool /*toggled*/) { std::ostringstream buff; for(auto err: errors) { - if(err.instance != NULL) { + if(err.instance != nullptr) { buff << err.instance->name; } - if(err.attribute != NULL) { + if(err.attribute != nullptr) { buff << "::" << err.attribute->name; } if(err.type == domain::Action::ERROR) {