feature/fact_knowledge_base #7
@ -1,18 +1,16 @@
|
||||
#include "knowledge_base.h"
|
||||
#include "models/action.h"
|
||||
#include "models/entity.h"
|
||||
#include "models/error.h"
|
||||
#include "models/fact.h"
|
||||
#include "models/rule.h"
|
||||
#include "models/suggest_action.h"
|
||||
#include "models/verb.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
obelisk::KnowledgeBase::KnowledgeBase(const char* filename)
|
||||
{
|
||||
KnowledgeBase(filename, DEFAULT_FLAGS);
|
||||
}
|
||||
#include <string>
|
||||
|
||||
obelisk::KnowledgeBase::KnowledgeBase(const char* filename, int flags)
|
||||
{
|
||||
@ -28,6 +26,8 @@ obelisk::KnowledgeBase::KnowledgeBase(const char* filename, int flags)
|
||||
logSqliteError(result);
|
||||
}
|
||||
|
||||
enableForeignKeys();
|
||||
|
||||
if (!dbExists)
|
||||
{
|
||||
createTable(obelisk::Action::createTable);
|
||||
@ -47,16 +47,25 @@ obelisk::KnowledgeBase::~KnowledgeBase()
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::KnowledgeBase::createTable(std::function<const char*()> function)
|
||||
/**
|
||||
* @brief Enable foreign key functionality in the open database.
|
||||
*
|
||||
* This must always be done when the connection is opened or it will not
|
||||
* enforce the foreign key constraints.
|
||||
*/
|
||||
void obelisk::KnowledgeBase::enableForeignKeys()
|
||||
{
|
||||
char* tmp;
|
||||
auto result = sqlite3_exec(dbConnection_, function(), NULL, NULL, &tmp);
|
||||
char* errmsg;
|
||||
int result = sqlite3_exec(dbConnection_,
|
||||
"PRAGMA foreign_keys = ON;",
|
||||
NULL,
|
||||
NULL,
|
||||
&errmsg);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
logSqliteError(result);
|
||||
if (tmp)
|
||||
if (errmsg)
|
||||
{
|
||||
std::string errmsg(tmp);
|
||||
throw obelisk::KnowledgeBaseException(errmsg);
|
||||
}
|
||||
else
|
||||
@ -66,7 +75,103 @@ void obelisk::KnowledgeBase::createTable(std::function<const char*()> function)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: log files?
|
||||
void obelisk::KnowledgeBase::createTable(std::function<const char*()> function)
|
||||
{
|
||||
char* errmsg;
|
||||
int result = sqlite3_exec(dbConnection_, function(), NULL, NULL, &errmsg);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
logSqliteError(result);
|
||||
if (errmsg)
|
||||
{
|
||||
throw obelisk::KnowledgeBaseException(errmsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw obelisk::KnowledgeBaseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::KnowledgeBase::addEntities(std::vector<obelisk::Entity>& entities)
|
||||
{
|
||||
for (auto& entity : entities)
|
||||
{
|
||||
try
|
||||
{
|
||||
entity.insertEntity(dbConnection_);
|
||||
}
|
||||
catch (obelisk::DatabaseException::ConstraintException& exception)
|
||||
{
|
||||
// ignore unique constraint error
|
||||
if (std::strcmp(exception.what(),
|
||||
"UNIQUE constraint failed: entity.name")
|
||||
!= 0)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::KnowledgeBase::addVerbs(std::vector<obelisk::Verb>& verbs)
|
||||
{
|
||||
for (auto& verb : verbs)
|
||||
{
|
||||
try
|
||||
{
|
||||
verb.insertVerb(dbConnection_);
|
||||
}
|
||||
catch (obelisk::DatabaseException::ConstraintException& exception)
|
||||
{
|
||||
// ignore unique constraint error
|
||||
if (std::strcmp(exception.what(),
|
||||
"UNIQUE constraint failed: verb.name")
|
||||
!= 0)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::KnowledgeBase::addFacts(std::vector<obelisk::Fact>& facts)
|
||||
{
|
||||
for (auto& fact : facts)
|
||||
{
|
||||
try
|
||||
{
|
||||
fact.insertFact(dbConnection_);
|
||||
}
|
||||
catch (obelisk::DatabaseException::ConstraintException& exception)
|
||||
{
|
||||
// ignore unique constraint error
|
||||
if (std::strcmp(exception.what(),
|
||||
"UNIQUE constraint failed: fact.left_entity, fact.right_entity, fact.verb")
|
||||
!= 0)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::KnowledgeBase::getEntity(obelisk::Entity& entity)
|
||||
{
|
||||
entity.selectEntity(dbConnection_);
|
||||
}
|
||||
|
||||
void obelisk::KnowledgeBase::getVerb(obelisk::Verb& verb)
|
||||
{
|
||||
verb.selectVerb(dbConnection_);
|
||||
}
|
||||
|
||||
void obelisk::KnowledgeBase::getFact(obelisk::Fact& fact)
|
||||
{
|
||||
fact.selectFact(dbConnection_);
|
||||
}
|
||||
|
||||
// TODO: log files? or just throw an error?
|
||||
void obelisk::KnowledgeBase::logSqliteError(int result)
|
||||
{
|
||||
std::cout << sqlite3_errstr(result) << std::endl;
|
||||
|
@ -1,10 +1,15 @@
|
||||
#ifndef OBELISK_KNOWLEDGE_BASE_H
|
||||
#define OBELISK_KNOWLEDGE_BASE_H
|
||||
|
||||
#include "models/entity.h"
|
||||
#include "models/fact.h"
|
||||
#include "models/verb.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace obelisk
|
||||
@ -19,19 +24,27 @@ namespace obelisk
|
||||
int flags_;
|
||||
void logSqliteError(int result);
|
||||
|
||||
void enableForeignKeys();
|
||||
void createTable(std::function<const char*()> function);
|
||||
|
||||
public:
|
||||
KnowledgeBase(const char* filename);
|
||||
KnowledgeBase(const char* filename, int flags);
|
||||
|
||||
KnowledgeBase(const char* filename) :
|
||||
KnowledgeBase(filename,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
|
||||
{
|
||||
}
|
||||
|
||||
~KnowledgeBase();
|
||||
|
||||
template<typename T, typename U>
|
||||
int addFacts(std::string verb, T leftEntities, U rightEntities);
|
||||
// TODO: add parameter for fact
|
||||
template<typename T, typename U>
|
||||
int addRules(std::string verb, T leftEntities, U rightEntities);
|
||||
template<typename T, typename U> int addActions();
|
||||
void addEntities(std::vector<obelisk::Entity>& entities);
|
||||
void addVerbs(std::vector<obelisk::Verb>& verbs);
|
||||
void addFacts(std::vector<obelisk::Fact>& facts);
|
||||
|
||||
void getEntity(obelisk::Entity& entity);
|
||||
void getVerb(obelisk::Verb& verb);
|
||||
void getFact(obelisk::Fact& fact);
|
||||
|
||||
void getDouble(double& result, float var1, float var2);
|
||||
void getFloat(float& result1, float& result2, double var);
|
||||
|
@ -11,7 +11,7 @@ const char* obelisk::Action::createTable()
|
||||
)";
|
||||
}
|
||||
|
||||
int obelisk::Action::getId()
|
||||
int& obelisk::Action::getId()
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
@ -21,7 +21,7 @@ void obelisk::Action::setId(int id)
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
std::string obelisk::Action::getName()
|
||||
std::string& obelisk::Action::getName()
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
@ -38,10 +38,10 @@ namespace obelisk
|
||||
|
||||
static const char* createTable();
|
||||
|
||||
int getId();
|
||||
int& getId();
|
||||
void setId(int id);
|
||||
|
||||
std::string getName();
|
||||
std::string& getName();
|
||||
void setName(std::string name);
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "models/entity.h"
|
||||
#include "models/error.h"
|
||||
|
||||
const char* obelisk::Entity::createTable()
|
||||
{
|
||||
@ -11,7 +12,142 @@ const char* obelisk::Entity::createTable()
|
||||
)";
|
||||
}
|
||||
|
||||
int obelisk::Entity::getId()
|
||||
void obelisk::Entity::selectEntity(sqlite3* dbConnection)
|
||||
{
|
||||
if (dbConnection == nullptr)
|
||||
{
|
||||
throw obelisk::DatabaseException("database isn't open");
|
||||
}
|
||||
|
||||
sqlite3_stmt* ppStmt = nullptr;
|
||||
|
||||
auto result = sqlite3_prepare_v2(dbConnection,
|
||||
"SELECT id, name FROM entity WHERE name=?",
|
||||
-1,
|
||||
&ppStmt,
|
||||
nullptr);
|
||||
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
|
||||
result = sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_STATIC);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_step(ppStmt);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_DONE :
|
||||
// no rows in the database
|
||||
break;
|
||||
case SQLITE_ROW :
|
||||
setId(sqlite3_column_int(ppStmt, 0));
|
||||
setName((char*) sqlite3_column_text(ppStmt, 1));
|
||||
break;
|
||||
case SQLITE_BUSY :
|
||||
throw obelisk::DatabaseException::BusyException();
|
||||
break;
|
||||
case SQLITE_MISUSE :
|
||||
throw obelisk::DatabaseException::MisuseException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_finalize(ppStmt);
|
||||
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::Entity::insertEntity(sqlite3* dbConnection)
|
||||
{
|
||||
if (dbConnection == nullptr)
|
||||
{
|
||||
throw obelisk::DatabaseException("database isn't open");
|
||||
}
|
||||
|
||||
sqlite3_stmt* ppStmt = nullptr;
|
||||
|
||||
auto result = sqlite3_prepare_v2(dbConnection,
|
||||
"INSERT INTO entity (name) VALUES (?)",
|
||||
-1,
|
||||
&ppStmt,
|
||||
nullptr);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
|
||||
result
|
||||
= sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_TRANSIENT);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_step(ppStmt);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_DONE :
|
||||
setId((int) sqlite3_last_insert_rowid(dbConnection));
|
||||
sqlite3_set_last_insert_rowid(dbConnection, 0);
|
||||
break;
|
||||
case SQLITE_CONSTRAINT :
|
||||
throw obelisk::DatabaseException::ConstraintException(
|
||||
sqlite3_errmsg(dbConnection));
|
||||
case SQLITE_BUSY :
|
||||
throw obelisk::DatabaseException::BusyException();
|
||||
break;
|
||||
case SQLITE_MISUSE :
|
||||
throw obelisk::DatabaseException::MisuseException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_finalize(ppStmt);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
}
|
||||
|
||||
int& obelisk::Entity::getId()
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
@ -21,7 +157,7 @@ void obelisk::Entity::setId(int id)
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
std::string obelisk::Entity::getName()
|
||||
std::string& obelisk::Entity::getName()
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef OBELISK_MODELS_ENTITY_H
|
||||
#define OBELISK_MODELS_ENTITY_H
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace obelisk
|
||||
@ -38,11 +40,14 @@ namespace obelisk
|
||||
|
||||
static const char* createTable();
|
||||
|
||||
int getId();
|
||||
int& getId();
|
||||
void setId(int id);
|
||||
|
||||
std::string getName();
|
||||
std::string& getName();
|
||||
void setName(std::string name);
|
||||
|
||||
void selectEntity(sqlite3* dbConnection);
|
||||
void insertEntity(sqlite3* dbConnection);
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
||||
|
146
src/models/error.h
Normal file
146
src/models/error.h
Normal file
@ -0,0 +1,146 @@
|
||||
#ifndef OBELISK_MODELS_ERROR_H
|
||||
#define OBELISK_MODELS_ERROR_H
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace obelisk
|
||||
{
|
||||
class DatabaseException : public std::exception
|
||||
{
|
||||
private:
|
||||
const std::string errorMessage_;
|
||||
|
||||
public:
|
||||
DatabaseException() :
|
||||
errorMessage_("an unknown error ocurred")
|
||||
{
|
||||
}
|
||||
|
||||
DatabaseException(const int errorCode) :
|
||||
errorMessage_(
|
||||
"database error " + std::to_string(errorCode) + " ocurred")
|
||||
{
|
||||
}
|
||||
|
||||
DatabaseException(const std::string& errorMessage) :
|
||||
errorMessage_(errorMessage)
|
||||
{
|
||||
}
|
||||
|
||||
const char* what() const noexcept
|
||||
{
|
||||
return errorMessage_.c_str();
|
||||
}
|
||||
|
||||
class SizeException : public std::exception
|
||||
{
|
||||
private:
|
||||
const std::string errorMessage_;
|
||||
|
||||
public:
|
||||
SizeException() :
|
||||
errorMessage_("size of string or blob exceeds limits")
|
||||
{
|
||||
}
|
||||
|
||||
const char* what() const noexcept
|
||||
{
|
||||
return errorMessage_.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class RangeException : public std::exception
|
||||
{
|
||||
private:
|
||||
const std::string errorMessage_;
|
||||
|
||||
public:
|
||||
RangeException() :
|
||||
errorMessage_("parameter index is out of range")
|
||||
{
|
||||
}
|
||||
|
||||
const char* what() const noexcept
|
||||
{
|
||||
return errorMessage_.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class MemoryException : public std::exception
|
||||
{
|
||||
private:
|
||||
const std::string errorMessage_;
|
||||
|
||||
public:
|
||||
MemoryException() :
|
||||
errorMessage_("not enough memory for operation")
|
||||
{
|
||||
}
|
||||
|
||||
const char* what() const noexcept
|
||||
{
|
||||
return errorMessage_.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class BusyException : public std::exception
|
||||
{
|
||||
private:
|
||||
const std::string errorMessage_;
|
||||
|
||||
public:
|
||||
BusyException() :
|
||||
errorMessage_(
|
||||
"database was busy and operation not performed")
|
||||
{
|
||||
}
|
||||
|
||||
const char* what() const noexcept
|
||||
{
|
||||
return errorMessage_.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class MisuseException : public std::exception
|
||||
{
|
||||
private:
|
||||
const std::string errorMessage_;
|
||||
|
||||
public:
|
||||
MisuseException() :
|
||||
errorMessage_("misuse of the database routine")
|
||||
{
|
||||
}
|
||||
|
||||
const char* what() const noexcept
|
||||
{
|
||||
return errorMessage_.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class ConstraintException : public std::exception
|
||||
{
|
||||
private:
|
||||
const std::string errorMessage_;
|
||||
|
||||
public:
|
||||
ConstraintException() :
|
||||
errorMessage_("a constraint exception occurred")
|
||||
{
|
||||
}
|
||||
|
||||
ConstraintException(const std::string& errorMessage) :
|
||||
errorMessage_(errorMessage)
|
||||
{
|
||||
}
|
||||
|
||||
const char* what() const noexcept
|
||||
{
|
||||
return errorMessage_.c_str();
|
||||
}
|
||||
};
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
||||
#endif
|
@ -1,3 +1,4 @@
|
||||
#include "models/error.h"
|
||||
#include "models/fact.h"
|
||||
|
||||
const char* obelisk::Fact::createTable()
|
||||
@ -9,6 +10,7 @@ const char* obelisk::Fact::createTable()
|
||||
"right_entity" INTEGER NOT NULL,
|
||||
"verb" INTEGER NOT NULL,
|
||||
PRIMARY KEY("id" AUTOINCREMENT),
|
||||
UNIQUE("left_entity", "right_entity", "verb")
|
||||
FOREIGN KEY("verb") REFERENCES "verb"("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY("right_entity") REFERENCES "entity"("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY("left_entity") REFERENCES "entity"("id") ON DELETE RESTRICT
|
||||
@ -16,7 +18,217 @@ const char* obelisk::Fact::createTable()
|
||||
)";
|
||||
}
|
||||
|
||||
int obelisk::Fact::getId()
|
||||
void obelisk::Fact::selectFact(sqlite3* dbConnection)
|
||||
{
|
||||
if (dbConnection == nullptr)
|
||||
{
|
||||
throw obelisk::DatabaseException("database isn't open");
|
||||
}
|
||||
|
||||
sqlite3_stmt* ppStmt = nullptr;
|
||||
|
||||
auto result = sqlite3_prepare_v2(dbConnection,
|
||||
"SELECT id, left_entity, right_entity, verb FROM fact WHERE (left_entity=? AND right_entity=? AND verb=?)",
|
||||
-1,
|
||||
&ppStmt,
|
||||
nullptr);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
|
||||
result = sqlite3_bind_int(ppStmt, 1, getLeftEntity().getId());
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_bind_int(ppStmt, 2, getRightEntity().getId());
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_bind_int(ppStmt, 3, getVerb().getId());
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_step(ppStmt);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_DONE :
|
||||
// no rows in the database
|
||||
break;
|
||||
case SQLITE_ROW :
|
||||
setId(sqlite3_column_int(ppStmt, 0));
|
||||
getLeftEntity().setId(sqlite3_column_int(ppStmt, 1));
|
||||
getRightEntity().setId(sqlite3_column_int(ppStmt, 2));
|
||||
getVerb().setId(sqlite3_column_int(ppStmt, 3));
|
||||
break;
|
||||
case SQLITE_BUSY :
|
||||
throw obelisk::DatabaseException::BusyException();
|
||||
break;
|
||||
case SQLITE_MISUSE :
|
||||
throw obelisk::DatabaseException::MisuseException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_finalize(ppStmt);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::Fact::insertFact(sqlite3* dbConnection)
|
||||
{
|
||||
if (dbConnection == nullptr)
|
||||
{
|
||||
throw obelisk::DatabaseException("database isn't open");
|
||||
}
|
||||
|
||||
sqlite3_stmt* ppStmt = nullptr;
|
||||
|
||||
auto result = sqlite3_prepare_v2(dbConnection,
|
||||
"INSERT INTO fact (left_entity, right_entity, verb) VALUES (?, ?, ?)",
|
||||
-1,
|
||||
&ppStmt,
|
||||
nullptr);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
|
||||
result = sqlite3_bind_int(ppStmt, 1, getLeftEntity().getId());
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_bind_int(ppStmt, 2, getRightEntity().getId());
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_bind_int(ppStmt, 3, getVerb().getId());
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_step(ppStmt);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_DONE :
|
||||
setId((int) sqlite3_last_insert_rowid(dbConnection));
|
||||
sqlite3_set_last_insert_rowid(dbConnection, 0);
|
||||
break;
|
||||
case SQLITE_CONSTRAINT :
|
||||
throw obelisk::DatabaseException::ConstraintException(
|
||||
sqlite3_errmsg(dbConnection));
|
||||
case SQLITE_BUSY :
|
||||
throw obelisk::DatabaseException::BusyException();
|
||||
break;
|
||||
case SQLITE_MISUSE :
|
||||
throw obelisk::DatabaseException::MisuseException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_finalize(ppStmt);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
}
|
||||
|
||||
int& obelisk::Fact::getId()
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
@ -26,7 +238,7 @@ void obelisk::Fact::setId(int id)
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
obelisk::Entity obelisk::Fact::getLeftEntity()
|
||||
obelisk::Entity& obelisk::Fact::getLeftEntity()
|
||||
{
|
||||
return leftEntity_;
|
||||
}
|
||||
@ -36,7 +248,7 @@ void obelisk::Fact::setLeftEntity(obelisk::Entity leftEntity)
|
||||
leftEntity_ = leftEntity;
|
||||
}
|
||||
|
||||
obelisk::Entity obelisk::Fact::getRightEntity()
|
||||
obelisk::Entity& obelisk::Fact::getRightEntity()
|
||||
{
|
||||
return rightEntity_;
|
||||
}
|
||||
@ -46,7 +258,7 @@ void obelisk::Fact::setRightEntity(obelisk::Entity rightEntity)
|
||||
rightEntity_ = rightEntity;
|
||||
}
|
||||
|
||||
obelisk::Verb obelisk::Fact::getVerb()
|
||||
obelisk::Verb& obelisk::Fact::getVerb()
|
||||
{
|
||||
return verb_;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OBELISK_MODELS_FACT_H
|
||||
|
||||
#include "models/entity.h"
|
||||
#include "models/fact.h"
|
||||
#include "models/verb.h"
|
||||
|
||||
#include <string>
|
||||
@ -56,17 +57,20 @@ namespace obelisk
|
||||
|
||||
static const char* createTable();
|
||||
|
||||
int getId();
|
||||
int& getId();
|
||||
void setId(int id);
|
||||
|
||||
obelisk::Entity getLeftEntity();
|
||||
Entity& getLeftEntity();
|
||||
void setLeftEntity(obelisk::Entity leftEntity);
|
||||
|
||||
obelisk::Entity getRightEntity();
|
||||
Entity& getRightEntity();
|
||||
void setRightEntity(obelisk::Entity leftEntity);
|
||||
|
||||
obelisk::Verb getVerb();
|
||||
Verb& getVerb();
|
||||
void setVerb(obelisk::Verb verb);
|
||||
|
||||
void selectFact(sqlite3* dbConnection);
|
||||
void insertFact(sqlite3* dbConnection);
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
||||
|
@ -8,13 +8,14 @@ const char* obelisk::Rule::createTable()
|
||||
"fact" INTEGER NOT NULL,
|
||||
"reason" INTEGER NOT NULL CHECK("reason" != "fact"),
|
||||
PRIMARY KEY("id" AUTOINCREMENT),
|
||||
UNIQUE("fact", "reason"),
|
||||
FOREIGN KEY("fact") REFERENCES "fact"("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY("reason") REFERENCES "fact"("id") ON DELETE RESTRICT
|
||||
);
|
||||
)";
|
||||
}
|
||||
|
||||
int obelisk::Rule::getId()
|
||||
int& obelisk::Rule::getId()
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
@ -24,7 +25,7 @@ void obelisk::Rule::setId(int id)
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
obelisk::Fact obelisk::Rule::getFact()
|
||||
obelisk::Fact& obelisk::Rule::getFact()
|
||||
{
|
||||
return fact_;
|
||||
}
|
||||
@ -34,7 +35,7 @@ void obelisk::Rule::setFact(obelisk::Fact fact)
|
||||
fact_ = fact;
|
||||
}
|
||||
|
||||
obelisk::Fact obelisk::Rule::getReason()
|
||||
obelisk::Fact& obelisk::Rule::getReason()
|
||||
{
|
||||
return reason_;
|
||||
}
|
||||
|
@ -45,13 +45,13 @@ namespace obelisk
|
||||
|
||||
static const char* createTable();
|
||||
|
||||
int getId();
|
||||
int& getId();
|
||||
void setId(int id);
|
||||
|
||||
obelisk::Fact getFact();
|
||||
obelisk::Fact& getFact();
|
||||
void setFact(obelisk::Fact fact);
|
||||
|
||||
obelisk::Fact getReason();
|
||||
obelisk::Fact& getReason();
|
||||
void setReason(obelisk::Fact reason);
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
@ -9,6 +9,7 @@ const char* obelisk::SuggestAction::createTable()
|
||||
"true_action" INTEGER NOT NULL,
|
||||
"false_action" INTEGER NOT NULL,
|
||||
PRIMARY KEY("id" AUTOINCREMENT),
|
||||
UNIQUE("fact", "true_action", "false_action"),
|
||||
FOREIGN KEY("fact") REFERENCES "fact"("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY("true_action") REFERENCES "action"("id") ON DELETE RESTRICT,
|
||||
FOREIGN KEY("false_action") REFERENCES "action"("id") ON DELETE RESTRICT
|
||||
@ -16,7 +17,7 @@ const char* obelisk::SuggestAction::createTable()
|
||||
)";
|
||||
}
|
||||
|
||||
int obelisk::SuggestAction::getId()
|
||||
int& obelisk::SuggestAction::getId()
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
@ -26,7 +27,7 @@ void obelisk::SuggestAction::setId(int id)
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
obelisk::Fact obelisk::SuggestAction::getFact()
|
||||
obelisk::Fact& obelisk::SuggestAction::getFact()
|
||||
{
|
||||
return fact_;
|
||||
}
|
||||
@ -36,7 +37,7 @@ void obelisk::SuggestAction::setFact(obelisk::Fact fact)
|
||||
fact_ = fact;
|
||||
}
|
||||
|
||||
obelisk::Action obelisk::SuggestAction::getTrueAction()
|
||||
obelisk::Action& obelisk::SuggestAction::getTrueAction()
|
||||
{
|
||||
return trueAction_;
|
||||
}
|
||||
@ -46,7 +47,7 @@ void obelisk::SuggestAction::setTrueAction(obelisk::Action trueAction)
|
||||
trueAction_ = trueAction;
|
||||
}
|
||||
|
||||
obelisk::Action obelisk::SuggestAction::getFalseAction()
|
||||
obelisk::Action& obelisk::SuggestAction::getFalseAction()
|
||||
{
|
||||
return falseAction_;
|
||||
}
|
||||
|
@ -56,16 +56,16 @@ namespace obelisk
|
||||
|
||||
static const char* createTable();
|
||||
|
||||
int getId();
|
||||
int& getId();
|
||||
void setId(int id);
|
||||
|
||||
obelisk::Fact getFact();
|
||||
obelisk::Fact& getFact();
|
||||
void setFact(obelisk::Fact fact);
|
||||
|
||||
obelisk::Action getTrueAction();
|
||||
obelisk::Action& getTrueAction();
|
||||
void setTrueAction(obelisk::Action trueAction);
|
||||
|
||||
obelisk::Action getFalseAction();
|
||||
obelisk::Action& getFalseAction();
|
||||
void setFalseAction(obelisk::Action falseAction);
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include "models/error.h"
|
||||
#include "models/verb.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
const char* obelisk::Verb::createTable()
|
||||
{
|
||||
return R"(
|
||||
@ -11,7 +14,140 @@ const char* obelisk::Verb::createTable()
|
||||
)";
|
||||
}
|
||||
|
||||
int obelisk::Verb::getId()
|
||||
void obelisk::Verb::selectVerb(sqlite3* dbConnection)
|
||||
{
|
||||
if (dbConnection == nullptr)
|
||||
{
|
||||
throw obelisk::DatabaseException("database isn't open");
|
||||
}
|
||||
|
||||
sqlite3_stmt* ppStmt = nullptr;
|
||||
|
||||
auto result = sqlite3_prepare_v2(dbConnection,
|
||||
"SELECT id, name FROM verb WHERE name=?",
|
||||
-1,
|
||||
&ppStmt,
|
||||
nullptr);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
|
||||
result = sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_STATIC);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_step(ppStmt);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_DONE :
|
||||
// no rows in the database
|
||||
break;
|
||||
case SQLITE_ROW :
|
||||
setId(sqlite3_column_int(ppStmt, 0));
|
||||
setName((char*) sqlite3_column_text(ppStmt, 1));
|
||||
break;
|
||||
case SQLITE_BUSY :
|
||||
throw obelisk::DatabaseException::BusyException();
|
||||
break;
|
||||
case SQLITE_MISUSE :
|
||||
throw obelisk::DatabaseException::MisuseException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_finalize(ppStmt);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::Verb::insertVerb(sqlite3* dbConnection)
|
||||
{
|
||||
if (dbConnection == nullptr)
|
||||
{
|
||||
throw obelisk::DatabaseException("database isn't open");
|
||||
}
|
||||
|
||||
sqlite3_stmt* ppStmt = nullptr;
|
||||
|
||||
auto result = sqlite3_prepare_v2(dbConnection,
|
||||
"INSERT INTO verb (name) VALUES (?)",
|
||||
-1,
|
||||
&ppStmt,
|
||||
nullptr);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
|
||||
result
|
||||
= sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_TRANSIENT);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_OK :
|
||||
break;
|
||||
case SQLITE_TOOBIG :
|
||||
throw obelisk::DatabaseException::SizeException();
|
||||
break;
|
||||
case SQLITE_RANGE :
|
||||
throw obelisk::DatabaseException::RangeException();
|
||||
break;
|
||||
case SQLITE_NOMEM :
|
||||
throw obelisk::DatabaseException::MemoryException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_step(ppStmt);
|
||||
switch (result)
|
||||
{
|
||||
case SQLITE_DONE :
|
||||
setId((int) sqlite3_last_insert_rowid(dbConnection));
|
||||
sqlite3_set_last_insert_rowid(dbConnection, 0);
|
||||
break;
|
||||
case SQLITE_CONSTRAINT :
|
||||
throw obelisk::DatabaseException::ConstraintException(
|
||||
sqlite3_errmsg(dbConnection));
|
||||
case SQLITE_BUSY :
|
||||
throw obelisk::DatabaseException::BusyException();
|
||||
break;
|
||||
case SQLITE_MISUSE :
|
||||
throw obelisk::DatabaseException::MisuseException();
|
||||
break;
|
||||
default :
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
break;
|
||||
}
|
||||
|
||||
result = sqlite3_finalize(ppStmt);
|
||||
if (result != SQLITE_OK)
|
||||
{
|
||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||
}
|
||||
}
|
||||
|
||||
int& obelisk::Verb::getId()
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
@ -21,7 +157,7 @@ void obelisk::Verb::setId(int id)
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
std::string obelisk::Verb::getName()
|
||||
std::string& obelisk::Verb::getName()
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef OBELISK_MODELS_VERB_H
|
||||
#define OBELISK_MODELS_VERB_H
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace obelisk
|
||||
@ -38,11 +40,14 @@ namespace obelisk
|
||||
|
||||
static const char* createTable();
|
||||
|
||||
int getId();
|
||||
int& getId();
|
||||
void setId(int id);
|
||||
|
||||
std::string getName();
|
||||
std::string& getName();
|
||||
void setName(std::string name);
|
||||
|
||||
void selectVerb(sqlite3* dbConnection);
|
||||
void insertVerb(sqlite3* dbConnection);
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
||||
|
@ -8,9 +8,21 @@
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
static void mainLoop()
|
||||
static int mainLoop()
|
||||
{
|
||||
auto parser = std::unique_ptr<obelisk::Parser> {new obelisk::Parser()};
|
||||
std::unique_ptr<obelisk::KnowledgeBase> kb;
|
||||
|
||||
try
|
||||
{
|
||||
kb = std::unique_ptr<obelisk::KnowledgeBase> {
|
||||
new obelisk::KnowledgeBase("cromer.kb")};
|
||||
}
|
||||
catch (obelisk::KnowledgeBaseException& exception)
|
||||
{
|
||||
std::cout << exception.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Prime the first token.
|
||||
fprintf(stderr, "ready> ");
|
||||
@ -22,7 +34,7 @@ static void mainLoop()
|
||||
switch (parser->getCurrentToken())
|
||||
{
|
||||
case obelisk::Lexer::kTokenEof :
|
||||
return;
|
||||
return EXIT_SUCCESS;
|
||||
case ';' : // ignore top-level semicolons.
|
||||
std::cout << "Identifier: "
|
||||
<< parser->getLexer()->getIdentifier() << std::endl;
|
||||
@ -31,19 +43,21 @@ static void mainLoop()
|
||||
parser->getNextToken();
|
||||
break;
|
||||
case obelisk::Lexer::kTokenFact :
|
||||
// parser->handleFactFunction();
|
||||
parser->handleFact(kb);
|
||||
break;
|
||||
case obelisk::Lexer::kTokenRule :
|
||||
// parser->handleRuleFunction();
|
||||
// parser->handleRule();
|
||||
break;
|
||||
case obelisk::Lexer::kTokenAction :
|
||||
// parser->handleActionFunction();
|
||||
// parser->handleAction();
|
||||
break;
|
||||
default :
|
||||
parser->getNextToken();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
@ -79,28 +93,5 @@ int main(int argc, char** argv)
|
||||
return EXIT_FAILURE;
|
||||
}*/
|
||||
|
||||
try
|
||||
{
|
||||
auto kb = std::unique_ptr<obelisk::KnowledgeBase> {
|
||||
new obelisk::KnowledgeBase("cromer.kb")};
|
||||
|
||||
/*std::vector<std::string> leftObjects;
|
||||
std::vector<std::string> rightObjects;
|
||||
leftObjects.push_back("chris");
|
||||
leftObjects.push_back("martin");
|
||||
|
||||
rightObjects.push_back("happy");
|
||||
rightObjects.push_back("smart");
|
||||
|
||||
kb->addFacts("is", leftObjects, rightObjects);*/
|
||||
}
|
||||
catch (obelisk::KnowledgeBaseException& exception)
|
||||
{
|
||||
std::cout << exception.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
mainLoop();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return mainLoop();
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
static void mainLoop();
|
||||
static int mainLoop();
|
||||
|
159
src/parser.cpp
159
src/parser.cpp
@ -1,10 +1,14 @@
|
||||
#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 <memory>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
obelisk::Parser::Parser()
|
||||
@ -211,64 +215,27 @@ std::unique_ptr<obelisk::PrototypeAST> obelisk::Parser::parseExtern()
|
||||
return parsePrototype();
|
||||
}
|
||||
|
||||
//action("martin" is "dangerous" then "avoid" or "ignore");
|
||||
std::unique_ptr<obelisk::ExpressionAST> obelisk::Parser::parseAction()
|
||||
{
|
||||
//action(is "dangerous" then "avoid" or "ignore");
|
||||
getNextToken();
|
||||
if (getCurrentToken() != '(')
|
||||
{
|
||||
// TODO: throw an error
|
||||
}
|
||||
}
|
||||
|
||||
//rule("chris" and "martin" is "happy" if "chris" plays "playstation");
|
||||
std::unique_ptr<obelisk::ExpressionAST> obelisk::Parser::parseRule()
|
||||
{
|
||||
//rule("player" can "die" if "enemy1" is "dangerous");
|
||||
getNextToken();
|
||||
if (getCurrentToken() != '(')
|
||||
{
|
||||
// TODO: throw an error
|
||||
}
|
||||
while (true) //left side of Rule
|
||||
{
|
||||
getNextToken();
|
||||
if (getCurrentToken() != '"')
|
||||
{
|
||||
//TODO: throw an error
|
||||
}
|
||||
|
||||
/*if (getCurrentToken() == ')') // TODO: break if not string and not "and"
|
||||
{
|
||||
// TODO: save the verb
|
||||
break;
|
||||
}*/
|
||||
}
|
||||
while (true) //right side of Ruke
|
||||
{
|
||||
getNextToken();
|
||||
if (getCurrentToken() != '"')
|
||||
{
|
||||
//TODO: throw an error
|
||||
}
|
||||
|
||||
if (getCurrentToken() == ')')
|
||||
{
|
||||
// TODO: save the verb
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fact("chris cromer" and "martin" and "Isabella" can "program" and "speak english");
|
||||
// fact("" and "martin")
|
||||
std::unique_ptr<obelisk::ExpressionAST> obelisk::Parser::parseFact()
|
||||
void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
|
||||
{
|
||||
std::stack<char> syntax;
|
||||
|
||||
getNextToken();
|
||||
if (getCurrentToken() != '(')
|
||||
{
|
||||
// TODO: throw an error
|
||||
throw obelisk::ParserException(
|
||||
"expected '(' but got '" + std::to_string(getCurrentToken()) + "'");
|
||||
}
|
||||
|
||||
syntax.push('(');
|
||||
@ -326,14 +293,29 @@ std::unique_ptr<obelisk::ExpressionAST> obelisk::Parser::parseFact()
|
||||
{
|
||||
if (getCurrentToken() == ')')
|
||||
{
|
||||
// TODO: throw an error if verb is empty
|
||||
// TODO: throw an error if rightEntities has 0 elements
|
||||
// closing parenthesis found, make sure we have everything needed
|
||||
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");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (getCurrentToken() == '"')
|
||||
{
|
||||
// TODO: throw and error because there is an unexpected double quote.
|
||||
throw obelisk::ParserException("unexpected '\"'");
|
||||
break;
|
||||
}
|
||||
|
||||
@ -352,22 +334,97 @@ std::unique_ptr<obelisk::ExpressionAST> obelisk::Parser::parseFact()
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
for (auto& leftEntity : leftEntities)
|
||||
{
|
||||
for (auto& rightEntity : rightEntities)
|
||||
{
|
||||
facts.push_back(obelisk::Fact(obelisk::Entity(leftEntity),
|
||||
obelisk::Entity(rightEntity),
|
||||
obelisk::Verb(verb)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::Parser::handleAction()
|
||||
void obelisk::Parser::handleAction(std::unique_ptr<obelisk::KnowledgeBase>& kb)
|
||||
{
|
||||
}
|
||||
|
||||
void obelisk::Parser::handleRule()
|
||||
void obelisk::Parser::handleRule(std::unique_ptr<obelisk::KnowledgeBase>& kb)
|
||||
{
|
||||
}
|
||||
|
||||
void obelisk::Parser::handleFact()
|
||||
void obelisk::Parser::handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb)
|
||||
{
|
||||
parseFact();
|
||||
std::vector<obelisk::Fact> facts;
|
||||
parseFact(facts);
|
||||
|
||||
int verbId = 0;
|
||||
for (auto& fact : facts)
|
||||
{
|
||||
// TODO: doesn't work after first insert
|
||||
std::vector<obelisk::Entity> 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)
|
||||
{
|
||||
obelisk::Entity entity = fact.getLeftEntity();
|
||||
kb->getEntity(entity);
|
||||
if (entity.getId() == 0)
|
||||
{
|
||||
// TODO: throw an error here, it was not inserted, and doesn't exist in the database
|
||||
}
|
||||
else
|
||||
{
|
||||
fact.setLeftEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void obelisk::Parser::insertFact()
|
||||
entities = {fact.getRightEntity()};
|
||||
kb->addEntities(entities);
|
||||
fact.setRightEntity(entities.front());
|
||||
|
||||
if (fact.getRightEntity().getId() == 0)
|
||||
{
|
||||
obelisk::Entity entity = fact.getRightEntity();
|
||||
kb->getEntity(entity);
|
||||
if (entity.getId() == 0)
|
||||
{
|
||||
// TODO: throw an error here, it was not inserted, and doesn't exist in the database
|
||||
}
|
||||
else
|
||||
{
|
||||
fact.setRightEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
if (verbId == 0)
|
||||
{
|
||||
std::vector<obelisk::Verb> verbs = {fact.getVerb()};
|
||||
kb->addVerbs(verbs);
|
||||
if (verbs.front().getId() != 0)
|
||||
{
|
||||
// The verb was inserted
|
||||
fact.setVerb(verbs.front());
|
||||
verbId = fact.getVerb().getId();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The verb is already already in the knowledge base
|
||||
// TODO: SELECT the verb and save it into verbId
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fact.getVerb().setId(verbId);
|
||||
}
|
||||
|
||||
// INSERT INTO fact
|
||||
std::vector<obelisk::Fact> facts {fact};
|
||||
kb->addFacts(facts);
|
||||
fact = facts.front();
|
||||
}
|
||||
}
|
||||
|
||||
// fact("chris cromer" and "martin" and "Isabella" can "program" and "speak english");
|
||||
|
32
src/parser.h
32
src/parser.h
@ -4,7 +4,9 @@
|
||||
#include "ast/expression_ast.h"
|
||||
#include "ast/function_ast.h"
|
||||
#include "ast/prototype_ast.h"
|
||||
#include "knowledge_base.h"
|
||||
#include "lexer.h"
|
||||
#include "models/fact.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -34,7 +36,7 @@ namespace obelisk
|
||||
std::unique_ptr<obelisk::PrototypeAST> parseExtern();
|
||||
std::unique_ptr<obelisk::ExpressionAST> parseAction();
|
||||
std::unique_ptr<obelisk::ExpressionAST> parseRule();
|
||||
std::unique_ptr<obelisk::ExpressionAST> parseFact();
|
||||
void parseFact(std::vector<obelisk::Fact>& facts);
|
||||
|
||||
public:
|
||||
Parser();
|
||||
@ -48,9 +50,31 @@ namespace obelisk
|
||||
void handleDefinition();
|
||||
void handleExtern();
|
||||
void handleTopLevelExpression();
|
||||
void handleAction();
|
||||
void handleRule();
|
||||
void handleFact();
|
||||
void handleAction(std::unique_ptr<obelisk::KnowledgeBase>& kb);
|
||||
void handleRule(std::unique_ptr<obelisk::KnowledgeBase>& kb);
|
||||
void handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb);
|
||||
};
|
||||
|
||||
class ParserException : public std::exception
|
||||
{
|
||||
private:
|
||||
const std::string errorMessage_;
|
||||
|
||||
public:
|
||||
ParserException() :
|
||||
errorMessage_("an unknown error ocurred")
|
||||
{
|
||||
}
|
||||
|
||||
ParserException(const std::string& errorMessage) :
|
||||
errorMessage_(errorMessage)
|
||||
{
|
||||
}
|
||||
|
||||
const char* what() const noexcept
|
||||
{
|
||||
return errorMessage_.c_str();
|
||||
}
|
||||
};
|
||||
} // namespace obelisk
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user