#include "ast/call_expression_ast.h" #include "ast/number_expression_ast.h" #include "ast/variable_expression_ast.h" #include "parser.h" #include #include #include #include std::shared_ptr obelisk::Parser::getLexer() { return lexer_; } void obelisk::Parser::setLexer(std::shared_ptr lexer) { lexer_ = lexer; currentToken_ = 0; } int obelisk::Parser::getNextToken() { try { setCurrentToken(getLexer()->getToken()); } catch (obelisk::LexerException& exception) { throw; } return getCurrentToken(); } int obelisk::Parser::getCurrentToken() { return currentToken_; } void obelisk::Parser::setCurrentToken(int currentToken) { currentToken_ = currentToken; } std::unique_ptr obelisk::Parser::logError( const char* str) { fprintf(stderr, "Error: %s\n", str); return nullptr; } std::unique_ptr obelisk::Parser::logErrorPrototype( const char* str) { logError(str); return nullptr; } std::unique_ptr obelisk::Parser::parseExpression() { auto LHS = parsePrimary(); if (!LHS) { return nullptr; } return LHS; } std::unique_ptr obelisk::Parser::parsePrimary() { switch (getCurrentToken()) { case obelisk::Lexer::kTokenIdentifier : return parseIdentifierExpression(); case obelisk::Lexer::kTokenNumber : return parseNumberExpression(); case '(' : return parseParenthesisExpression(); default : return logError("unknown token when expecting and expression"); } } std::unique_ptr obelisk::Parser::parseNumberExpression() { auto result = std::make_unique( getLexer()->getNumberValue()); getNextToken(); return result; } std::unique_ptr obelisk::Parser::parseParenthesisExpression() { getNextToken(); auto v = parseExpression(); if (!v) { return nullptr; } if (getCurrentToken() != ')') { return logError("expected ')'"); } getNextToken(); return v; } std::unique_ptr obelisk::Parser::parseIdentifierExpression() { std::string idName = getLexer()->getIdentifier(); getNextToken(); if (getCurrentToken() != '(') { return std::make_unique(idName); } getNextToken(); std::vector> args; if (getCurrentToken() != ')') { while (true) { if (auto arg = parseExpression()) { args.push_back(std::move(arg)); } else { return nullptr; } if (getCurrentToken() == ')') { break; } if (getCurrentToken() != ',') { return logError("Expected ')' or ',' in argument list"); } getNextToken(); } } getNextToken(); return std::make_unique(idName, std::move(args)); } std::unique_ptr obelisk::Parser::parsePrototype() { if (getCurrentToken() != obelisk::Lexer::kTokenIdentifier) { return logErrorPrototype("Expected function name in prototype"); } std::string functionName = getLexer()->getIdentifier(); getNextToken(); if (getCurrentToken() != '(') { return logErrorPrototype("Expected '(' in prototype"); } std::vector argNames; while (getNextToken() == obelisk::Lexer::kTokenIdentifier) { argNames.push_back(getLexer()->getIdentifier()); } if (getCurrentToken() != ')') { return logErrorPrototype("Expected ')' in prototype"); } getNextToken(); return std::make_unique(functionName, std::move(argNames)); } std::unique_ptr obelisk::Parser::parseDefinition() { getNextToken(); auto prototype = parsePrototype(); if (!prototype) { return nullptr; } if (auto expression = parseExpression()) { return std::make_unique(std::move(prototype), std::move(expression)); } return nullptr; } std::unique_ptr obelisk::Parser::parseTopLevelExpression() { if (auto expression = parseExpression()) { // Make an anonymous prototype auto prototype = std::make_unique("__anon_expr", std::vector()); return std::make_unique(std::move(prototype), std::move(expression)); } return nullptr; } std::unique_ptr obelisk::Parser::parseExtern() { getNextToken(); return parsePrototype(); } 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 = std::move(entityName); } else { rightEntity = std::move(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 '\"'"); } if (getLexer()->getIdentifier() == "then") { break; } else { verb = getLexer()->getIdentifier(); for (const auto& letter : verb) { if (!isalpha(letter)) { throw new obelisk::ParserException( "non alphabetic symbol in verb"); } } 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 = std::move(entityName); } else { falseAction = std::move(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 (leftEntity == "") { throw obelisk::ParserException("missing left entity"); } if (rightEntity == "") { throw obelisk::ParserException("missing left entity"); } if (verb == "") { throw obelisk::ParserException("missing verb"); } if (trueAction == "") { throw obelisk::ParserException("missing true action"); } if (falseAction == "") { throw obelisk::ParserException("missing false action"); } getNextToken(); if (getCurrentToken() != ';') { throw obelisk::ParserException("missing ';'"); } break; } if (getCurrentToken() == '"') { throw obelisk::ParserException("unexpected '\"'"); break; } if (getLexer()->getIdentifier() == "else") { 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.setFalseAction(obelisk::Action(falseAction)); } void obelisk::Parser::parseRule(obelisk::Rule& rule) { std::stack syntax; getNextToken(); if (getCurrentToken() != '(') { throw obelisk::ParserException( "expected '(' but got '" + std::to_string(getCurrentToken()) + "'"); } syntax.push('('); bool getEntity {true}; bool getReason {false}; std::string leftEntity {""}; std::string rightEntity {""}; std::string verb {""}; std::string leftReasonEntity {""}; std::string rightReasonEntity {""}; std::string reasonVerb {""}; std::string entityName {""}; 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 (!getReason) { if (verb == "") { leftEntity = std::move(entityName); } else { rightEntity = std::move(entityName); } } else { if (reasonVerb == "") { leftReasonEntity = std::move(entityName); } else { rightReasonEntity = std::move(entityName); } } getEntity = 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 (leftEntity == "") { throw obelisk::ParserException("missing left entity"); } if (rightEntity == "") { throw obelisk::ParserException("missing right entity"); } if (verb == "") { throw obelisk::ParserException("missing verb"); } if (leftReasonEntity == "") { throw obelisk::ParserException( "missing left reason entity"); } if (rightReasonEntity == "") { throw obelisk::ParserException( "missing right reason entity"); } if (reasonVerb == "") { throw obelisk::ParserException("missing reason verb"); } getNextToken(); if (getCurrentToken() != ';') { throw obelisk::ParserException("missing ';'"); } break; } if (getCurrentToken() == '"') { throw obelisk::ParserException("unexpected '\"'"); } if (getLexer()->getIdentifier() == "if") { getReason = true; getEntity = true; getNextToken(); continue; } else { if (!getReason) { verb = getLexer()->getIdentifier(); for (const auto& letter : verb) { if (!isalpha(letter)) { throw new obelisk::ParserException( "non alphabetic symbol in verb"); } } getEntity = true; continue; } else { reasonVerb = getLexer()->getIdentifier(); for (const auto& letter : reasonVerb) { if (!isalpha(letter)) { throw new obelisk::ParserException( "non alphabetic symbol in verb"); } } getEntity = true; continue; } } } } rule.setFact(obelisk::Fact(obelisk::Entity(leftEntity), obelisk::Entity(rightEntity), obelisk::Verb(verb))); rule.setReason(obelisk::Fact(obelisk::Entity(leftReasonEntity), obelisk::Entity(rightReasonEntity), obelisk::Verb(reasonVerb))); } void obelisk::Parser::parseFact(std::vector& facts) { std::stack syntax; getNextToken(); if (getCurrentToken() != '(') { throw obelisk::ParserException( "expected '(' but got '" + std::to_string(getCurrentToken()) + "'"); } syntax.push('('); bool getEntity {true}; std::vector leftEntities; std::vector rightEntities; std::string entityName {""}; std::string verb {""}; getNextToken(); 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 == "") { leftEntities.push_back(entityName); } else { rightEntities.push_back(entityName); } entityName = ""; getEntity = 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 (verb == "") { throw obelisk::ParserException("verb is empty"); } if (leftEntities.size() == 0) { throw obelisk::ParserException( "missing left side entities"); } if (rightEntities.size() == 0) { throw obelisk::ParserException( "missing right side entities"); } getNextToken(); if (getCurrentToken() != ';') { throw obelisk::ParserException("missing ';'"); } break; } if (getCurrentToken() == '"') { throw obelisk::ParserException("unexpected '\"'"); } if (getLexer()->getIdentifier() == "and") { getNextToken(); getEntity = true; continue; } else { verb = getLexer()->getIdentifier(); for (const auto& letter : verb) { if (!isalpha(letter)) { throw new obelisk::ParserException( "non alphabetic symbol in verb"); } } getEntity = true; continue; } } } for (auto& leftEntity : leftEntities) { for (auto& rightEntity : rightEntities) { facts.push_back(obelisk::Fact(obelisk::Entity(leftEntity), obelisk::Entity(rightEntity), obelisk::Verb(verb), true)); } } } void obelisk::Parser::handleAction(std::unique_ptr& kb) { obelisk::SuggestAction suggestAction; try { parseAction(suggestAction); insertEntity(kb, suggestAction.getFact().getLeftEntity()); insertEntity(kb, suggestAction.getFact().getRightEntity()); insertVerb(kb, suggestAction.getFact().getVerb()); insertFact(kb, suggestAction.getFact()); insertAction(kb, suggestAction.getTrueAction()); insertAction(kb, suggestAction.getFalseAction()); insertSuggestAction(kb, suggestAction); } catch (obelisk::ParserException& exception) { throw; } } void obelisk::Parser::handleRule(std::unique_ptr& kb) { obelisk::Rule rule; try { parseRule(rule); insertEntity(kb, rule.getReason().getLeftEntity()); insertEntity(kb, rule.getReason().getRightEntity()); insertVerb(kb, rule.getReason().getVerb()); insertFact(kb, rule.getReason()); // The rule is true, so the fact must be true to. if (rule.getReason().getIsTrue() > 0) { rule.getFact().setIsTrue(1.0); } insertEntity(kb, rule.getFact().getLeftEntity()); insertEntity(kb, rule.getFact().getRightEntity()); insertVerb(kb, rule.getFact().getVerb()); insertFact(kb, rule.getFact()); insertRule(kb, rule); } catch (obelisk::ParserException& exception) { throw; } } void obelisk::Parser::handleFact(std::unique_ptr& kb) { std::vector facts; try { parseFact(facts); } catch (obelisk::ParserException& exception) { throw; } int verbId = 0; for (auto& fact : facts) { try { insertEntity(kb, fact.getLeftEntity()); insertEntity(kb, fact.getRightEntity()); } catch (obelisk::ParserException& exception) { throw; } if (verbId == 0) { try { insertVerb(kb, fact.getVerb()); } catch (obelisk::ParserException& exception) { throw; } verbId = fact.getVerb().getId(); } else { fact.getVerb().setId(verbId); } try { insertFact(kb, fact, true); } catch (obelisk::ParserException& exception) { throw; } kb->checkRule(fact); } } 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::insertAction(std::unique_ptr& kb, obelisk::Action& action) { std::vector actions {action}; kb->addActions(actions); action = std::move(actions.front()); // the id was not inserted, so check if it exists in the database if (action.getId() == 0) { kb->getAction(action); if (action.getId() == 0) { throw obelisk::ParserException( "action could not be inserted into the database"); } } } void obelisk::Parser::insertFact(std::unique_ptr& kb, obelisk::Fact& fact, bool updateIsTrue) { 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"); } else { if (updateIsTrue) { fact.setIsTrue(1.0); kb->updateIsTrue(fact); } } } } void obelisk::Parser::insertSuggestAction( std::unique_ptr& kb, obelisk::SuggestAction& suggestAction) { std::vector suggestActions {suggestAction}; kb->addSuggestActions(suggestActions); suggestAction = std::move(suggestActions.front()); // the id was not inserted, so check if it exists in the database if (suggestAction.getId() == 0) { kb->getSuggestAction(suggestAction); if (suggestAction.getId() == 0) { throw obelisk::ParserException( "suggest_action could not be inserted into the database"); } } } void obelisk::Parser::insertRule(std::unique_ptr& kb, obelisk::Rule& rule) { std::vector rules {rule}; kb->addRules(rules); rule = std::move(rules.front()); // the id was not inserted, so check if it exists in the database if (rule.getId() == 0) { kb->getRule(rule); if (rule.getId() == 0) { throw obelisk::ParserException( "rule could not be inserted into the database"); } } }