parse suggested actions

This commit is contained in:
Chris Cromer 2023-02-16 00:35:29 -03:00
parent 6062004f67
commit bc93f42c00
Signed by: cromer
GPG Key ID: FA91071797BEEEC2
3 changed files with 310 additions and 69 deletions

View File

@ -89,7 +89,7 @@ int obelisk::mainLoop(const std::vector<std::string>& sourceFiles, const std::st
// parser->handleRule(); // parser->handleRule();
break; break;
case obelisk::Lexer::kTokenAction : case obelisk::Lexer::kTokenAction :
// parser->handleAction(); parser->handleAction(kb);
break; break;
default : default :
parser->getNextToken(); parser->getNextToken();

View File

@ -1,9 +1,6 @@
#include "ast/call_expression_ast.h" #include "ast/call_expression_ast.h"
#include "ast/number_expression_ast.h" #include "ast/number_expression_ast.h"
#include "ast/variable_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 "parser.h"
#include <memory> #include <memory>
@ -214,11 +211,205 @@ std::unique_ptr<obelisk::PrototypeAST> obelisk::Parser::parseExtern()
return parsePrototype(); return parsePrototype();
} }
std::unique_ptr<obelisk::ExpressionAST> obelisk::Parser::parseAction() void obelisk::Parser::parseAction(obelisk::SuggestAction& suggestAction)
{ {
std::stack<char> 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::ExpressionAST> obelisk::Parser::parseRule() void obelisk::Parser::parseRule(std::vector<obelisk::Rule>& rules)
{ {
} }
@ -240,7 +431,7 @@ void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
std::string entityName {""}; std::string entityName {""};
std::string verb {""}; std::string verb {""};
getNextToken(); getNextToken();
while (true) //left side of fact while (true)
{ {
if (getEntity) if (getEntity)
{ {
@ -286,6 +477,15 @@ void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
if (getCurrentToken() == ')') if (getCurrentToken() == ')')
{ {
// closing parenthesis found, make sure we have everything needed // closing parenthesis found, make sure we have everything needed
if (syntax.top() != '(')
{
throw obelisk::ParserException("unexpected ')'");
}
else
{
syntax.pop();
}
if (verb == "") if (verb == "")
{ {
throw obelisk::ParserException("verb is empty"); throw obelisk::ParserException("verb is empty");
@ -300,6 +500,7 @@ void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
{ {
throw obelisk::ParserException("missing right side entities"); throw obelisk::ParserException("missing right side entities");
} }
break; break;
} }
@ -337,6 +538,22 @@ void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
void obelisk::Parser::handleAction(std::unique_ptr<obelisk::KnowledgeBase>& kb) void obelisk::Parser::handleAction(std::unique_ptr<obelisk::KnowledgeBase>& 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<obelisk::KnowledgeBase>& kb) void obelisk::Parser::handleRule(std::unique_ptr<obelisk::KnowledgeBase>& kb)
@ -346,88 +563,103 @@ void obelisk::Parser::handleRule(std::unique_ptr<obelisk::KnowledgeBase>& kb)
void obelisk::Parser::handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb) void obelisk::Parser::handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb)
{ {
std::vector<obelisk::Fact> facts; std::vector<obelisk::Fact> facts;
parseFact(facts); try
{
parseFact(facts);
}
catch (obelisk::ParserException& exception)
{
throw;
}
int verbId = 0; int verbId = 0;
for (auto& fact : facts) for (auto& fact : facts)
{ {
std::vector<obelisk::Entity> entities {fact.getLeftEntity()}; try
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)
{ {
obelisk::Entity entity = fact.getLeftEntity(); insertEntity(kb, fact.getLeftEntity());
kb->getEntity(entity); insertEntity(kb, fact.getRightEntity());
if (entity.getId() == 0)
{
throw obelisk::ParserException("left entity could not be inserted into the database");
}
else
{
fact.setLeftEntity(entity);
}
} }
catch (obelisk::ParserException& exception)
entities = {fact.getRightEntity()};
kb->addEntities(entities);
fact.setRightEntity(entities.front());
if (fact.getRightEntity().getId() == 0)
{ {
obelisk::Entity entity = fact.getRightEntity(); throw;
kb->getEntity(entity);
if (entity.getId() == 0)
{
throw obelisk::ParserException("right entity could not be inserted into the database");
}
else
{
fact.setRightEntity(entity);
}
} }
if (verbId == 0) if (verbId == 0)
{ {
std::vector<obelisk::Verb> verbs = {fact.getVerb()}; try
kb->addVerbs(verbs);
if (verbs.front().getId() != 0)
{ {
fact.setVerb(verbs.front()); insertVerb(kb, fact.getVerb());
verbId = fact.getVerb().getId();
} }
else catch (obelisk::ParserException& exception)
{ {
obelisk::Verb verb = fact.getVerb(); throw;
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();
}
} }
verbId = fact.getVerb().getId();
} }
else else
{ {
fact.getVerb().setId(verbId); fact.getVerb().setId(verbId);
} }
std::vector<obelisk::Fact> facts {fact}; try
kb->addFacts(facts);
fact = facts.front();
if (fact.getId() == 0)
{ {
kb->getFact(fact); insertFact(kb, fact);
if (fact.getId() == 0) }
{ catch (obelisk::ParserException& exception)
throw obelisk::ParserException("fact could not be inserted into the database"); {
} throw;
}
}
}
void obelisk::Parser::insertEntity(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Entity& entity)
{
std::vector<obelisk::Entity> 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<obelisk::KnowledgeBase>& kb, obelisk::Verb& verb)
{
std::vector<obelisk::Verb> 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<obelisk::KnowledgeBase>& kb, obelisk::Fact& fact)
{
std::vector<obelisk::Fact> 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");
} }
} }
} }

View File

@ -6,7 +6,12 @@
#include "ast/prototype_ast.h" #include "ast/prototype_ast.h"
#include "knowledge_base.h" #include "knowledge_base.h"
#include "lexer.h" #include "lexer.h"
#include "models/action.h"
#include "models/entity.h"
#include "models/fact.h" #include "models/fact.h"
#include "models/rule.h"
#include "models/suggest_action.h"
#include "models/verb.h"
#include <memory> #include <memory>
@ -32,8 +37,8 @@ namespace obelisk
std::unique_ptr<obelisk::FunctionAST> parseDefinition(); std::unique_ptr<obelisk::FunctionAST> parseDefinition();
std::unique_ptr<obelisk::FunctionAST> parseTopLevelExpression(); std::unique_ptr<obelisk::FunctionAST> parseTopLevelExpression();
std::unique_ptr<obelisk::PrototypeAST> parseExtern(); std::unique_ptr<obelisk::PrototypeAST> parseExtern();
std::unique_ptr<obelisk::ExpressionAST> parseAction(); void parseAction(obelisk::SuggestAction& suggestAction);
std::unique_ptr<obelisk::ExpressionAST> parseRule(); void parseRule(std::vector<obelisk::Rule>& rules);
void parseFact(std::vector<obelisk::Fact>& facts); void parseFact(std::vector<obelisk::Fact>& facts);
public: public:
@ -55,6 +60,10 @@ namespace obelisk
void handleAction(std::unique_ptr<obelisk::KnowledgeBase>& kb); void handleAction(std::unique_ptr<obelisk::KnowledgeBase>& kb);
void handleRule(std::unique_ptr<obelisk::KnowledgeBase>& kb); void handleRule(std::unique_ptr<obelisk::KnowledgeBase>& kb);
void handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb); void handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb);
void insertEntity(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Entity& entity);
void insertVerb(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Verb& verb);
void insertFact(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Fact& fact);
}; };
class ParserException : public std::exception class ParserException : public std::exception