Updated error handling while parsing *.csl files

This commit is contained in:
Borna Rajković 2022-05-01 18:13:01 +02:00
parent d6c1023df2
commit dde9bb8af8
5 changed files with 179 additions and 68 deletions

View File

@ -145,6 +145,30 @@ ComdelParser::parseList(std::optional<TokenType> 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<SourceError> &ComdelParser::getErrors()
{
return errors;
@ -241,12 +265,17 @@ std::optional<LibraryNode> ComdelParser::parse()
false,
[this]{return parseProperty(std::optional<TokenType>(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<ComponentNode> ComdelParser::parseComponent()
PResult<poly<AstNode>> 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<BusNode> ComdelParser::parseBus() {
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while(!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> err;
if(check(TokenType::KW_TOOLTIP)) {
bump();
ASSIGN_OR_RETURN_IF_ERR(bus.tooltip, parseString());
@ -545,7 +582,14 @@ PResult<BusNode> 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<PinNode> ComdelParser::parsePin() {
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while(!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> 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<ValueNode>(std::optional<TokenType>(TokenType::LBRACE), TokenType::RBRACE, std::optional<TokenType>(TokenType::COMMA), false,
@ -682,7 +727,14 @@ PResult<PinNode> 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<PopupNode> ComdelParser::parsePopup() {
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while(!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> 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<EnumerationNode>(
std::optional<TokenType>(TokenType::LBRACE),
TokenType::RBRACE,
@ -894,7 +947,14 @@ PResult<PopupNode> 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<ConnectionNode> ComdelParser::parseConnection() {
int wireCount = 0;
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)) {
@ -954,7 +1015,14 @@ PResult<ConnectionNode> 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<SchemaNode> 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<WireInstanceNode> ComdelParser::parseWireInstance() {
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while(!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> 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<InstanceNode> ComdelParser::parseInstance() {
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while(!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> 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<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
while(!check(TokenType::RBRACE)) {
PResult<poly<AstNode>> 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"});
}
}
}

View File

@ -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 <typename T, typename = std::enable_if<std::is_base_of<AstNode, T>::value>>
@ -48,6 +49,8 @@ private:
bool consume(TokenType tokenType);
bool check(TokenType tokenType);
void skipUntilNextKeyword();
Token &current();
[[nodiscard]] PError unexpected();
@ -61,7 +64,6 @@ private:
Spanner getSpanner();
PResult<StringNode> parseString();
PResult<IdentifierNode> parseIdentifier();
PResult<NumberNode> parseNumber();

View File

@ -20,6 +20,7 @@ struct TokenTables {
std::unordered_map<std::string, TokenType> 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);
}

View File

@ -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

View File

@ -93,7 +93,7 @@ void MainWindow::onLoadLibrary() {
}
} else {
buffer<<"Bad request"<<std::endl;
buffer<<"Failed loading library"<<std::endl;
}
}
@ -158,7 +158,7 @@ void MainWindow::onStoreScheme() {
for(auto &instance: schema->instances) {
auto componentInstance = dynamic_cast<domain::ComponentInstance*>(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<domain::BusInstance*>(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) {