From bc93f42c00a4d0eef0cfb4e0340fa8d1a46a8076 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Thu, 16 Feb 2023 00:35:29 -0300 Subject: [PATCH] parse suggested actions --- src/obelisk.cpp | 2 +- src/parser.cpp | 364 +++++++++++++++++++++++++++++++++++++++--------- src/parser.h | 13 +- 3 files changed, 310 insertions(+), 69 deletions(-) diff --git a/src/obelisk.cpp b/src/obelisk.cpp index 8d64044..6b6a71d 100644 --- a/src/obelisk.cpp +++ b/src/obelisk.cpp @@ -89,7 +89,7 @@ int obelisk::mainLoop(const std::vector& sourceFiles, const std::st // parser->handleRule(); break; case obelisk::Lexer::kTokenAction : - // parser->handleAction(); + parser->handleAction(kb); break; default : parser->getNextToken(); diff --git a/src/parser.cpp b/src/parser.cpp index b30c75b..9ac6841 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,9 +1,6 @@ #include "ast/call_expression_ast.h" #include "ast/number_expression_ast.h" #include "ast/variable_expression_ast.h" -#include "models/entity.h" -#include "models/fact.h" -#include "models/verb.h" #include "parser.h" #include @@ -214,11 +211,205 @@ std::unique_ptr obelisk::Parser::parseExtern() return parsePrototype(); } -std::unique_ptr obelisk::Parser::parseAction() +void obelisk::Parser::parseAction(obelisk::SuggestAction& suggestAction) { + std::stack syntax; + + getNextToken(); + if (getCurrentToken() != '(') + { + throw obelisk::ParserException("expected '(' but got '" + std::to_string(getCurrentToken()) + "'"); + } + + syntax.push('('); + + getNextToken(); + if (getLexer()->getIdentifier() != "if") + { + throw obelisk::ParserException("expected 'if' but got '" + getLexer()->getIdentifier() + "'"); + } + + bool getEntity {true}; + std::string leftEntity {""}; + std::string rightEntity {""}; + std::string trueAction {""}; + std::string falseAction {""}; + std::string entityName {""}; + std::string verb {""}; + getNextToken(); + + // get the entity side of statement + while (true) + { + if (getEntity) + { + if (getCurrentToken() == '"') + { + if (syntax.top() != '"') + { + // open a double quote + syntax.push('"'); + getNextToken(); + } + else if (syntax.top() == '"') + { + // close a double quote + syntax.pop(); + if (verb == "") + { + leftEntity = entityName; + } + else + { + rightEntity = entityName; + } + entityName = ""; + getEntity = false; + getNextToken(); + continue; + } + } + + if (syntax.top() == '"') + { + if (entityName != "") + { + entityName += " "; + } + entityName += getLexer()->getIdentifier(); + } + getNextToken(); + } + else + { + if (getCurrentToken() == ')') + { + throw obelisk::ParserException("unexpected ')'"); + } + + if (getCurrentToken() == '"') + { + throw obelisk::ParserException("unexpected '\"'"); + break; + } + + if (getLexer()->getIdentifier() == "and") + { + getNextToken(); + getEntity = true; + continue; + } + else if (getLexer()->getIdentifier() == "then") + { + break; + } + else + { + verb = getLexer()->getIdentifier(); + // TODO: make sure verb is alphabetic + getEntity = true; + continue; + } + } + } + + // get the action side of statement + bool getAction {true}; + while (true) + { + if (getAction) + { + if (getCurrentToken() == '"') + { + if (syntax.top() != '"') + { + // open a double quote + syntax.push('"'); + getNextToken(); + } + else if (syntax.top() == '"') + { + // close a double quote + syntax.pop(); + if (trueAction == "") + { + trueAction = entityName; + } + else + { + falseAction = entityName; + } + entityName = ""; + getAction = false; + getNextToken(); + continue; + } + } + + if (syntax.top() == '"') + { + if (entityName != "") + { + entityName += " "; + } + entityName += getLexer()->getIdentifier(); + } + getNextToken(); + } + else + { + if (getCurrentToken() == ')') + { + // closing parenthesis found, make sure we have everything needed + if (syntax.top() != '(') + { + throw obelisk::ParserException("unexpected ')'"); + } + else + { + syntax.pop(); + } + + if (trueAction == "") + { + throw obelisk::ParserException("missing true action"); + } + + if (falseAction == "") + { + throw obelisk::ParserException("missing false action"); + } + + break; + } + + if (getCurrentToken() == '"') + { + throw obelisk::ParserException("unexpected '\"'"); + break; + } + + if (getLexer()->getIdentifier() == "or") + { + getNextToken(); + getAction = true; + continue; + } + else + { + getAction = true; + continue; + } + } + } + + suggestAction.setFact( + obelisk::Fact(obelisk::Entity(leftEntity), obelisk::Entity(rightEntity), obelisk::Verb(verb))); + suggestAction.setTrueAction(obelisk::Action(trueAction)); + suggestAction.setTrueAction(obelisk::Action(falseAction)); } -std::unique_ptr obelisk::Parser::parseRule() +void obelisk::Parser::parseRule(std::vector& rules) { } @@ -240,7 +431,7 @@ void obelisk::Parser::parseFact(std::vector& facts) std::string entityName {""}; std::string verb {""}; getNextToken(); - while (true) //left side of fact + while (true) { if (getEntity) { @@ -286,6 +477,15 @@ void obelisk::Parser::parseFact(std::vector& facts) if (getCurrentToken() == ')') { // closing parenthesis found, make sure we have everything needed + if (syntax.top() != '(') + { + throw obelisk::ParserException("unexpected ')'"); + } + else + { + syntax.pop(); + } + if (verb == "") { throw obelisk::ParserException("verb is empty"); @@ -300,6 +500,7 @@ void obelisk::Parser::parseFact(std::vector& facts) { throw obelisk::ParserException("missing right side entities"); } + break; } @@ -337,6 +538,22 @@ void obelisk::Parser::parseFact(std::vector& facts) void obelisk::Parser::handleAction(std::unique_ptr& kb) { + obelisk::SuggestAction suggestAction; + parseAction(suggestAction); + + try + { + insertEntity(kb, suggestAction.getFact().getLeftEntity()); + insertEntity(kb, suggestAction.getFact().getRightEntity()); + insertVerb(kb, suggestAction.getFact().getVerb()); + insertFact(kb, suggestAction.getFact()); + + // TODO: insert the actions, then insert the suggested action + } + catch (obelisk::ParserException& exception) + { + throw; + } } void obelisk::Parser::handleRule(std::unique_ptr& kb) @@ -346,88 +563,103 @@ void obelisk::Parser::handleRule(std::unique_ptr& kb) void obelisk::Parser::handleFact(std::unique_ptr& kb) { std::vector facts; - parseFact(facts); + try + { + parseFact(facts); + } + catch (obelisk::ParserException& exception) + { + throw; + } int verbId = 0; for (auto& fact : facts) { - std::vector entities {fact.getLeftEntity()}; - kb->addEntities(entities); - fact.setLeftEntity(entities.front()); - - // the id was not inserted, so check if it exists in the database - if (fact.getLeftEntity().getId() == 0) + try { - obelisk::Entity entity = fact.getLeftEntity(); - kb->getEntity(entity); - if (entity.getId() == 0) - { - throw obelisk::ParserException("left entity could not be inserted into the database"); - } - else - { - fact.setLeftEntity(entity); - } + insertEntity(kb, fact.getLeftEntity()); + insertEntity(kb, fact.getRightEntity()); } - - entities = {fact.getRightEntity()}; - kb->addEntities(entities); - fact.setRightEntity(entities.front()); - - if (fact.getRightEntity().getId() == 0) + catch (obelisk::ParserException& exception) { - obelisk::Entity entity = fact.getRightEntity(); - kb->getEntity(entity); - if (entity.getId() == 0) - { - throw obelisk::ParserException("right entity could not be inserted into the database"); - } - else - { - fact.setRightEntity(entity); - } + throw; } if (verbId == 0) { - std::vector verbs = {fact.getVerb()}; - kb->addVerbs(verbs); - if (verbs.front().getId() != 0) + try { - fact.setVerb(verbs.front()); - verbId = fact.getVerb().getId(); + insertVerb(kb, fact.getVerb()); } - else + catch (obelisk::ParserException& exception) { - obelisk::Verb verb = fact.getVerb(); - kb->getVerb(verb); - if (verb.getId() == 0) - { - throw obelisk::ParserException("verb could not be inserted into the database"); - } - else - { - fact.setVerb(verb); - verbId = fact.getVerb().getId(); - } + throw; } + verbId = fact.getVerb().getId(); } else { fact.getVerb().setId(verbId); } - std::vector facts {fact}; - kb->addFacts(facts); - fact = facts.front(); - - if (fact.getId() == 0) + try { - kb->getFact(fact); - if (fact.getId() == 0) - { - throw obelisk::ParserException("fact could not be inserted into the database"); - } + insertFact(kb, fact); + } + catch (obelisk::ParserException& exception) + { + throw; + } + } +} + +void obelisk::Parser::insertEntity(std::unique_ptr& kb, obelisk::Entity& entity) +{ + std::vector entities {entity}; + kb->addEntities(entities); + entity = std::move(entities.front()); + + // the id was not inserted, so check if it exists in the database + if (entity.getId() == 0) + { + kb->getEntity(entity); + if (entity.getId() == 0) + { + throw obelisk::ParserException("entity could not be inserted into the database"); + } + } +} + +void obelisk::Parser::insertVerb(std::unique_ptr& kb, obelisk::Verb& verb) +{ + std::vector verbs {verb}; + kb->addVerbs(verbs); + verb = std::move(verbs.front()); + + // the id was not inserted, so check if it exists in the database + if (verb.getId() == 0) + { + kb->getVerb(verb); + if (verb.getId() == 0) + { + throw obelisk::ParserException("verb could not be inserted into the database"); + } + } +} + +void obelisk::Parser::insertFact(std::unique_ptr& kb, obelisk::Fact& fact) +{ + std::vector facts {fact}; + kb->addFacts(facts); + fact = std::move(facts.front()); + + // the id was not inserted, so check if it exists in the database + if (fact.getId() == 0) + { + kb->getFact(fact); + if (fact.getId() == 0) + { + throw obelisk::ParserException("fact could not be inserted into the database"); } } } diff --git a/src/parser.h b/src/parser.h index 19b4a8b..bea0dd9 100644 --- a/src/parser.h +++ b/src/parser.h @@ -6,7 +6,12 @@ #include "ast/prototype_ast.h" #include "knowledge_base.h" #include "lexer.h" +#include "models/action.h" +#include "models/entity.h" #include "models/fact.h" +#include "models/rule.h" +#include "models/suggest_action.h" +#include "models/verb.h" #include @@ -32,8 +37,8 @@ namespace obelisk std::unique_ptr parseDefinition(); std::unique_ptr parseTopLevelExpression(); std::unique_ptr parseExtern(); - std::unique_ptr parseAction(); - std::unique_ptr parseRule(); + void parseAction(obelisk::SuggestAction& suggestAction); + void parseRule(std::vector& rules); void parseFact(std::vector& facts); public: @@ -55,6 +60,10 @@ namespace obelisk void handleAction(std::unique_ptr& kb); void handleRule(std::unique_ptr& kb); void handleFact(std::unique_ptr& kb); + + void insertEntity(std::unique_ptr& kb, obelisk::Entity& entity); + void insertVerb(std::unique_ptr& kb, obelisk::Verb& verb); + void insertFact(std::unique_ptr& kb, obelisk::Fact& fact); }; class ParserException : public std::exception