Merge pull request 'develop' (#15) from develop into master
Reviewed-on: #15
This commit is contained in:
commit
1940fe377a
@ -167,7 +167,7 @@ RawStringFormats:
|
|||||||
- PROTO
|
- PROTO
|
||||||
CanonicalDelimiter: pb
|
CanonicalDelimiter: pb
|
||||||
ReferenceAlignment: Left
|
ReferenceAlignment: Left
|
||||||
ReflowComments: false
|
ReflowComments: true
|
||||||
RemoveBracesLLVM: false
|
RemoveBracesLLVM: false
|
||||||
SeparateDefinitionBlocks: Always
|
SeparateDefinitionBlocks: Always
|
||||||
ShortNamespaceLines: 0
|
ShortNamespaceLines: 0
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
.vscode
|
.vscode
|
||||||
builddir
|
builddir
|
||||||
*.kb
|
*.kb
|
||||||
|
*.obk
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/obelisk.cpp.o -MF src/obelisk.p/obelisk.cpp.o.d -o src/obelisk.p/obelisk.cpp.o -c ../src/obelisk.cpp",
|
|
||||||
"file": "../src/obelisk.cpp",
|
|
||||||
"output": "src/obelisk.p/obelisk.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/lexer.cpp.o -MF src/obelisk.p/lexer.cpp.o.d -o src/obelisk.p/lexer.cpp.o -c ../src/lexer.cpp",
|
|
||||||
"file": "../src/lexer.cpp",
|
|
||||||
"output": "src/obelisk.p/lexer.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/parser.cpp.o -MF src/obelisk.p/parser.cpp.o.d -o src/obelisk.p/parser.cpp.o -c ../src/parser.cpp",
|
|
||||||
"file": "../src/parser.cpp",
|
|
||||||
"output": "src/obelisk.p/parser.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/knowledge_base.cpp.o -MF src/obelisk.p/knowledge_base.cpp.o.d -o src/obelisk.p/knowledge_base.cpp.o -c ../src/knowledge_base.cpp",
|
|
||||||
"file": "../src/knowledge_base.cpp",
|
|
||||||
"output": "src/obelisk.p/knowledge_base.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/ast_call_expression_ast.cpp.o -MF src/obelisk.p/ast_call_expression_ast.cpp.o.d -o src/obelisk.p/ast_call_expression_ast.cpp.o -c ../src/ast/call_expression_ast.cpp",
|
|
||||||
"file": "../src/ast/call_expression_ast.cpp",
|
|
||||||
"output": "src/obelisk.p/ast_call_expression_ast.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/ast_error.cpp.o -MF src/obelisk.p/ast_error.cpp.o.d -o src/obelisk.p/ast_error.cpp.o -c ../src/ast/error.cpp",
|
|
||||||
"file": "../src/ast/error.cpp",
|
|
||||||
"output": "src/obelisk.p/ast_error.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/ast_function_ast.cpp.o -MF src/obelisk.p/ast_function_ast.cpp.o.d -o src/obelisk.p/ast_function_ast.cpp.o -c ../src/ast/function_ast.cpp",
|
|
||||||
"file": "../src/ast/function_ast.cpp",
|
|
||||||
"output": "src/obelisk.p/ast_function_ast.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/ast_number_expression_ast.cpp.o -MF src/obelisk.p/ast_number_expression_ast.cpp.o.d -o src/obelisk.p/ast_number_expression_ast.cpp.o -c ../src/ast/number_expression_ast.cpp",
|
|
||||||
"file": "../src/ast/number_expression_ast.cpp",
|
|
||||||
"output": "src/obelisk.p/ast_number_expression_ast.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/ast_prototype_ast.cpp.o -MF src/obelisk.p/ast_prototype_ast.cpp.o.d -o src/obelisk.p/ast_prototype_ast.cpp.o -c ../src/ast/prototype_ast.cpp",
|
|
||||||
"file": "../src/ast/prototype_ast.cpp",
|
|
||||||
"output": "src/obelisk.p/ast_prototype_ast.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/ast_variable_expression_ast.cpp.o -MF src/obelisk.p/ast_variable_expression_ast.cpp.o.d -o src/obelisk.p/ast_variable_expression_ast.cpp.o -c ../src/ast/variable_expression_ast.cpp",
|
|
||||||
"file": "../src/ast/variable_expression_ast.cpp",
|
|
||||||
"output": "src/obelisk.p/ast_variable_expression_ast.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/models_action.cpp.o -MF src/obelisk.p/models_action.cpp.o.d -o src/obelisk.p/models_action.cpp.o -c ../src/models/action.cpp",
|
|
||||||
"file": "../src/models/action.cpp",
|
|
||||||
"output": "src/obelisk.p/models_action.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/models_entity.cpp.o -MF src/obelisk.p/models_entity.cpp.o.d -o src/obelisk.p/models_entity.cpp.o -c ../src/models/entity.cpp",
|
|
||||||
"file": "../src/models/entity.cpp",
|
|
||||||
"output": "src/obelisk.p/models_entity.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/models_fact.cpp.o -MF src/obelisk.p/models_fact.cpp.o.d -o src/obelisk.p/models_fact.cpp.o -c ../src/models/fact.cpp",
|
|
||||||
"file": "../src/models/fact.cpp",
|
|
||||||
"output": "src/obelisk.p/models_fact.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/models_rule.cpp.o -MF src/obelisk.p/models_rule.cpp.o.d -o src/obelisk.p/models_rule.cpp.o -c ../src/models/rule.cpp",
|
|
||||||
"file": "../src/models/rule.cpp",
|
|
||||||
"output": "src/obelisk.p/models_rule.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/models_suggest_action.cpp.o -MF src/obelisk.p/models_suggest_action.cpp.o.d -o src/obelisk.p/models_suggest_action.cpp.o -c ../src/models/suggest_action.cpp",
|
|
||||||
"file": "../src/models/suggest_action.cpp",
|
|
||||||
"output": "src/obelisk.p/models_suggest_action.cpp.o"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"directory": "/mnt/data/ubb/courses/proyecto-titulo/obelisk/builddir",
|
|
||||||
"command": "c++ -Isrc/obelisk.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -std=c++17 -g -isystem/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -MD -MQ src/obelisk.p/models_verb.cpp.o -MF src/obelisk.p/models_verb.cpp.o.d -o src/obelisk.p/models_verb.cpp.o -c ../src/models/verb.cpp",
|
|
||||||
"file": "../src/models/verb.cpp",
|
|
||||||
"output": "src/obelisk.p/models_verb.cpp.o"
|
|
||||||
}
|
|
||||||
]
|
|
2661
doc/doxygen.conf.in
Normal file
2661
doc/doxygen.conf.in
Normal file
File diff suppressed because it is too large
Load Diff
18
doc/meson.build
Normal file
18
doc/meson.build
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
cdata.set('TOP_SRCDIR', meson.project_source_root())
|
||||||
|
cdata.set('TOP_BUILDDIR', meson.project_build_root())
|
||||||
|
|
||||||
|
doxyfile = configure_file(input: 'doxygen.conf.in',
|
||||||
|
output: 'doxygen.conf',
|
||||||
|
configuration: cdata,
|
||||||
|
install: false
|
||||||
|
)
|
||||||
|
|
||||||
|
datadir = join_paths(get_option('datadir'), 'doc', 'obelisk')
|
||||||
|
|
||||||
|
html_target = custom_target('obelisk-docs',
|
||||||
|
input: doxyfile,
|
||||||
|
output: 'html',
|
||||||
|
command: [doxygen, doxyfile],
|
||||||
|
install: true,
|
||||||
|
install_dir: datadir
|
||||||
|
)
|
22
meson.build
22
meson.build
@ -1,6 +1,8 @@
|
|||||||
project('obelisk',
|
project('obelisk',
|
||||||
|
'c',
|
||||||
'cpp',
|
'cpp',
|
||||||
version : '1.0.0',
|
version : '1.0.0',
|
||||||
|
license : 'BSD-3-Clause',
|
||||||
default_options : [
|
default_options : [
|
||||||
'warning_level=3',
|
'warning_level=3',
|
||||||
'c_std=c17',
|
'c_std=c17',
|
||||||
@ -8,4 +10,24 @@ project('obelisk',
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
project_version_lib = '0'
|
||||||
|
|
||||||
|
llvm = dependency('llvm', version: '>= 14.0.0', modules : ['core', 'target', 'mcjit', 'nativecodegen'], required : true, method: 'config-tool')
|
||||||
|
|
||||||
|
cdata = configuration_data()
|
||||||
|
cdata.set('VERSION', meson.project_version())
|
||||||
|
|
||||||
|
docs_enabled = get_option('docs')
|
||||||
|
if docs_enabled
|
||||||
|
doxygen = find_program('doxygen', required : false)
|
||||||
|
if doxygen.found()
|
||||||
|
if find_program('dot', required : false).found()
|
||||||
|
cdata.set('HAVE_DOT', 'YES')
|
||||||
|
else
|
||||||
|
cdata.set('HAVE_DOT', 'NO')
|
||||||
|
endif
|
||||||
|
subdir('doc')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
subdir('src')
|
subdir('src')
|
||||||
|
5
meson_options.txt
Normal file
5
meson_options.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
option('docs',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true,
|
||||||
|
description: 'Build documentation for obelisk'
|
||||||
|
)
|
@ -11,9 +11,28 @@
|
|||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief The LLVM context.
|
||||||
|
*
|
||||||
|
*/
|
||||||
static std::unique_ptr<llvm::LLVMContext> TheContext;
|
static std::unique_ptr<llvm::LLVMContext> TheContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The LLVM module.
|
||||||
|
*
|
||||||
|
*/
|
||||||
static std::unique_ptr<llvm::Module> TheModule;
|
static std::unique_ptr<llvm::Module> TheModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The LLVM IR builder.
|
||||||
|
*
|
||||||
|
*/
|
||||||
static std::unique_ptr<llvm::IRBuilder<>> Builder;
|
static std::unique_ptr<llvm::IRBuilder<>> Builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The LLVM named values.
|
||||||
|
*
|
||||||
|
*/
|
||||||
static std::map<std::string, llvm::Value *> NamedValues;
|
static std::map<std::string, llvm::Value *> NamedValues;
|
||||||
} // namespace obelisk
|
} // namespace obelisk
|
||||||
|
|
||||||
|
@ -9,19 +9,62 @@
|
|||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief The call AST expression node used to call functions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class CallExpressionAST : public ExpressionAST
|
class CallExpressionAST : public ExpressionAST
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The function being called.
|
||||||
|
*
|
||||||
|
*/
|
||||||
std::string callee_;
|
std::string callee_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The arguments passed to the function.
|
||||||
|
*
|
||||||
|
*/
|
||||||
std::vector<std::unique_ptr<ExpressionAST>> args_;
|
std::vector<std::unique_ptr<ExpressionAST>> args_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the callee.
|
||||||
|
*
|
||||||
|
* @return std::string Returns the name of the function being
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
std::string getCallee();
|
std::string getCallee();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the callee.
|
||||||
|
*
|
||||||
|
* @param[in] callee The name of the function.
|
||||||
|
*/
|
||||||
void setCallee(std::string callee);
|
void setCallee(std::string callee);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the arguments being used by the function.
|
||||||
|
*
|
||||||
|
* @return std::vector<std::unique_ptr<ExpressionAST>> Returns an
|
||||||
|
* AST expression containing the args.
|
||||||
|
*/
|
||||||
std::vector<std::unique_ptr<ExpressionAST>> getArgs();
|
std::vector<std::unique_ptr<ExpressionAST>> getArgs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the arguments to be used by the function.
|
||||||
|
*
|
||||||
|
* @param[in] args The args to set.
|
||||||
|
*/
|
||||||
void setArgs(std::vector<std::unique_ptr<ExpressionAST>> args);
|
void setArgs(std::vector<std::unique_ptr<ExpressionAST>> args);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new CallExpressionAST object.
|
||||||
|
*
|
||||||
|
* @param[in] callee The function to call.
|
||||||
|
* @param[in] args The args to pass into the function.
|
||||||
|
*/
|
||||||
CallExpressionAST(const std::string &callee,
|
CallExpressionAST(const std::string &callee,
|
||||||
std::vector<std::unique_ptr<ExpressionAST>> args) :
|
std::vector<std::unique_ptr<ExpressionAST>> args) :
|
||||||
callee_(callee),
|
callee_(callee),
|
||||||
@ -29,6 +72,11 @@ namespace obelisk
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate the calle IR code.
|
||||||
|
*
|
||||||
|
* @return llvm::Value*
|
||||||
|
*/
|
||||||
llvm::Value *codegen() override;
|
llvm::Value *codegen() override;
|
||||||
};
|
};
|
||||||
} // namespace obelisk
|
} // namespace obelisk
|
||||||
|
@ -7,8 +7,22 @@
|
|||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
std::unique_ptr<ExpressionAST> LogError(const char *Str);
|
/**
|
||||||
llvm::Value *LogErrorV(const char *Str);
|
* @brief Log an AST expression error.
|
||||||
|
*
|
||||||
|
* @param[in] str The error message.
|
||||||
|
* @return std::unique_ptr<ExpressionAST> Returns the AST expression that
|
||||||
|
* caused the error.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<ExpressionAST> LogError(const char *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Log an AST value error.
|
||||||
|
*
|
||||||
|
* @param[in] str The error message.
|
||||||
|
* @return llvm::Value* Returns the AST value that caused the error.
|
||||||
|
*/
|
||||||
|
llvm::Value *LogErrorV(const char *str);
|
||||||
} // namespace obelisk
|
} // namespace obelisk
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,10 +5,25 @@
|
|||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief A generic AST expression which other expression will inherit from.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class ExpressionAST
|
class ExpressionAST
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Destroy the ExpressionAST object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
virtual ~ExpressionAST() = default;
|
virtual ~ExpressionAST() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate LLVM IR code based on the AST expression.
|
||||||
|
*
|
||||||
|
* @return llvm::Value* Returns the LLVM code value from the
|
||||||
|
* expression.
|
||||||
|
*/
|
||||||
virtual llvm::Value *codegen() = 0;
|
virtual llvm::Value *codegen() = 0;
|
||||||
};
|
};
|
||||||
} // namespace obelisk
|
} // namespace obelisk
|
||||||
|
@ -8,16 +8,46 @@
|
|||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief A Funcion AST node.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class FunctionAST
|
class FunctionAST
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The prototype of the function.
|
||||||
|
*
|
||||||
|
*/
|
||||||
std::unique_ptr<PrototypeAST> prototype_;
|
std::unique_ptr<PrototypeAST> prototype_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The body of the function.
|
||||||
|
*
|
||||||
|
*/
|
||||||
std::unique_ptr<ExpressionAST> body_;
|
std::unique_ptr<ExpressionAST> body_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the prototype.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<PrototypeAST> Returns the prototype AST.
|
||||||
|
*/
|
||||||
std::unique_ptr<PrototypeAST> getPrototype();
|
std::unique_ptr<PrototypeAST> getPrototype();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the prototype.
|
||||||
|
*
|
||||||
|
* @param[in] prototype Set the prototype.
|
||||||
|
*/
|
||||||
void setPrototype(std::unique_ptr<PrototypeAST> prototype);
|
void setPrototype(std::unique_ptr<PrototypeAST> prototype);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new FunctionAST object.
|
||||||
|
*
|
||||||
|
* @param[in] prototype The prototype of the function.
|
||||||
|
* @param[in] body The body of the function.
|
||||||
|
*/
|
||||||
FunctionAST(std::unique_ptr<PrototypeAST> prototype,
|
FunctionAST(std::unique_ptr<PrototypeAST> prototype,
|
||||||
std::unique_ptr<ExpressionAST> body) :
|
std::unique_ptr<ExpressionAST> body) :
|
||||||
prototype_(std::move(prototype)),
|
prototype_(std::move(prototype)),
|
||||||
@ -25,6 +55,11 @@ namespace obelisk
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate LLVM IR code.
|
||||||
|
*
|
||||||
|
* @return llvm::Function* Returns the LLVM IR function code.
|
||||||
|
*/
|
||||||
llvm::Function *codegen();
|
llvm::Function *codegen();
|
||||||
};
|
};
|
||||||
} // namespace obelisk
|
} // namespace obelisk
|
||||||
|
@ -5,20 +5,49 @@
|
|||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief A number expression AST node.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class NumberExpressionAST : public ExpressionAST
|
class NumberExpressionAST : public ExpressionAST
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The number.
|
||||||
|
*
|
||||||
|
*/
|
||||||
double number_;
|
double number_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the number.
|
||||||
|
*
|
||||||
|
* @return double Returns the number.
|
||||||
|
*/
|
||||||
double getNumber();
|
double getNumber();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the number.
|
||||||
|
*
|
||||||
|
* @param[in] number The number.
|
||||||
|
*/
|
||||||
void setNumber(double number);
|
void setNumber(double number);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new NumberExpressionAST object.
|
||||||
|
*
|
||||||
|
* @param[in] number The number.
|
||||||
|
*/
|
||||||
NumberExpressionAST(double number) :
|
NumberExpressionAST(double number) :
|
||||||
number_(number)
|
number_(number)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate LLVM IR code for the number.
|
||||||
|
*
|
||||||
|
* @return llvm::Value* Returns the genrated IR code.
|
||||||
|
*/
|
||||||
llvm::Value *codegen() override;
|
llvm::Value *codegen() override;
|
||||||
};
|
};
|
||||||
} // namespace obelisk
|
} // namespace obelisk
|
||||||
|
@ -8,17 +8,52 @@
|
|||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief The prototype AST node.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class PrototypeAST
|
class PrototypeAST
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The name of the prototype.
|
||||||
|
*
|
||||||
|
*/
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
/**
|
||||||
|
* @brief The arguments the protype accepts.
|
||||||
|
*
|
||||||
|
*/
|
||||||
std::vector<std::string> args_;
|
std::vector<std::string> args_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the name of the prototype.
|
||||||
|
*
|
||||||
|
* @param[in] name The name.
|
||||||
|
*/
|
||||||
void setName(const std::string& name);
|
void setName(const std::string& name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the arguments the prototype accepts.
|
||||||
|
*
|
||||||
|
* @return std::vector<std::string> Returns the arguments.
|
||||||
|
*/
|
||||||
std::vector<std::string> getArgs();
|
std::vector<std::string> getArgs();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the arguments the prototype accepts.
|
||||||
|
*
|
||||||
|
* @param[in] args The arguments.
|
||||||
|
*/
|
||||||
void setArgs(std::vector<std::string> args);
|
void setArgs(std::vector<std::string> args);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new PrototypeAST object.
|
||||||
|
*
|
||||||
|
* @param[in] name The name of the prototype.
|
||||||
|
* @param[in] args The arguments the prototype accepts.
|
||||||
|
*/
|
||||||
PrototypeAST(const std::string& name,
|
PrototypeAST(const std::string& name,
|
||||||
std::vector<std::string> args) :
|
std::vector<std::string> args) :
|
||||||
name_(name),
|
name_(name),
|
||||||
@ -26,13 +61,23 @@ namespace obelisk
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the name of the prototype.
|
||||||
|
*
|
||||||
|
* @return const std::string& Returns the name of the prototype.
|
||||||
|
*/
|
||||||
const std::string& getName() const
|
const std::string& getName() const
|
||||||
{
|
{
|
||||||
return name_;
|
return name_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate LLVM IR code for the prototype.
|
||||||
|
*
|
||||||
|
* @return llvm::Function* Returns IR code for the prototype.
|
||||||
|
*/
|
||||||
llvm::Function* codegen();
|
llvm::Function* codegen();
|
||||||
};
|
};
|
||||||
} //namespace obelisk
|
} // namespace obelisk
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,21 +7,51 @@
|
|||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief The variable expression AST node.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class VariableExpressionAST : public ExpressionAST
|
class VariableExpressionAST : public ExpressionAST
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The name of the variable.
|
||||||
|
*
|
||||||
|
*/
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the name of the variable.
|
||||||
|
*
|
||||||
|
* @return std::string Returns the name of the variable.
|
||||||
|
*/
|
||||||
std::string getName();
|
std::string getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the name of the variable.
|
||||||
|
*
|
||||||
|
* @param[in] name The name of the variable.
|
||||||
|
*/
|
||||||
void setName(const std::string name);
|
void setName(const std::string name);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new VariableExpressionAST object.
|
||||||
|
*
|
||||||
|
* @param[in] name The name of the variable.
|
||||||
|
*/
|
||||||
VariableExpressionAST(const std::string &name) :
|
VariableExpressionAST(const std::string &name) :
|
||||||
name_(name)
|
name_(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate the variable LLVM IR code.
|
||||||
|
*
|
||||||
|
* @return llvm::Value* Returns the generated IR code.
|
||||||
|
*/
|
||||||
llvm::Value *codegen() override;
|
llvm::Value *codegen() override;
|
||||||
};
|
};
|
||||||
} //namespace obelisk
|
} // namespace obelisk
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
#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
|
|
||||||
{
|
|
||||||
class KnowledgeBase
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
const int DEFAULT_FLAGS
|
|
||||||
= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
|
||||||
const char* filename_;
|
|
||||||
sqlite3* dbConnection_ = nullptr;
|
|
||||||
int flags_;
|
|
||||||
void logSqliteError(int result);
|
|
||||||
|
|
||||||
void enableForeignKeys();
|
|
||||||
void createTable(std::function<const char*()> function);
|
|
||||||
|
|
||||||
public:
|
|
||||||
KnowledgeBase(const char* filename, int flags);
|
|
||||||
|
|
||||||
KnowledgeBase(const char* filename) :
|
|
||||||
KnowledgeBase(filename,
|
|
||||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~KnowledgeBase();
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
class KnowledgeBaseException : public std::exception
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
const std::string errorMessage_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
KnowledgeBaseException() :
|
|
||||||
errorMessage_("an unknown error ocurred")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
KnowledgeBaseException(const std::string& errorMessage) :
|
|
||||||
errorMessage_(errorMessage)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* what() const noexcept
|
|
||||||
{
|
|
||||||
return errorMessage_.c_str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace obelisk
|
|
||||||
|
|
||||||
#endif
|
|
@ -2,20 +2,34 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
obelisk::Lexer::Lexer(const std::string& sourceFile)
|
||||||
|
{
|
||||||
|
fileStream_.open(sourceFile, std::ifstream::in);
|
||||||
|
if (!fileStream_)
|
||||||
|
{
|
||||||
|
throw obelisk::LexerException(
|
||||||
|
"could not open source file " + sourceFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obelisk::Lexer::~Lexer()
|
||||||
|
{
|
||||||
|
fileStream_.close();
|
||||||
|
fileStream_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
int obelisk::Lexer::getToken()
|
int obelisk::Lexer::getToken()
|
||||||
{
|
{
|
||||||
static int lastChar = ' ';
|
|
||||||
|
|
||||||
while (isspace(lastChar))
|
while (isspace(lastChar))
|
||||||
{
|
{
|
||||||
lastChar = std::getc(stdin);
|
lastChar = fileStream_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isalpha(lastChar))
|
if (isalpha(lastChar))
|
||||||
{
|
{
|
||||||
eraseIdentifier();
|
eraseIdentifier();
|
||||||
appendIdentifier(lastChar);
|
appendIdentifier(lastChar);
|
||||||
while (isalnum((lastChar = getchar())))
|
while (isalnum((lastChar = fileStream_.get())))
|
||||||
{
|
{
|
||||||
appendIdentifier(lastChar);
|
appendIdentifier(lastChar);
|
||||||
}
|
}
|
||||||
@ -27,7 +41,7 @@ int obelisk::Lexer::getToken()
|
|||||||
|
|
||||||
if (getIdentifier() == "rule")
|
if (getIdentifier() == "rule")
|
||||||
{
|
{
|
||||||
return Token::kTokenFact;
|
return Token::kTokenRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getIdentifier() == "action")
|
if (getIdentifier() == "action")
|
||||||
@ -63,7 +77,7 @@ int obelisk::Lexer::getToken()
|
|||||||
firstPeriod = true;
|
firstPeriod = true;
|
||||||
}
|
}
|
||||||
numberStr += lastChar;
|
numberStr += lastChar;
|
||||||
lastChar = getchar();
|
lastChar = fileStream_.get();
|
||||||
}
|
}
|
||||||
while (isdigit(lastChar) || lastChar == '.');
|
while (isdigit(lastChar) || lastChar == '.');
|
||||||
|
|
||||||
@ -83,7 +97,7 @@ int obelisk::Lexer::getToken()
|
|||||||
}
|
}
|
||||||
else if (lastChar == '/')
|
else if (lastChar == '/')
|
||||||
{
|
{
|
||||||
lastChar = getchar();
|
lastChar = fileStream_.get();
|
||||||
if (lastChar == '/')
|
if (lastChar == '/')
|
||||||
{
|
{
|
||||||
commentLine(&lastChar);
|
commentLine(&lastChar);
|
||||||
@ -101,7 +115,7 @@ int obelisk::Lexer::getToken()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int thisChar = lastChar;
|
int thisChar = lastChar;
|
||||||
lastChar = getchar();
|
lastChar = fileStream_.get();
|
||||||
return thisChar;
|
return thisChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +123,7 @@ void obelisk::Lexer::commentLine(int* lastChar)
|
|||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
*lastChar = getchar();
|
*lastChar = fileStream_.get();
|
||||||
}
|
}
|
||||||
while (*lastChar != EOF && *lastChar != '\n' && *lastChar != '\r');
|
while (*lastChar != EOF && *lastChar != '\n' && *lastChar != '\r');
|
||||||
}
|
}
|
||||||
|
146
src/lexer.h
146
src/lexer.h
@ -1,62 +1,202 @@
|
|||||||
#ifndef OBELISK_LEXER_H
|
#ifndef OBELISK_LEXER_H
|
||||||
#define OBELISK_LEXER_H
|
#define OBELISK_LEXER_H
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief The Lexer reads and identifies tokens in the obelisk source code.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class Lexer
|
class Lexer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
int lastChar = ' ';
|
||||||
|
/**
|
||||||
|
* @brief The stream of the source file being read.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::ifstream fileStream_;
|
||||||
|
/**
|
||||||
|
* @brief The last found identifier.
|
||||||
|
*
|
||||||
|
*/
|
||||||
std::string identifier_;
|
std::string identifier_;
|
||||||
double numberValue_;
|
/**
|
||||||
|
* @brief The last found number.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
double numberValue_ = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the identifier.
|
||||||
|
*
|
||||||
|
* @param[in] identifier The new identifier.
|
||||||
|
*/
|
||||||
void setIdentifier(const std::string& identifier);
|
void setIdentifier(const std::string& identifier);
|
||||||
|
/**
|
||||||
|
* @brief Erase the last identifier.
|
||||||
|
*
|
||||||
|
*/
|
||||||
void eraseIdentifier();
|
void eraseIdentifier();
|
||||||
|
/**
|
||||||
|
* @brief Add the last found char to the end of the identifier.
|
||||||
|
*
|
||||||
|
* @param[in] lastChar The last char that was found.
|
||||||
|
*/
|
||||||
void appendIdentifier(int lastChar);
|
void appendIdentifier(int lastChar);
|
||||||
|
/**
|
||||||
|
* @brief Set the number value.
|
||||||
|
*
|
||||||
|
* @param[in] numberValue The new number value.
|
||||||
|
*/
|
||||||
void setNumberValue(double numberValue);
|
void setNumberValue(double numberValue);
|
||||||
|
/**
|
||||||
|
* @brief Comment the rest of the line.
|
||||||
|
*
|
||||||
|
* @param[in] lastChar The char to check to see if it in the end of
|
||||||
|
* the line.
|
||||||
|
*/
|
||||||
void commentLine(int* lastChar);
|
void commentLine(int* lastChar);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief These token represent recognized language keywords and
|
||||||
|
* language functionality.
|
||||||
|
*
|
||||||
|
*/
|
||||||
enum Token
|
enum Token
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief End of file is returned when the source code is
|
||||||
|
* finished.
|
||||||
|
*
|
||||||
|
*/
|
||||||
kTokenEof = -1,
|
kTokenEof = -1,
|
||||||
|
|
||||||
// commands
|
/**
|
||||||
|
* @brief A fact which is a relationship between 2 entities.
|
||||||
|
*
|
||||||
|
*/
|
||||||
kTokenFact = -2,
|
kTokenFact = -2,
|
||||||
|
/**
|
||||||
|
* @brief A rule which is a relationship between a new fact a
|
||||||
|
* existing fact.
|
||||||
|
*
|
||||||
|
*/
|
||||||
kTokenRule = -3,
|
kTokenRule = -3,
|
||||||
|
/**
|
||||||
|
* @brief An action to take if a fact is true.
|
||||||
|
*
|
||||||
|
*/
|
||||||
kTokenAction = -4,
|
kTokenAction = -4,
|
||||||
|
/**
|
||||||
|
* @brief A definition of a new function.
|
||||||
|
*
|
||||||
|
*/
|
||||||
kTokenDef = -5,
|
kTokenDef = -5,
|
||||||
|
/**
|
||||||
|
* @brief An external function that will be linked to.
|
||||||
|
*
|
||||||
|
*/
|
||||||
kTokenExtern = -6,
|
kTokenExtern = -6,
|
||||||
|
|
||||||
// primary
|
/**
|
||||||
|
* @brief An identifier which is a alphanumeric value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
kTokenIdentifier = -7,
|
kTokenIdentifier = -7,
|
||||||
|
/**
|
||||||
|
* @brief A double floating point value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
kTokenNumber = -8,
|
kTokenNumber = -8,
|
||||||
|
/**
|
||||||
|
* @brief A string.
|
||||||
|
*
|
||||||
|
*/
|
||||||
kTokenString = -9
|
kTokenString = -9
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Lexer object.
|
||||||
|
*
|
||||||
|
* @param[in] sourceFile The source file to read.
|
||||||
|
*/
|
||||||
|
Lexer(const std::string& sourceFile);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy the Lexer object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
~Lexer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the next token in the source code.
|
||||||
|
*
|
||||||
|
* @throws LexerException when an invalid token is found.
|
||||||
|
* @return int Returns a Token value or char if no known token was
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
int getToken();
|
int getToken();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last identifier.
|
||||||
|
*
|
||||||
|
* @return const std::string& Returns a string that contains the
|
||||||
|
* last found identifier.
|
||||||
|
*/
|
||||||
const std::string& getIdentifier();
|
const std::string& getIdentifier();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the last number value.
|
||||||
|
*
|
||||||
|
* @return double Return the last number that was found.
|
||||||
|
*/
|
||||||
double getNumberValue();
|
double getNumberValue();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Lexer exception class.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class LexerException : public std::exception
|
class LexerException : public std::exception
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The error message from the exception.
|
||||||
|
*
|
||||||
|
*/
|
||||||
const std::string errorMessage_;
|
const std::string errorMessage_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new LexerException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
LexerException() :
|
LexerException() :
|
||||||
errorMessage_("an unknown error ocurred")
|
errorMessage_("an unknown error ocurred")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new LexerException object.
|
||||||
|
*
|
||||||
|
* @param[in] errorMessage Error message to include.
|
||||||
|
*/
|
||||||
LexerException(const std::string& errorMessage) :
|
LexerException(const std::string& errorMessage) :
|
||||||
errorMessage_(errorMessage)
|
errorMessage_(errorMessage)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the exception's error message.
|
||||||
|
*
|
||||||
|
* @return const char* Returns a string containing the error
|
||||||
|
* message.
|
||||||
|
*/
|
||||||
const char* what() const noexcept
|
const char* what() const noexcept
|
||||||
{
|
{
|
||||||
return errorMessage_.c_str();
|
return errorMessage_.c_str();
|
||||||
|
82
src/lib/include/obelisk.h
Normal file
82
src/lib/include/obelisk.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#ifndef OBELISK_INCLUDE_OBELISK_H
|
||||||
|
#define OBELISK_INCLUDE_OBELISK_H
|
||||||
|
|
||||||
|
#include "knowledge_base.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The obelisk namespace contains everything needed to compile obelisk
|
||||||
|
* code.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The obelisk library provides everything needed to consult the
|
||||||
|
* KnowledgeBase.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Obelisk
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::unique_ptr<obelisk::KnowledgeBase> kb_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Obelisk object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Obelisk(std::string filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy the Obelisk object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
~Obelisk() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the obelisk version.
|
||||||
|
*
|
||||||
|
* @return std::string The version.
|
||||||
|
*/
|
||||||
|
std::string getVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the obelisk library so version.
|
||||||
|
*
|
||||||
|
* @return int The version.
|
||||||
|
*/
|
||||||
|
int getLibVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query the obelisk KnowledgeBase to see if a Fact is true
|
||||||
|
* or not.
|
||||||
|
*
|
||||||
|
* @param[in] p_obelisk The obelisk object pointer.
|
||||||
|
* @param[in] left_entity The left entity.
|
||||||
|
* @param[in] verb The verb.
|
||||||
|
* @param[in] right_entity The right entity.
|
||||||
|
* @return double Returns whether or not the Fact is true.
|
||||||
|
*/
|
||||||
|
double query(const std::string& leftEntity,
|
||||||
|
const std::string& verb,
|
||||||
|
const std::string& rightEntity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query the Obelisk KnowledgeBase and return the suggested
|
||||||
|
* action to take.
|
||||||
|
*
|
||||||
|
* @param[in] leftEntity The left entity.
|
||||||
|
* @param[in] verb The verb.
|
||||||
|
* @param[in] rightEntity The right entity.
|
||||||
|
* @return std::string Returns the suggested action.
|
||||||
|
*/
|
||||||
|
std::string queryAction(const std::string& leftEntity,
|
||||||
|
const std::string& verb,
|
||||||
|
const std::string& rightEntity);
|
||||||
|
};
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
80
src/lib/include/obelisk_c.h
Normal file
80
src/lib/include/obelisk_c.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#ifndef OBELISK_INCLUDE_OBELISK_PROGRAM_H
|
||||||
|
#define OBELISK_INCLUDE_OBELISK_PROGRAM_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct wrapper around Obelisk class.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
typedef struct CObelisk CObelisk;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create an obelisk object.
|
||||||
|
*
|
||||||
|
* @param[in] filename The obelisk KnowledgeBase file to use.
|
||||||
|
* @return CObelisk* Returns an obelisk object.
|
||||||
|
*/
|
||||||
|
extern CObelisk* obelisk_open(const char* filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete an obelisk object.
|
||||||
|
*
|
||||||
|
* @param[in] obelisk The obelisk object.
|
||||||
|
*/
|
||||||
|
extern void obelisk_close(CObelisk* obelisk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the obelisk version.
|
||||||
|
*
|
||||||
|
* @param[in] obelisk The obelisk object.
|
||||||
|
* @return const char* Returns a string containing the version. This must be
|
||||||
|
* freed by the caller.
|
||||||
|
*/
|
||||||
|
extern char* obelisk_get_version(CObelisk* obelisk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query the obelisk KnowledgeBase to see if a Fact is true or false.
|
||||||
|
*
|
||||||
|
* @param[in] obelisk The obelisk object.
|
||||||
|
* @param[in] left_entity The left entity.
|
||||||
|
* @param[in] verb The verb.
|
||||||
|
* @param[in] right_entity The right entity.
|
||||||
|
* @return double Returns whether the Fact is true or false.
|
||||||
|
*/
|
||||||
|
extern double obelisk_query(CObelisk* obelisk,
|
||||||
|
const char* left_entity,
|
||||||
|
const char* verb,
|
||||||
|
const char* right_entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query the obelisk KnowledgeBase to get a suggested Action to do.
|
||||||
|
*
|
||||||
|
* @param[in] obelisk The obelisk object.
|
||||||
|
* @param[in] left_entity The left entity.
|
||||||
|
* @param[in] verb The verb.
|
||||||
|
* @param[in] right_entity The right entity.
|
||||||
|
* @return char* Returns the Action to do or an empty string if there is no
|
||||||
|
* action.
|
||||||
|
*/
|
||||||
|
extern char* obelisk_query_action(CObelisk* obelisk,
|
||||||
|
const char* left_entity,
|
||||||
|
const char* verb,
|
||||||
|
const char* right_entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the obelisk library so version.
|
||||||
|
*
|
||||||
|
* @param[in] obelisk The obelisk object.
|
||||||
|
* @return int Returns the so version.
|
||||||
|
*/
|
||||||
|
extern int obelisk_get_lib_version(CObelisk* obelisk);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -1,11 +1,5 @@
|
|||||||
#include "knowledge_base.h"
|
#include "knowledge_base.h"
|
||||||
#include "models/action.h"
|
|
||||||
#include "models/entity.h"
|
|
||||||
#include "models/error.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 <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@ -23,7 +17,7 @@ obelisk::KnowledgeBase::KnowledgeBase(const char* filename, int flags)
|
|||||||
auto result = sqlite3_open_v2(filename, &dbConnection_, flags, NULL);
|
auto result = sqlite3_open_v2(filename, &dbConnection_, flags, NULL);
|
||||||
if (result != SQLITE_OK)
|
if (result != SQLITE_OK)
|
||||||
{
|
{
|
||||||
logSqliteError(result);
|
throw new KnowledgeBaseException("database could not be opened");
|
||||||
}
|
}
|
||||||
|
|
||||||
enableForeignKeys();
|
enableForeignKeys();
|
||||||
@ -47,12 +41,6 @@ obelisk::KnowledgeBase::~KnowledgeBase()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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()
|
void obelisk::KnowledgeBase::enableForeignKeys()
|
||||||
{
|
{
|
||||||
char* errmsg;
|
char* errmsg;
|
||||||
@ -63,7 +51,6 @@ void obelisk::KnowledgeBase::enableForeignKeys()
|
|||||||
&errmsg);
|
&errmsg);
|
||||||
if (result != SQLITE_OK)
|
if (result != SQLITE_OK)
|
||||||
{
|
{
|
||||||
logSqliteError(result);
|
|
||||||
if (errmsg)
|
if (errmsg)
|
||||||
{
|
{
|
||||||
throw obelisk::KnowledgeBaseException(errmsg);
|
throw obelisk::KnowledgeBaseException(errmsg);
|
||||||
@ -81,7 +68,6 @@ void obelisk::KnowledgeBase::createTable(std::function<const char*()> function)
|
|||||||
int result = sqlite3_exec(dbConnection_, function(), NULL, NULL, &errmsg);
|
int result = sqlite3_exec(dbConnection_, function(), NULL, NULL, &errmsg);
|
||||||
if (result != SQLITE_OK)
|
if (result != SQLITE_OK)
|
||||||
{
|
{
|
||||||
logSqliteError(result);
|
|
||||||
if (errmsg)
|
if (errmsg)
|
||||||
{
|
{
|
||||||
throw obelisk::KnowledgeBaseException(errmsg);
|
throw obelisk::KnowledgeBaseException(errmsg);
|
||||||
@ -99,9 +85,9 @@ void obelisk::KnowledgeBase::addEntities(std::vector<obelisk::Entity>& entities)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
entity.insertEntity(dbConnection_);
|
entity.insert(dbConnection_);
|
||||||
}
|
}
|
||||||
catch (obelisk::DatabaseException::ConstraintException& exception)
|
catch (obelisk::DatabaseConstraintException& exception)
|
||||||
{
|
{
|
||||||
// ignore unique constraint error
|
// ignore unique constraint error
|
||||||
if (std::strcmp(exception.what(),
|
if (std::strcmp(exception.what(),
|
||||||
@ -120,9 +106,9 @@ void obelisk::KnowledgeBase::addVerbs(std::vector<obelisk::Verb>& verbs)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
verb.insertVerb(dbConnection_);
|
verb.insert(dbConnection_);
|
||||||
}
|
}
|
||||||
catch (obelisk::DatabaseException::ConstraintException& exception)
|
catch (obelisk::DatabaseConstraintException& exception)
|
||||||
{
|
{
|
||||||
// ignore unique constraint error
|
// ignore unique constraint error
|
||||||
if (std::strcmp(exception.what(),
|
if (std::strcmp(exception.what(),
|
||||||
@ -135,15 +121,36 @@ void obelisk::KnowledgeBase::addVerbs(std::vector<obelisk::Verb>& verbs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obelisk::KnowledgeBase::addActions(std::vector<obelisk::Action>& actions)
|
||||||
|
{
|
||||||
|
for (auto& action : actions)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
action.insert(dbConnection_);
|
||||||
|
}
|
||||||
|
catch (obelisk::DatabaseConstraintException& exception)
|
||||||
|
{
|
||||||
|
// ignore unique constraint error
|
||||||
|
if (std::strcmp(exception.what(),
|
||||||
|
"UNIQUE constraint failed: action.name")
|
||||||
|
!= 0)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void obelisk::KnowledgeBase::addFacts(std::vector<obelisk::Fact>& facts)
|
void obelisk::KnowledgeBase::addFacts(std::vector<obelisk::Fact>& facts)
|
||||||
{
|
{
|
||||||
for (auto& fact : facts)
|
for (auto& fact : facts)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
fact.insertFact(dbConnection_);
|
fact.insert(dbConnection_);
|
||||||
}
|
}
|
||||||
catch (obelisk::DatabaseException::ConstraintException& exception)
|
catch (obelisk::DatabaseConstraintException& exception)
|
||||||
{
|
{
|
||||||
// ignore unique constraint error
|
// ignore unique constraint error
|
||||||
if (std::strcmp(exception.what(),
|
if (std::strcmp(exception.what(),
|
||||||
@ -156,25 +163,111 @@ void obelisk::KnowledgeBase::addFacts(std::vector<obelisk::Fact>& facts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obelisk::KnowledgeBase::addSuggestActions(
|
||||||
|
std::vector<obelisk::SuggestAction>& suggestActions)
|
||||||
|
{
|
||||||
|
for (auto& suggestAction : suggestActions)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
suggestAction.insert(dbConnection_);
|
||||||
|
}
|
||||||
|
catch (obelisk::DatabaseConstraintException& exception)
|
||||||
|
{
|
||||||
|
// ignore unique constraint error
|
||||||
|
if (std::strcmp(exception.what(),
|
||||||
|
"UNIQUE constraint failed: suggest_action.fact, suggest_action.true_action, suggest_action.false_action")
|
||||||
|
!= 0)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::KnowledgeBase::addRules(std::vector<obelisk::Rule>& rules)
|
||||||
|
{
|
||||||
|
for (auto& rule : rules)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rule.insert(dbConnection_);
|
||||||
|
}
|
||||||
|
catch (obelisk::DatabaseConstraintException& exception)
|
||||||
|
{
|
||||||
|
// ignore unique constraint error
|
||||||
|
if (std::strcmp(exception.what(),
|
||||||
|
"UNIQUE constraint failed: rule.fact, rule.reason")
|
||||||
|
!= 0)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void obelisk::KnowledgeBase::getEntity(obelisk::Entity& entity)
|
void obelisk::KnowledgeBase::getEntity(obelisk::Entity& entity)
|
||||||
{
|
{
|
||||||
entity.selectEntity(dbConnection_);
|
entity.selectByName(dbConnection_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::KnowledgeBase::getVerb(obelisk::Verb& verb)
|
void obelisk::KnowledgeBase::getVerb(obelisk::Verb& verb)
|
||||||
{
|
{
|
||||||
verb.selectVerb(dbConnection_);
|
verb.selectByName(dbConnection_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::KnowledgeBase::getAction(obelisk::Action& action)
|
||||||
|
{
|
||||||
|
action.selectByName(dbConnection_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::KnowledgeBase::getFact(obelisk::Fact& fact)
|
void obelisk::KnowledgeBase::getFact(obelisk::Fact& fact)
|
||||||
{
|
{
|
||||||
fact.selectFact(dbConnection_);
|
fact.selectById(dbConnection_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: log files? or just throw an error?
|
void obelisk::KnowledgeBase::getSuggestAction(
|
||||||
void obelisk::KnowledgeBase::logSqliteError(int result)
|
obelisk::SuggestAction& suggestAction)
|
||||||
{
|
{
|
||||||
std::cout << sqlite3_errstr(result) << std::endl;
|
suggestAction.selectById(dbConnection_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::KnowledgeBase::getRule(obelisk::Rule& rule)
|
||||||
|
{
|
||||||
|
rule.selectById(dbConnection_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::KnowledgeBase::checkRule(obelisk::Fact& fact)
|
||||||
|
{
|
||||||
|
std::vector<obelisk::Rule> rules;
|
||||||
|
obelisk::Rule::selectByReason(dbConnection_, fact.getId(), rules);
|
||||||
|
for (auto& rule : rules)
|
||||||
|
{
|
||||||
|
auto reason = rule.getReason();
|
||||||
|
getFact(reason);
|
||||||
|
if (reason.getIsTrue() > 0)
|
||||||
|
{
|
||||||
|
auto updateFact = rule.getFact();
|
||||||
|
updateFact.setIsTrue(1.0);
|
||||||
|
updateFact.updateIsTrue(dbConnection_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::KnowledgeBase::updateIsTrue(obelisk::Fact& fact)
|
||||||
|
{
|
||||||
|
fact.updateIsTrue(dbConnection_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::KnowledgeBase::queryFact(obelisk::Fact& fact)
|
||||||
|
{
|
||||||
|
fact.selectByName(dbConnection_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::KnowledgeBase::querySuggestAction(obelisk::Fact& fact,
|
||||||
|
obelisk::Action& action)
|
||||||
|
{
|
||||||
|
fact.selectActionByFact(dbConnection_, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::KnowledgeBase::getFloat(float& result1,
|
void obelisk::KnowledgeBase::getFloat(float& result1,
|
292
src/lib/knowledge_base.h
Normal file
292
src/lib/knowledge_base.h
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
#ifndef OBELISK_KNOWLEDGE_BASE_H
|
||||||
|
#define OBELISK_KNOWLEDGE_BASE_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 <sqlite3.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The KnowledgeBase class represents a collection of facts, rules,
|
||||||
|
* actions, and related language connectors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class KnowledgeBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The filename of the opened KnowledgeBase.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const char* filename_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The SQLite connection handle.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
sqlite3* dbConnection_ = nullptr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The user passed flags to use when opening the database.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int flags_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 enableForeignKeys();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the tables in the database.
|
||||||
|
*
|
||||||
|
* @param[in] function This function is called to create the table.
|
||||||
|
*/
|
||||||
|
void createTable(std::function<const char*()> function);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new KnowledgeBase object.
|
||||||
|
*
|
||||||
|
* @param[in] filename The name of the file to save the knowledge
|
||||||
|
* base as.
|
||||||
|
* @param[in] flags The flags to open the KnowledgeBase with.
|
||||||
|
*/
|
||||||
|
KnowledgeBase(const char* filename, int flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new KnowledgeBase object.
|
||||||
|
*
|
||||||
|
* @param[in] filename The name of the file to save the knowledge
|
||||||
|
* base as.
|
||||||
|
*/
|
||||||
|
KnowledgeBase(const char* filename) :
|
||||||
|
KnowledgeBase(filename,
|
||||||
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy the KnowledgeBase object.
|
||||||
|
*
|
||||||
|
* This will close the opened KnowledgeBase before destroying it.
|
||||||
|
*/
|
||||||
|
~KnowledgeBase();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add entities to the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in,out] entities The entities to add. If the insert is
|
||||||
|
* successful it will have a row ID, if not the ID will be 0.
|
||||||
|
*/
|
||||||
|
void addEntities(std::vector<obelisk::Entity>& entities);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add verbs to the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in,out] verbs The verbs to add. If the insert is
|
||||||
|
* successful it will have a row ID, if not the ID will be 0.
|
||||||
|
*/
|
||||||
|
void addVerbs(std::vector<obelisk::Verb>& verbs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add actions to the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in,out] actions The actions to add. If the insert is
|
||||||
|
* successful it will have a row ID, if nto the ID will be 0.
|
||||||
|
*/
|
||||||
|
void addActions(std::vector<obelisk::Action>& actions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add facts to the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in,out] facts The facts to add. If the insert is
|
||||||
|
* successful it will have a row ID, if not the ID will be 0.
|
||||||
|
*/
|
||||||
|
void addFacts(std::vector<obelisk::Fact>& facts);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add suggested actions to the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in,out] suggestActions The suggested actions to add. If
|
||||||
|
* the insert is successful it will have a row ID, if not the ID
|
||||||
|
* will be 0.
|
||||||
|
*/
|
||||||
|
void addSuggestActions(
|
||||||
|
std::vector<obelisk::SuggestAction>& suggestActions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add rules to the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in,out] rules The rules to add. If the insert is
|
||||||
|
* successful it will have a row ID, if not the ID will be 0.
|
||||||
|
*/
|
||||||
|
void addRules(std::vector<obelisk::Rule>& rules);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get an Entity object based on the ID it contains.
|
||||||
|
*
|
||||||
|
* @param[in,out] entity The Entity object should contain just the
|
||||||
|
* ID and the rest will be filled in.
|
||||||
|
*/
|
||||||
|
void getEntity(obelisk::Entity& entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a Verb object based on the ID it contains.
|
||||||
|
*
|
||||||
|
* @param[in,out] verb The Verb object should contain just the ID
|
||||||
|
* and the rest will be filled in.
|
||||||
|
*/
|
||||||
|
void getVerb(obelisk::Verb& verb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get an Action based on the ID it contains.
|
||||||
|
*
|
||||||
|
* @param[in] action The Action object should contain just the ID
|
||||||
|
* and the rest will be filled in.
|
||||||
|
*/
|
||||||
|
void getAction(obelisk::Action& action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a Fact object based on the ID it contains.
|
||||||
|
*
|
||||||
|
* @param[in,out] fact The Fact object should contain just the ID
|
||||||
|
* and the rest will be filled in.
|
||||||
|
*/
|
||||||
|
void getFact(obelisk::Fact& fact);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a SuggestAction based on the ID it contains.
|
||||||
|
*
|
||||||
|
* @param[in,out] suggestAction The SuggestAction object should
|
||||||
|
* contain just the ID and the rest will be filled in.
|
||||||
|
*/
|
||||||
|
void getSuggestAction(obelisk::SuggestAction& suggestAction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a Rule based on the ID it contains.
|
||||||
|
*
|
||||||
|
* @param[in,out] rule The Rule object should contain just the ID
|
||||||
|
* and the rest will be filled in.
|
||||||
|
*/
|
||||||
|
void getRule(obelisk::Rule& rule);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a rule looks for this Fact, if so update its
|
||||||
|
* truth.
|
||||||
|
*
|
||||||
|
* @param[in,out] fact The Fact to check for existing rules.
|
||||||
|
*/
|
||||||
|
void checkRule(obelisk::Fact& fact);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the is true field in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in,out] fact The fact to update.
|
||||||
|
*/
|
||||||
|
void updateIsTrue(obelisk::Fact& fact);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query the KnowledgeBase to see if a Fact is true or false.
|
||||||
|
*
|
||||||
|
* @param[in] fact The Fact to check.
|
||||||
|
*/
|
||||||
|
void queryFact(obelisk::Fact& fact);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Query the KnowledgeBase to get a suggested action based
|
||||||
|
* on a Fact.
|
||||||
|
* If a SuggestAction doesn't exist, it will return an empty Action.
|
||||||
|
*
|
||||||
|
* @param[in] fact The Fact to search for.
|
||||||
|
* @param[out] action The Action that is suggested to take.
|
||||||
|
*/
|
||||||
|
void querySuggestAction(obelisk::Fact& fact,
|
||||||
|
obelisk::Action& action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Take a float and divide it into 2 floats.
|
||||||
|
*
|
||||||
|
* This is useful to store doubles in SQLite since SQLite doesn't
|
||||||
|
* have a double type. Instead just store the 2 floats in the
|
||||||
|
* database. Then after selecting them combine them.
|
||||||
|
*
|
||||||
|
* @param[out] result1 The first float generated from the double.
|
||||||
|
* @param[out] result2 The second float generated from the double.
|
||||||
|
* @param[in] var The double to split into the 2 floats.
|
||||||
|
*/
|
||||||
|
void getFloat(float& result1, float& result2, double var);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Combines 2 separated floats back into a double.
|
||||||
|
*
|
||||||
|
* This will recombine the separated floats from the getFloat
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @param[out] result The double generated from the combined floats.
|
||||||
|
* @param[in] var1 The first float to combine.
|
||||||
|
* @param[in] var2 The second float to combine.
|
||||||
|
*/
|
||||||
|
void getDouble(double& result, float var1, float var2);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exception thrown by the KnowledgeBase.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class KnowledgeBaseException : public std::exception
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The error message given.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const std::string errorMessage_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new KnowledgeBaseException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
KnowledgeBaseException() :
|
||||||
|
errorMessage_("an unknown error ocurred")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new KnowledgeBaseException object.
|
||||||
|
*
|
||||||
|
* @param[in] errorMessage The error message given when thrown.
|
||||||
|
*/
|
||||||
|
KnowledgeBaseException(const std::string& errorMessage) :
|
||||||
|
errorMessage_(errorMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the error message that occurred.
|
||||||
|
*
|
||||||
|
* @return const char* Returns the error message.
|
||||||
|
*/
|
||||||
|
const char* what() const noexcept
|
||||||
|
{
|
||||||
|
return errorMessage_.c_str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
36
src/lib/meson.build
Normal file
36
src/lib/meson.build
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
conf_data = configuration_data()
|
||||||
|
conf_data.set('version', meson.project_version())
|
||||||
|
conf_data.set('so_version', project_version_lib)
|
||||||
|
configure_file(input : 'version.h.in',
|
||||||
|
output : 'version.h',
|
||||||
|
configuration : conf_data
|
||||||
|
)
|
||||||
|
|
||||||
|
subdir('models')
|
||||||
|
|
||||||
|
obelisk_lib_sources = files(
|
||||||
|
'obelisk.cpp',
|
||||||
|
'obelisk.c',
|
||||||
|
'obelisk_wrapper.cpp',
|
||||||
|
'knowledge_base.cpp'
|
||||||
|
)
|
||||||
|
|
||||||
|
obelisk_lib_sources += obelisk_model_sources
|
||||||
|
|
||||||
|
sqlite3 = dependency('sqlite3')
|
||||||
|
|
||||||
|
incdirs = include_directories(['.', 'include'])
|
||||||
|
lib = library('obelisk',
|
||||||
|
obelisk_lib_sources,
|
||||||
|
include_directories: incdirs,
|
||||||
|
dependencies : [sqlite3],
|
||||||
|
version : meson.project_version(),
|
||||||
|
soversion : project_version_lib,
|
||||||
|
install : true
|
||||||
|
)
|
||||||
|
|
||||||
|
libobelisk = declare_dependency(
|
||||||
|
include_directories : incdirs,
|
||||||
|
link_with : lib,
|
||||||
|
sources : obelisk_lib_sources
|
||||||
|
)
|
168
src/lib/models/action.cpp
Normal file
168
src/lib/models/action.cpp
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
#include "models/action.h"
|
||||||
|
#include "models/error.h"
|
||||||
|
|
||||||
|
const char* obelisk::Action::createTable()
|
||||||
|
{
|
||||||
|
return R"(
|
||||||
|
CREATE TABLE "action" (
|
||||||
|
"id" INTEGER NOT NULL UNIQUE,
|
||||||
|
"name" TEXT NOT NULL CHECK(trim(name) != '') UNIQUE,
|
||||||
|
PRIMARY KEY("id" AUTOINCREMENT)
|
||||||
|
);
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Action::selectByName(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 action 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::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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::Action::insert(sqlite3* dbConnection)
|
||||||
|
{
|
||||||
|
if (dbConnection == nullptr)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException("database isn't open");
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
|
auto result = sqlite3_prepare_v2(dbConnection,
|
||||||
|
"INSERT INTO action (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::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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::DatabaseConstraintException(
|
||||||
|
sqlite3_errmsg(dbConnection));
|
||||||
|
case SQLITE_BUSY :
|
||||||
|
throw obelisk::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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::Action::getId()
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Action::setId(int id)
|
||||||
|
{
|
||||||
|
id_ = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& obelisk::Action::getName()
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Action::setName(std::string name)
|
||||||
|
{
|
||||||
|
name_ = name;
|
||||||
|
}
|
128
src/lib/models/action.h
Normal file
128
src/lib/models/action.h
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#ifndef OBELISK_MODELS_ACTION_H
|
||||||
|
#define OBELISK_MODELS_ACTION_H
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The Action model represents an action to take when a fact is true
|
||||||
|
* or false.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Action
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The ID of the Action in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int id_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The name of the Action.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::string name_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Action object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Action() :
|
||||||
|
id_(0),
|
||||||
|
name_("")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Action object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Action.
|
||||||
|
*/
|
||||||
|
Action(int id) :
|
||||||
|
id_(id),
|
||||||
|
name_("")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Action object.
|
||||||
|
*
|
||||||
|
* @param[in] name The name of the Action.
|
||||||
|
*/
|
||||||
|
Action(std::string name) :
|
||||||
|
id_(0),
|
||||||
|
name_(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Action object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Action.
|
||||||
|
* @param[in] name The name of the Action.
|
||||||
|
*/
|
||||||
|
Action(int id, std::string name) :
|
||||||
|
id_(id),
|
||||||
|
name_(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the Action table in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @return const char* Returns the query used to create the table.
|
||||||
|
*/
|
||||||
|
static const char* createTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the ID of the Action.
|
||||||
|
*
|
||||||
|
* @return int& Returns the ID.
|
||||||
|
*/
|
||||||
|
int& getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the ID of the Action.
|
||||||
|
*
|
||||||
|
* @param[in] id Set the ID of the Action.
|
||||||
|
*/
|
||||||
|
void setId(int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the name of the Action.
|
||||||
|
*
|
||||||
|
* @return std::string& The Action name.
|
||||||
|
*/
|
||||||
|
std::string& getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the name of the Action.
|
||||||
|
*
|
||||||
|
* @param[in] name The name of the Action.
|
||||||
|
*/
|
||||||
|
void setName(std::string name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select an Action from the datbase based on the object
|
||||||
|
* name.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void selectByName(sqlite3* dbConnection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Insert an Action into the KnowledgeBase based on the
|
||||||
|
* object's fields.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void insert(sqlite3* dbConnection);
|
||||||
|
};
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
@ -12,7 +12,7 @@ const char* obelisk::Entity::createTable()
|
|||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Entity::selectEntity(sqlite3* dbConnection)
|
void obelisk::Entity::selectByName(sqlite3* dbConnection)
|
||||||
{
|
{
|
||||||
if (dbConnection == nullptr)
|
if (dbConnection == nullptr)
|
||||||
{
|
{
|
||||||
@ -38,13 +38,13 @@ void obelisk::Entity::selectEntity(sqlite3* dbConnection)
|
|||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -62,10 +62,10 @@ void obelisk::Entity::selectEntity(sqlite3* dbConnection)
|
|||||||
setName((char*) sqlite3_column_text(ppStmt, 1));
|
setName((char*) sqlite3_column_text(ppStmt, 1));
|
||||||
break;
|
break;
|
||||||
case SQLITE_BUSY :
|
case SQLITE_BUSY :
|
||||||
throw obelisk::DatabaseException::BusyException();
|
throw obelisk::DatabaseBusyException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_MISUSE :
|
case SQLITE_MISUSE :
|
||||||
throw obelisk::DatabaseException::MisuseException();
|
throw obelisk::DatabaseMisuseException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -80,7 +80,7 @@ void obelisk::Entity::selectEntity(sqlite3* dbConnection)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Entity::insertEntity(sqlite3* dbConnection)
|
void obelisk::Entity::insert(sqlite3* dbConnection)
|
||||||
{
|
{
|
||||||
if (dbConnection == nullptr)
|
if (dbConnection == nullptr)
|
||||||
{
|
{
|
||||||
@ -106,13 +106,13 @@ void obelisk::Entity::insertEntity(sqlite3* dbConnection)
|
|||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -127,13 +127,13 @@ void obelisk::Entity::insertEntity(sqlite3* dbConnection)
|
|||||||
sqlite3_set_last_insert_rowid(dbConnection, 0);
|
sqlite3_set_last_insert_rowid(dbConnection, 0);
|
||||||
break;
|
break;
|
||||||
case SQLITE_CONSTRAINT :
|
case SQLITE_CONSTRAINT :
|
||||||
throw obelisk::DatabaseException::ConstraintException(
|
throw obelisk::DatabaseConstraintException(
|
||||||
sqlite3_errmsg(dbConnection));
|
sqlite3_errmsg(dbConnection));
|
||||||
case SQLITE_BUSY :
|
case SQLITE_BUSY :
|
||||||
throw obelisk::DatabaseException::BusyException();
|
throw obelisk::DatabaseBusyException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_MISUSE :
|
case SQLITE_MISUSE :
|
||||||
throw obelisk::DatabaseException::MisuseException();
|
throw obelisk::DatabaseMisuseException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
128
src/lib/models/entity.h
Normal file
128
src/lib/models/entity.h
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#ifndef OBELISK_MODELS_ENTITY_H
|
||||||
|
#define OBELISK_MODELS_ENTITY_H
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The Entity model represents either a left or right side entity,
|
||||||
|
* typically used in facts and rules.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Entity
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The ID of the Entity in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int id_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The name of the Entity.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::string name_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Entity object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Entity() :
|
||||||
|
id_(0),
|
||||||
|
name_("")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Entity object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Entity.
|
||||||
|
*/
|
||||||
|
Entity(int id) :
|
||||||
|
id_(id),
|
||||||
|
name_("")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Entity object.
|
||||||
|
*
|
||||||
|
* @param[in] name The name of the Entity.
|
||||||
|
*/
|
||||||
|
Entity(std::string name) :
|
||||||
|
id_(0),
|
||||||
|
name_(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Entity object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Entity.
|
||||||
|
* @param[in] name The name of the Entity.
|
||||||
|
*/
|
||||||
|
Entity(int id, std::string name) :
|
||||||
|
id_(id),
|
||||||
|
name_(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the table in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @return const char* Returns the query used to create the table.
|
||||||
|
*/
|
||||||
|
static const char* createTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the ID of the Entity.
|
||||||
|
*
|
||||||
|
* @return int& Returns the ID.
|
||||||
|
*/
|
||||||
|
int& getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the ID of the Entity.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Entity.
|
||||||
|
*/
|
||||||
|
void setId(int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the name of the Entity.
|
||||||
|
*
|
||||||
|
* @return std::string& The name of the Entity.
|
||||||
|
*/
|
||||||
|
std::string& getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the name of the Entity.
|
||||||
|
*
|
||||||
|
* @param[in] name The name of the Entity.
|
||||||
|
*/
|
||||||
|
void setName(std::string name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select an Entity from the KnowledgeBase based on the
|
||||||
|
* object's name.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void selectByName(sqlite3* dbConnection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Insert an Entity into the KnowledgeBase based on the
|
||||||
|
* object's fields.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void insert(sqlite3* dbConnection);
|
||||||
|
};
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
193
src/lib/models/error.h
Normal file
193
src/lib/models/error.h
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#ifndef OBELISK_MODELS_ERROR_H
|
||||||
|
#define OBELISK_MODELS_ERROR_H
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief Exception thrown by database models.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DatabaseException : public std::exception
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief The error message describing the exception.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::string errorMessage_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DatabaseException() :
|
||||||
|
errorMessage_("an unknown error ocurred")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseException object.
|
||||||
|
*
|
||||||
|
* @param[in] errorCode The error code that came from sqlite.
|
||||||
|
*/
|
||||||
|
DatabaseException(const int errorCode) :
|
||||||
|
errorMessage_(
|
||||||
|
"database error " + std::to_string(errorCode) + " ocurred")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseException object.
|
||||||
|
*
|
||||||
|
* @param[in] errorMessage The error message to describe the
|
||||||
|
* exception.
|
||||||
|
*/
|
||||||
|
DatabaseException(const std::string& errorMessage) :
|
||||||
|
errorMessage_(errorMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retreive the exception message as a C type string.
|
||||||
|
*
|
||||||
|
* @return const char* The error message.
|
||||||
|
*/
|
||||||
|
virtual const char* what() const noexcept
|
||||||
|
{
|
||||||
|
return errorMessage_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the error message.
|
||||||
|
*
|
||||||
|
* @param[in] errorMessage The error message.
|
||||||
|
*/
|
||||||
|
virtual void setErrorMessage(const std::string errorMessage)
|
||||||
|
{
|
||||||
|
errorMessage_ = errorMessage;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exception thrown if the string or blob size exceeds sqlite's
|
||||||
|
* limits.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DatabaseSizeException : public obelisk::DatabaseException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseSizeException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DatabaseSizeException()
|
||||||
|
{
|
||||||
|
setErrorMessage("size of string or blob exceeds limits");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exception thrown if the index used it out of range.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DatabaseRangeException : public obelisk::DatabaseException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseRangeException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DatabaseRangeException()
|
||||||
|
{
|
||||||
|
setErrorMessage("parameter index is out of range");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exception thrown if there is not enough memory to perform the
|
||||||
|
* operation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DatabaseMemoryException : public obelisk::DatabaseException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseMemoryException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DatabaseMemoryException()
|
||||||
|
{
|
||||||
|
setErrorMessage("not enough memory for operation");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exception thrown if the database was busy.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DatabaseBusyException : public obelisk::DatabaseException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseBusyException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DatabaseBusyException()
|
||||||
|
{
|
||||||
|
setErrorMessage(
|
||||||
|
"database was busy and operation was not performed");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exception thrown if there is a misuse of the databse.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DatabaseMisuseException : public obelisk::DatabaseException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseMisuseException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DatabaseMisuseException()
|
||||||
|
|
||||||
|
{
|
||||||
|
setErrorMessage("misuse of the database routine");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exception thrown if a constraint was violated.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class DatabaseConstraintException : public obelisk::DatabaseException
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseConstraintException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DatabaseConstraintException()
|
||||||
|
{
|
||||||
|
setErrorMessage("a constraint exception occurred");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new DatabaseConstraintException object.
|
||||||
|
*
|
||||||
|
* @param[in] errorMessage The error message to send when the
|
||||||
|
* constraint is violated.
|
||||||
|
*/
|
||||||
|
DatabaseConstraintException(const std::string& errorMessage)
|
||||||
|
{
|
||||||
|
setErrorMessage(errorMessage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
600
src/lib/models/fact.cpp
Normal file
600
src/lib/models/fact.cpp
Normal file
@ -0,0 +1,600 @@
|
|||||||
|
#include "models/error.h"
|
||||||
|
#include "models/fact.h"
|
||||||
|
|
||||||
|
const char* obelisk::Fact::createTable()
|
||||||
|
{
|
||||||
|
return R"(
|
||||||
|
CREATE TABLE "fact" (
|
||||||
|
"id" INTEGER NOT NULL UNIQUE,
|
||||||
|
"left_entity" INTEGER NOT NULL,
|
||||||
|
"verb" INTEGER NOT NULL,
|
||||||
|
"right_entity" INTEGER NOT NULL,
|
||||||
|
"is_true" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
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
|
||||||
|
);
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Fact::selectById(sqlite3* dbConnection)
|
||||||
|
{
|
||||||
|
if (dbConnection == nullptr)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException("database isn't open");
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
|
const char* query;
|
||||||
|
if (getId() == 0)
|
||||||
|
{
|
||||||
|
query
|
||||||
|
= "SELECT id, left_entity, right_entity, verb, is_true FROM fact WHERE (left_entity=? AND right_entity=? AND verb=?)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query
|
||||||
|
= "SELECT id, left_entity, right_entity, verb, is_true FROM fact WHERE (id=?)";
|
||||||
|
}
|
||||||
|
auto result = sqlite3_prepare_v2(dbConnection, query, -1, &ppStmt, nullptr);
|
||||||
|
if (result != SQLITE_OK)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getId() == 0)
|
||||||
|
{
|
||||||
|
result = sqlite3_bind_int(ppStmt, 1, getLeftEntity().getId());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = sqlite3_bind_int(ppStmt, 1, getId());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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));
|
||||||
|
setIsTrue(sqlite3_column_int(ppStmt, 4));
|
||||||
|
break;
|
||||||
|
case SQLITE_BUSY :
|
||||||
|
throw obelisk::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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::selectByName(sqlite3* dbConnection)
|
||||||
|
{
|
||||||
|
if (dbConnection == nullptr)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException("database isn't open");
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
|
auto result = sqlite3_prepare_v2(dbConnection,
|
||||||
|
"SELECT fact.id, fact.left_entity, fact.right_entity, fact.verb, fact.is_true FROM fact LEFT JOIN entity le ON le.id = fact.left_entity LEFT JOIN entity re ON re.id = fact.right_entity LEFT JOIN verb v ON fact.verb = v.id WHERE (le.name=? AND v.name=? AND re.name=?)",
|
||||||
|
-1,
|
||||||
|
&ppStmt,
|
||||||
|
nullptr);
|
||||||
|
if (result != SQLITE_OK)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_text(ppStmt,
|
||||||
|
1,
|
||||||
|
getLeftEntity().getName().c_str(),
|
||||||
|
-1,
|
||||||
|
SQLITE_STATIC);
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_text(ppStmt,
|
||||||
|
2,
|
||||||
|
getVerb().getName().c_str(),
|
||||||
|
-1,
|
||||||
|
SQLITE_STATIC);
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_text(ppStmt,
|
||||||
|
3,
|
||||||
|
getRightEntity().getName().c_str(),
|
||||||
|
-1,
|
||||||
|
SQLITE_STATIC);
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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));
|
||||||
|
setIsTrue(sqlite3_column_int(ppStmt, 4));
|
||||||
|
break;
|
||||||
|
case SQLITE_BUSY :
|
||||||
|
throw obelisk::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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::selectActionByFact(sqlite3* dbConnection,
|
||||||
|
obelisk::Action& action)
|
||||||
|
{
|
||||||
|
if (dbConnection == nullptr)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException("database isn't open");
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
|
auto result = sqlite3_prepare_v2(dbConnection,
|
||||||
|
"SELECT CASE f.is_true WHEN 0 THEN (SELECT name FROM action WHERE id = fa.id) WHEN 1 THEN (SELECT name from action WHERE id = ta.id) END action FROM suggest_action LEFT JOIN action ta ON ta.id = suggest_action.true_action LEFT JOIN action fa ON fa.id = suggest_action.false_action LEFT JOIN fact f ON f.id = suggest_action.fact WHERE (f.id = ?)",
|
||||||
|
-1,
|
||||||
|
&ppStmt,
|
||||||
|
nullptr);
|
||||||
|
if (result != SQLITE_OK)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_int(ppStmt, 1, getId());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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 :
|
||||||
|
action.setName((char*) sqlite3_column_text(ppStmt, 0));
|
||||||
|
break;
|
||||||
|
case SQLITE_BUSY :
|
||||||
|
throw obelisk::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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::insert(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, is_true) 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::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_int(ppStmt, 4, getIsTrue());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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::DatabaseConstraintException(
|
||||||
|
sqlite3_errmsg(dbConnection));
|
||||||
|
case SQLITE_BUSY :
|
||||||
|
throw obelisk::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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::updateIsTrue(sqlite3* dbConnection)
|
||||||
|
{
|
||||||
|
if (dbConnection == nullptr)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException("database isn't open");
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
|
auto result = sqlite3_prepare_v2(dbConnection,
|
||||||
|
"UPDATE fact SET is_true=? WHERE id=?",
|
||||||
|
-1,
|
||||||
|
&ppStmt,
|
||||||
|
nullptr);
|
||||||
|
if (result != SQLITE_OK)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_int(ppStmt, 1, getIsTrue());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_int(ppStmt, 2, getId());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_step(ppStmt);
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_DONE :
|
||||||
|
// Row updated
|
||||||
|
break;
|
||||||
|
case SQLITE_CONSTRAINT :
|
||||||
|
throw obelisk::DatabaseConstraintException(
|
||||||
|
sqlite3_errmsg(dbConnection));
|
||||||
|
case SQLITE_BUSY :
|
||||||
|
throw obelisk::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Fact::setId(int id)
|
||||||
|
{
|
||||||
|
id_ = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
obelisk::Entity& obelisk::Fact::getLeftEntity()
|
||||||
|
{
|
||||||
|
return leftEntity_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Fact::setLeftEntity(obelisk::Entity leftEntity)
|
||||||
|
{
|
||||||
|
leftEntity_ = leftEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
obelisk::Entity& obelisk::Fact::getRightEntity()
|
||||||
|
{
|
||||||
|
return rightEntity_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Fact::setRightEntity(obelisk::Entity rightEntity)
|
||||||
|
{
|
||||||
|
rightEntity_ = rightEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
obelisk::Verb& obelisk::Fact::getVerb()
|
||||||
|
{
|
||||||
|
return verb_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Fact::setVerb(obelisk::Verb verb)
|
||||||
|
{
|
||||||
|
verb_ = verb;
|
||||||
|
}
|
||||||
|
|
||||||
|
double& obelisk::Fact::getIsTrue()
|
||||||
|
{
|
||||||
|
return isTrue_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Fact::setIsTrue(double isTrue)
|
||||||
|
{
|
||||||
|
isTrue_ = isTrue;
|
||||||
|
}
|
247
src/lib/models/fact.h
Normal file
247
src/lib/models/fact.h
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
#ifndef OBELISK_MODELS_FACT_H
|
||||||
|
#define OBELISK_MODELS_FACT_H
|
||||||
|
|
||||||
|
#include "models/action.h"
|
||||||
|
#include "models/entity.h"
|
||||||
|
#include "models/fact.h"
|
||||||
|
#include "models/verb.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The Fact model represents truth in the releationship between two
|
||||||
|
* entities separated by a verb.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Fact
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The ID of the Fact in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int id_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Entity from the left side of the expression.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
obelisk::Entity leftEntity_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Entity from the right side of the expression.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
obelisk::Entity rightEntity_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Verb that represents the relationship in the
|
||||||
|
* expression.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
obelisk::Verb verb_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Whether or not the fact is considered true or not.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
double isTrue_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Fact object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Fact() :
|
||||||
|
id_(0),
|
||||||
|
leftEntity_(),
|
||||||
|
rightEntity_(),
|
||||||
|
verb_(),
|
||||||
|
isTrue_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Fact object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Fact in the KnowledgeBase.
|
||||||
|
*/
|
||||||
|
Fact(int id) :
|
||||||
|
id_(id),
|
||||||
|
leftEntity_(),
|
||||||
|
rightEntity_(),
|
||||||
|
verb_(),
|
||||||
|
isTrue_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Fact object.
|
||||||
|
*
|
||||||
|
* @param[in] leftEntity The Entity on the left side of the
|
||||||
|
* expression.
|
||||||
|
* @param[in] rightEntity The Entity on the right side of the
|
||||||
|
* expression.
|
||||||
|
* @param[in] verb The Verb separating the entities.
|
||||||
|
* @param[in] isTrue Whether or not the fact is true.
|
||||||
|
*/
|
||||||
|
Fact(obelisk::Entity leftEntity,
|
||||||
|
obelisk::Entity rightEntity,
|
||||||
|
obelisk::Verb verb,
|
||||||
|
double isTrue = 0) :
|
||||||
|
id_(0),
|
||||||
|
leftEntity_(leftEntity),
|
||||||
|
rightEntity_(rightEntity),
|
||||||
|
verb_(verb),
|
||||||
|
isTrue_(isTrue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Fact object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Fact in the KnowledgeBase.
|
||||||
|
* @param[in] leftEntity The Entity on the left side of the
|
||||||
|
* expression.
|
||||||
|
* @param[in] rightEntity The Entity on the right side of the
|
||||||
|
* expression.
|
||||||
|
* @param[in] verb The Verb separating the entities.
|
||||||
|
* @param[in] isTrue Whether or not the fact is true.
|
||||||
|
*/
|
||||||
|
Fact(int id,
|
||||||
|
obelisk::Entity leftEntity,
|
||||||
|
obelisk::Entity rightEntity,
|
||||||
|
obelisk::Verb verb,
|
||||||
|
double isTrue = 0) :
|
||||||
|
id_(id),
|
||||||
|
leftEntity_(leftEntity),
|
||||||
|
rightEntity_(rightEntity),
|
||||||
|
verb_(verb),
|
||||||
|
isTrue_(isTrue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the Fact table in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @return const char* Returns the query used to create the table.
|
||||||
|
*/
|
||||||
|
static const char* createTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the ID of the Fact
|
||||||
|
*
|
||||||
|
* @return int& Returns the ID.
|
||||||
|
*/
|
||||||
|
int& getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the ID of the Fact.
|
||||||
|
*
|
||||||
|
* @param[in] id Set the ID of the Fact.
|
||||||
|
*/
|
||||||
|
void setId(int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the left Entity object.
|
||||||
|
*
|
||||||
|
* @return Entity& The left Entity.
|
||||||
|
*/
|
||||||
|
Entity& getLeftEntity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the left Entity object.
|
||||||
|
*
|
||||||
|
* @param[in] leftEntity The left Entity to set.
|
||||||
|
*/
|
||||||
|
void setLeftEntity(obelisk::Entity leftEntity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the right Entity object.
|
||||||
|
*
|
||||||
|
* @return Entity& The right Entity.
|
||||||
|
*/
|
||||||
|
Entity& getRightEntity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the right Entity object.
|
||||||
|
*
|
||||||
|
* @param[in] rightEntity The right Entity to set.
|
||||||
|
*/
|
||||||
|
void setRightEntity(obelisk::Entity rightEntity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the Verb object.
|
||||||
|
*
|
||||||
|
* @return Verb& The Verb.
|
||||||
|
*/
|
||||||
|
Verb& getVerb();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Verb object.
|
||||||
|
*
|
||||||
|
* @param[in] verb The Verb.
|
||||||
|
*/
|
||||||
|
void setVerb(obelisk::Verb verb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the isTrue value.
|
||||||
|
*
|
||||||
|
* @return true If the Fact is considered true.
|
||||||
|
* @return false If the Fact is considered false.
|
||||||
|
*/
|
||||||
|
double& getIsTrue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Fact as true or false.
|
||||||
|
*
|
||||||
|
* @param[in] isTrue Whether or not the Fact is true.
|
||||||
|
*/
|
||||||
|
void setIsTrue(double isTrue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select the Fact from the KnowledgeBase by IDs of the
|
||||||
|
* sub-objects.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void selectById(sqlite3* dbConnection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select the Fact from the KnowledgeBase by the name's of
|
||||||
|
* the entities and verb.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void selectByName(sqlite3* dbConnection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select an Action from the KnowledgeBase using the provided
|
||||||
|
* Fact.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
* @param[out] action The Action to take based on the provided fact.
|
||||||
|
*/
|
||||||
|
void selectActionByFact(sqlite3* dbConnection,
|
||||||
|
obelisk::Action& action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Insert the Fact into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void insert(sqlite3* dbConnection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update whether or not the fact is true in the
|
||||||
|
* KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection.
|
||||||
|
*/
|
||||||
|
void updateIsTrue(sqlite3* dbConnection);
|
||||||
|
};
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
286
src/lib/models/rule.cpp
Normal file
286
src/lib/models/rule.cpp
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
#include "models/error.h"
|
||||||
|
#include "models/rule.h"
|
||||||
|
|
||||||
|
const char* obelisk::Rule::createTable()
|
||||||
|
{
|
||||||
|
return R"(
|
||||||
|
CREATE TABLE "rule" (
|
||||||
|
"id" INTEGER NOT NULL UNIQUE,
|
||||||
|
"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
|
||||||
|
);
|
||||||
|
)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Rule::selectById(sqlite3* dbConnection)
|
||||||
|
{
|
||||||
|
if (dbConnection == nullptr)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException("database isn't open");
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
|
auto result = sqlite3_prepare_v2(dbConnection,
|
||||||
|
"SELECT id, fact, reason FROM rule WHERE (fact=? AND reason=?)",
|
||||||
|
-1,
|
||||||
|
&ppStmt,
|
||||||
|
nullptr);
|
||||||
|
if (result != SQLITE_OK)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_int(ppStmt, 1, getFact().getId());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_int(ppStmt, 2, getReason().getId());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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));
|
||||||
|
getFact().setId(sqlite3_column_int(ppStmt, 1));
|
||||||
|
getReason().setId(sqlite3_column_int(ppStmt, 2));
|
||||||
|
break;
|
||||||
|
case SQLITE_BUSY :
|
||||||
|
throw obelisk::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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::Rule::insert(sqlite3* dbConnection)
|
||||||
|
{
|
||||||
|
if (dbConnection == nullptr)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException("database isn't open");
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
|
auto result = sqlite3_prepare_v2(dbConnection,
|
||||||
|
"INSERT INTO rule (fact, reason) VALUES (?, ?)",
|
||||||
|
-1,
|
||||||
|
&ppStmt,
|
||||||
|
nullptr);
|
||||||
|
if (result != SQLITE_OK)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_int(ppStmt, 1, getFact().getId());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_int(ppStmt, 2, getReason().getId());
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
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::DatabaseConstraintException(
|
||||||
|
sqlite3_errmsg(dbConnection));
|
||||||
|
case SQLITE_BUSY :
|
||||||
|
throw obelisk::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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::Rule::selectByReason(sqlite3* dbConnection,
|
||||||
|
int reasonId,
|
||||||
|
std::vector<obelisk::Rule>& rules)
|
||||||
|
{
|
||||||
|
if (dbConnection == nullptr)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException("database isn't open");
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
|
auto result = sqlite3_prepare_v2(dbConnection,
|
||||||
|
"SELECT id, fact, reason FROM rule WHERE (reason=?)",
|
||||||
|
-1,
|
||||||
|
&ppStmt,
|
||||||
|
nullptr);
|
||||||
|
if (result != SQLITE_OK)
|
||||||
|
{
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sqlite3_bind_int(ppStmt, 1, reasonId);
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_OK :
|
||||||
|
break;
|
||||||
|
case SQLITE_TOOBIG :
|
||||||
|
throw obelisk::DatabaseSizeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_RANGE :
|
||||||
|
throw obelisk::DatabaseRangeException();
|
||||||
|
break;
|
||||||
|
case SQLITE_NOMEM :
|
||||||
|
throw obelisk::DatabaseMemoryException();
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((result = sqlite3_step(ppStmt)) != SQLITE_DONE)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case SQLITE_ROW :
|
||||||
|
rules.push_back(obelisk::Rule(sqlite3_column_int(ppStmt, 0),
|
||||||
|
obelisk::Fact(sqlite3_column_int(ppStmt, 1)),
|
||||||
|
obelisk::Fact(sqlite3_column_int(ppStmt, 2))));
|
||||||
|
break;
|
||||||
|
case SQLITE_BUSY :
|
||||||
|
throw obelisk::DatabaseBusyException();
|
||||||
|
break;
|
||||||
|
case SQLITE_MISUSE :
|
||||||
|
throw obelisk::DatabaseMisuseException();
|
||||||
|
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::Rule::getId()
|
||||||
|
{
|
||||||
|
return id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Rule::setId(int id)
|
||||||
|
{
|
||||||
|
id_ = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
obelisk::Fact& obelisk::Rule::getFact()
|
||||||
|
{
|
||||||
|
return fact_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Rule::setFact(obelisk::Fact fact)
|
||||||
|
{
|
||||||
|
fact_ = fact;
|
||||||
|
}
|
||||||
|
|
||||||
|
obelisk::Fact& obelisk::Rule::getReason()
|
||||||
|
{
|
||||||
|
return reason_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk::Rule::setReason(obelisk::Fact reason)
|
||||||
|
{
|
||||||
|
reason_ = reason;
|
||||||
|
}
|
163
src/lib/models/rule.h
Normal file
163
src/lib/models/rule.h
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#ifndef OBELISK_MODELS_RULE_H
|
||||||
|
#define OBELISK_MODELS_RULE_H
|
||||||
|
|
||||||
|
#include "models/fact.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The Rule model represents a truth relation between 2 Facts.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Rule
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The ID of the Rule in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int id_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Fact that depends on the Fact reason being true.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
obelisk::Fact fact_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Fact that makes the other Fact true or false.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
obelisk::Fact reason_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Rule object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Rule() :
|
||||||
|
id_(0),
|
||||||
|
fact_(),
|
||||||
|
reason_()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Rule object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Rule in the KnowledgeBase.
|
||||||
|
*/
|
||||||
|
Rule(int id) :
|
||||||
|
id_(id),
|
||||||
|
fact_(),
|
||||||
|
reason_()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Rule object.
|
||||||
|
*
|
||||||
|
* @param[in] fact The Fact.
|
||||||
|
* @param[in] reason The reason Fact.
|
||||||
|
*/
|
||||||
|
Rule(obelisk::Fact fact, obelisk::Fact reason) :
|
||||||
|
id_(0),
|
||||||
|
fact_(fact),
|
||||||
|
reason_(reason)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Rule object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Rule.
|
||||||
|
* @param[in] fact The Fact.
|
||||||
|
* @param[in] reason The reason Fact.
|
||||||
|
*/
|
||||||
|
Rule(int id, obelisk::Fact fact, obelisk::Fact reason) :
|
||||||
|
id_(id),
|
||||||
|
fact_(fact),
|
||||||
|
reason_(reason)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the Rule table in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @return const char* Returns the query used to create the table.
|
||||||
|
*/
|
||||||
|
static const char* createTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the ID of the Rule.
|
||||||
|
*
|
||||||
|
* @return int& The ID.
|
||||||
|
*/
|
||||||
|
int& getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the ID of the Rule.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID.
|
||||||
|
*/
|
||||||
|
void setId(int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the Fact object.
|
||||||
|
*
|
||||||
|
* @return obelisk::Fact& The Fact.
|
||||||
|
*/
|
||||||
|
obelisk::Fact& getFact();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Fact object.
|
||||||
|
*
|
||||||
|
* @param[in] fact The Fact.
|
||||||
|
*/
|
||||||
|
void setFact(obelisk::Fact fact);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the reason Fact object.
|
||||||
|
*
|
||||||
|
* @return obelisk::Fact& The reason Fact.
|
||||||
|
*/
|
||||||
|
obelisk::Fact& getReason();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the reason Fact object.
|
||||||
|
*
|
||||||
|
* @param[in] reason The reason Fact.
|
||||||
|
*/
|
||||||
|
void setReason(obelisk::Fact reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select the Rule from the KnowledgeBase by IDs of the
|
||||||
|
* sub-objects.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void selectById(sqlite3* dbConnection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the rules that match the reason.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
* @param[out] rules The rules to fill in from the database.
|
||||||
|
*/
|
||||||
|
static void selectByReason(sqlite3* dbConnection,
|
||||||
|
int reasonId,
|
||||||
|
std::vector<obelisk::Rule>& rules);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Insert the Rule into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void insert(sqlite3* dbConnection);
|
||||||
|
};
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
@ -1,24 +1,24 @@
|
|||||||
#include "models/error.h"
|
#include "models/error.h"
|
||||||
#include "models/fact.h"
|
#include "models/suggest_action.h"
|
||||||
|
|
||||||
const char* obelisk::Fact::createTable()
|
const char* obelisk::SuggestAction::createTable()
|
||||||
{
|
{
|
||||||
return R"(
|
return R"(
|
||||||
CREATE TABLE "fact" (
|
CREATE TABLE "suggest_action" (
|
||||||
"id" INTEGER NOT NULL UNIQUE,
|
"id" INTEGER NOT NULL UNIQUE,
|
||||||
"left_entity" INTEGER NOT NULL,
|
"fact" INTEGER NOT NULL,
|
||||||
"right_entity" INTEGER NOT NULL,
|
"true_action" INTEGER NOT NULL,
|
||||||
"verb" INTEGER NOT NULL,
|
"false_action" INTEGER NOT NULL,
|
||||||
PRIMARY KEY("id" AUTOINCREMENT),
|
PRIMARY KEY("id" AUTOINCREMENT),
|
||||||
UNIQUE("left_entity", "right_entity", "verb")
|
UNIQUE("fact", "true_action", "false_action"),
|
||||||
FOREIGN KEY("verb") REFERENCES "verb"("id") ON DELETE RESTRICT,
|
FOREIGN KEY("fact") REFERENCES "fact"("id") ON DELETE RESTRICT,
|
||||||
FOREIGN KEY("right_entity") REFERENCES "entity"("id") ON DELETE RESTRICT,
|
FOREIGN KEY("true_action") REFERENCES "action"("id") ON DELETE RESTRICT,
|
||||||
FOREIGN KEY("left_entity") REFERENCES "entity"("id") ON DELETE RESTRICT
|
FOREIGN KEY("false_action") REFERENCES "action"("id") ON DELETE RESTRICT
|
||||||
);
|
);
|
||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Fact::selectFact(sqlite3* dbConnection)
|
void obelisk::SuggestAction::selectById(sqlite3* dbConnection)
|
||||||
{
|
{
|
||||||
if (dbConnection == nullptr)
|
if (dbConnection == nullptr)
|
||||||
{
|
{
|
||||||
@ -28,7 +28,7 @@ void obelisk::Fact::selectFact(sqlite3* dbConnection)
|
|||||||
sqlite3_stmt* ppStmt = nullptr;
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
auto result = sqlite3_prepare_v2(dbConnection,
|
auto result = sqlite3_prepare_v2(dbConnection,
|
||||||
"SELECT id, left_entity, right_entity, verb FROM fact WHERE (left_entity=? AND right_entity=? AND verb=?)",
|
"SELECT id, fact, true_action, false_action FROM suggest_action WHERE (fact=? AND true_action=? AND false_action=?)",
|
||||||
-1,
|
-1,
|
||||||
&ppStmt,
|
&ppStmt,
|
||||||
nullptr);
|
nullptr);
|
||||||
@ -37,57 +37,57 @@ void obelisk::Fact::selectFact(sqlite3* dbConnection)
|
|||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
}
|
}
|
||||||
|
|
||||||
result = sqlite3_bind_int(ppStmt, 1, getLeftEntity().getId());
|
result = sqlite3_bind_int(ppStmt, 1, getFact().getId());
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = sqlite3_bind_int(ppStmt, 2, getRightEntity().getId());
|
result = sqlite3_bind_int(ppStmt, 2, getTrueAction().getId());
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = sqlite3_bind_int(ppStmt, 3, getVerb().getId());
|
result = sqlite3_bind_int(ppStmt, 3, getFalseAction().getId());
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -102,15 +102,15 @@ void obelisk::Fact::selectFact(sqlite3* dbConnection)
|
|||||||
break;
|
break;
|
||||||
case SQLITE_ROW :
|
case SQLITE_ROW :
|
||||||
setId(sqlite3_column_int(ppStmt, 0));
|
setId(sqlite3_column_int(ppStmt, 0));
|
||||||
getLeftEntity().setId(sqlite3_column_int(ppStmt, 1));
|
getFact().setId(sqlite3_column_int(ppStmt, 1));
|
||||||
getRightEntity().setId(sqlite3_column_int(ppStmt, 2));
|
getTrueAction().setId(sqlite3_column_int(ppStmt, 2));
|
||||||
getVerb().setId(sqlite3_column_int(ppStmt, 3));
|
getFalseAction().setId(sqlite3_column_int(ppStmt, 3));
|
||||||
break;
|
break;
|
||||||
case SQLITE_BUSY :
|
case SQLITE_BUSY :
|
||||||
throw obelisk::DatabaseException::BusyException();
|
throw obelisk::DatabaseBusyException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_MISUSE :
|
case SQLITE_MISUSE :
|
||||||
throw obelisk::DatabaseException::MisuseException();
|
throw obelisk::DatabaseMisuseException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -124,7 +124,7 @@ void obelisk::Fact::selectFact(sqlite3* dbConnection)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Fact::insertFact(sqlite3* dbConnection)
|
void obelisk::SuggestAction::insert(sqlite3* dbConnection)
|
||||||
{
|
{
|
||||||
if (dbConnection == nullptr)
|
if (dbConnection == nullptr)
|
||||||
{
|
{
|
||||||
@ -134,7 +134,7 @@ void obelisk::Fact::insertFact(sqlite3* dbConnection)
|
|||||||
sqlite3_stmt* ppStmt = nullptr;
|
sqlite3_stmt* ppStmt = nullptr;
|
||||||
|
|
||||||
auto result = sqlite3_prepare_v2(dbConnection,
|
auto result = sqlite3_prepare_v2(dbConnection,
|
||||||
"INSERT INTO fact (left_entity, right_entity, verb) VALUES (?, ?, ?)",
|
"INSERT INTO suggest_action (fact, true_action, false_action) VALUES (?, ?, ?)",
|
||||||
-1,
|
-1,
|
||||||
&ppStmt,
|
&ppStmt,
|
||||||
nullptr);
|
nullptr);
|
||||||
@ -143,57 +143,57 @@ void obelisk::Fact::insertFact(sqlite3* dbConnection)
|
|||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
}
|
}
|
||||||
|
|
||||||
result = sqlite3_bind_int(ppStmt, 1, getLeftEntity().getId());
|
result = sqlite3_bind_int(ppStmt, 1, getFact().getId());
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = sqlite3_bind_int(ppStmt, 2, getRightEntity().getId());
|
result = sqlite3_bind_int(ppStmt, 2, getTrueAction().getId());
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = sqlite3_bind_int(ppStmt, 3, getVerb().getId());
|
result = sqlite3_bind_int(ppStmt, 3, getFalseAction().getId());
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -208,13 +208,13 @@ void obelisk::Fact::insertFact(sqlite3* dbConnection)
|
|||||||
sqlite3_set_last_insert_rowid(dbConnection, 0);
|
sqlite3_set_last_insert_rowid(dbConnection, 0);
|
||||||
break;
|
break;
|
||||||
case SQLITE_CONSTRAINT :
|
case SQLITE_CONSTRAINT :
|
||||||
throw obelisk::DatabaseException::ConstraintException(
|
throw obelisk::DatabaseConstraintException(
|
||||||
sqlite3_errmsg(dbConnection));
|
sqlite3_errmsg(dbConnection));
|
||||||
case SQLITE_BUSY :
|
case SQLITE_BUSY :
|
||||||
throw obelisk::DatabaseException::BusyException();
|
throw obelisk::DatabaseBusyException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_MISUSE :
|
case SQLITE_MISUSE :
|
||||||
throw obelisk::DatabaseException::MisuseException();
|
throw obelisk::DatabaseMisuseException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -228,42 +228,42 @@ void obelisk::Fact::insertFact(sqlite3* dbConnection)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int& obelisk::Fact::getId()
|
int& obelisk::SuggestAction::getId()
|
||||||
{
|
{
|
||||||
return id_;
|
return id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Fact::setId(int id)
|
void obelisk::SuggestAction::setId(int id)
|
||||||
{
|
{
|
||||||
id_ = id;
|
id_ = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
obelisk::Entity& obelisk::Fact::getLeftEntity()
|
obelisk::Fact& obelisk::SuggestAction::getFact()
|
||||||
{
|
{
|
||||||
return leftEntity_;
|
return fact_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Fact::setLeftEntity(obelisk::Entity leftEntity)
|
void obelisk::SuggestAction::setFact(obelisk::Fact fact)
|
||||||
{
|
{
|
||||||
leftEntity_ = leftEntity;
|
fact_ = fact;
|
||||||
}
|
}
|
||||||
|
|
||||||
obelisk::Entity& obelisk::Fact::getRightEntity()
|
obelisk::Action& obelisk::SuggestAction::getTrueAction()
|
||||||
{
|
{
|
||||||
return rightEntity_;
|
return trueAction_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Fact::setRightEntity(obelisk::Entity rightEntity)
|
void obelisk::SuggestAction::setTrueAction(obelisk::Action trueAction)
|
||||||
{
|
{
|
||||||
rightEntity_ = rightEntity;
|
trueAction_ = trueAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
obelisk::Verb& obelisk::Fact::getVerb()
|
obelisk::Action& obelisk::SuggestAction::getFalseAction()
|
||||||
{
|
{
|
||||||
return verb_;
|
return falseAction_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Fact::setVerb(obelisk::Verb verb)
|
void obelisk::SuggestAction::setFalseAction(obelisk::Action falseAction)
|
||||||
{
|
{
|
||||||
verb_ = verb;
|
falseAction_ = falseAction;
|
||||||
}
|
}
|
185
src/lib/models/suggest_action.h
Normal file
185
src/lib/models/suggest_action.h
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
#ifndef OBELISK_MODELS_SUGGEST_ACTION_H
|
||||||
|
#define OBELISK_MODELS_SUGGEST_ACTION_H
|
||||||
|
|
||||||
|
#include "models/action.h"
|
||||||
|
#include "models/fact.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The SuggestAction model representas the actions to take depending
|
||||||
|
* on if the Fact is true or false.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class SuggestAction
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The ID of the SuggestAction.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int id_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Fact to check the truth of.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
obelisk::Fact fact_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Action to take if the Fact is true.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
obelisk::Action trueAction_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Action to take if the Fact is false.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
obelisk::Action falseAction_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new SuggestAction object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
SuggestAction() :
|
||||||
|
id_(0),
|
||||||
|
fact_(),
|
||||||
|
trueAction_(),
|
||||||
|
falseAction_()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new SuggestAction object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the SuggestAction in the KnowledgeBase.
|
||||||
|
*/
|
||||||
|
SuggestAction(int id) :
|
||||||
|
id_(id),
|
||||||
|
fact_(),
|
||||||
|
trueAction_(),
|
||||||
|
falseAction_()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new SuggestAction object.
|
||||||
|
*
|
||||||
|
* @param[in] fact The Fact.
|
||||||
|
* @param[in] trueAction The true Action.
|
||||||
|
* @param[in] falseAction The false Action.
|
||||||
|
*/
|
||||||
|
SuggestAction(obelisk::Fact fact,
|
||||||
|
obelisk::Action trueAction,
|
||||||
|
obelisk::Action falseAction) :
|
||||||
|
id_(0),
|
||||||
|
fact_(fact),
|
||||||
|
trueAction_(trueAction),
|
||||||
|
falseAction_(falseAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new SuggestAction object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the SuggestAction in the KnowledgeBase.
|
||||||
|
* @param[in] fact The Fact.
|
||||||
|
* @param[in] trueAction The true Action.
|
||||||
|
* @param[in] falseAction The false Action.
|
||||||
|
*/
|
||||||
|
SuggestAction(int id,
|
||||||
|
obelisk::Fact fact,
|
||||||
|
obelisk::Action trueAction,
|
||||||
|
obelisk::Action falseAction) :
|
||||||
|
id_(id),
|
||||||
|
fact_(fact),
|
||||||
|
trueAction_(trueAction),
|
||||||
|
falseAction_(falseAction)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the SuggestAction table in the database.
|
||||||
|
*
|
||||||
|
* @return const char* Returns the query used to create the table.
|
||||||
|
*/
|
||||||
|
static const char* createTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the ID of the SuggestAction.
|
||||||
|
*
|
||||||
|
* @return int& Returns the ID.
|
||||||
|
*/
|
||||||
|
int& getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the ID of the SuggestAction.
|
||||||
|
*
|
||||||
|
* @param[in] id The new ID.
|
||||||
|
*/
|
||||||
|
void setId(int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the Fact object.
|
||||||
|
*
|
||||||
|
* @return obelisk::Fact& Returns the Fact.
|
||||||
|
*/
|
||||||
|
obelisk::Fact& getFact();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Fact object.
|
||||||
|
*
|
||||||
|
* @param[in] fact The new Fact.
|
||||||
|
*/
|
||||||
|
void setFact(obelisk::Fact fact);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the true Action object.
|
||||||
|
*
|
||||||
|
* @return obelisk::Action& Returns the true Action.
|
||||||
|
*/
|
||||||
|
obelisk::Action& getTrueAction();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the true Action object.
|
||||||
|
*
|
||||||
|
* @param[in] trueAction The new true Action.
|
||||||
|
*/
|
||||||
|
void setTrueAction(obelisk::Action trueAction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the false Action object.
|
||||||
|
*
|
||||||
|
* @return obelisk::Action& Returns the false Action.
|
||||||
|
*/
|
||||||
|
obelisk::Action& getFalseAction();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the false Action object.
|
||||||
|
*
|
||||||
|
* @param[in] falseAction The new false Action.
|
||||||
|
*/
|
||||||
|
void setFalseAction(obelisk::Action falseAction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select the SuggestAction from the KnowledgeBase by IDs of
|
||||||
|
* the sub-objects.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void selectById(sqlite3* dbConnection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Insert the SuggestAction into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void insert(sqlite3* dbConnection);
|
||||||
|
};
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
@ -14,7 +14,7 @@ const char* obelisk::Verb::createTable()
|
|||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Verb::selectVerb(sqlite3* dbConnection)
|
void obelisk::Verb::selectByName(sqlite3* dbConnection)
|
||||||
{
|
{
|
||||||
if (dbConnection == nullptr)
|
if (dbConnection == nullptr)
|
||||||
{
|
{
|
||||||
@ -39,13 +39,13 @@ void obelisk::Verb::selectVerb(sqlite3* dbConnection)
|
|||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -63,10 +63,10 @@ void obelisk::Verb::selectVerb(sqlite3* dbConnection)
|
|||||||
setName((char*) sqlite3_column_text(ppStmt, 1));
|
setName((char*) sqlite3_column_text(ppStmt, 1));
|
||||||
break;
|
break;
|
||||||
case SQLITE_BUSY :
|
case SQLITE_BUSY :
|
||||||
throw obelisk::DatabaseException::BusyException();
|
throw obelisk::DatabaseBusyException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_MISUSE :
|
case SQLITE_MISUSE :
|
||||||
throw obelisk::DatabaseException::MisuseException();
|
throw obelisk::DatabaseMisuseException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -80,7 +80,7 @@ void obelisk::Verb::selectVerb(sqlite3* dbConnection)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Verb::insertVerb(sqlite3* dbConnection)
|
void obelisk::Verb::insert(sqlite3* dbConnection)
|
||||||
{
|
{
|
||||||
if (dbConnection == nullptr)
|
if (dbConnection == nullptr)
|
||||||
{
|
{
|
||||||
@ -106,13 +106,13 @@ void obelisk::Verb::insertVerb(sqlite3* dbConnection)
|
|||||||
case SQLITE_OK :
|
case SQLITE_OK :
|
||||||
break;
|
break;
|
||||||
case SQLITE_TOOBIG :
|
case SQLITE_TOOBIG :
|
||||||
throw obelisk::DatabaseException::SizeException();
|
throw obelisk::DatabaseSizeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_RANGE :
|
case SQLITE_RANGE :
|
||||||
throw obelisk::DatabaseException::RangeException();
|
throw obelisk::DatabaseRangeException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_NOMEM :
|
case SQLITE_NOMEM :
|
||||||
throw obelisk::DatabaseException::MemoryException();
|
throw obelisk::DatabaseMemoryException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
||||||
@ -127,13 +127,13 @@ void obelisk::Verb::insertVerb(sqlite3* dbConnection)
|
|||||||
sqlite3_set_last_insert_rowid(dbConnection, 0);
|
sqlite3_set_last_insert_rowid(dbConnection, 0);
|
||||||
break;
|
break;
|
||||||
case SQLITE_CONSTRAINT :
|
case SQLITE_CONSTRAINT :
|
||||||
throw obelisk::DatabaseException::ConstraintException(
|
throw obelisk::DatabaseConstraintException(
|
||||||
sqlite3_errmsg(dbConnection));
|
sqlite3_errmsg(dbConnection));
|
||||||
case SQLITE_BUSY :
|
case SQLITE_BUSY :
|
||||||
throw obelisk::DatabaseException::BusyException();
|
throw obelisk::DatabaseBusyException();
|
||||||
break;
|
break;
|
||||||
case SQLITE_MISUSE :
|
case SQLITE_MISUSE :
|
||||||
throw obelisk::DatabaseException::MisuseException();
|
throw obelisk::DatabaseMisuseException();
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
|
126
src/lib/models/verb.h
Normal file
126
src/lib/models/verb.h
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#ifndef OBELISK_MODELS_VERB_H
|
||||||
|
#define OBELISK_MODELS_VERB_H
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The Verb model represents a verb which is used to connnect
|
||||||
|
* entities.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Verb
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The ID of the Verb in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int id_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The name of the Verb.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::string name_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Verb object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Verb() :
|
||||||
|
id_(0),
|
||||||
|
name_("")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Verb object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Verb.
|
||||||
|
*/
|
||||||
|
Verb(int id) :
|
||||||
|
id_(id),
|
||||||
|
name_("")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Verb object.
|
||||||
|
*
|
||||||
|
* @param[in] name The name of the Verb.
|
||||||
|
*/
|
||||||
|
Verb(std::string name) :
|
||||||
|
id_(0),
|
||||||
|
name_(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Verb object.
|
||||||
|
*
|
||||||
|
* @param[in] id The ID of the Verb.
|
||||||
|
* @param[in] name The name of the Verb.
|
||||||
|
*/
|
||||||
|
Verb(int id, std::string name) :
|
||||||
|
id_(id),
|
||||||
|
name_(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create the Verb table in the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @return const char* Returns the query used to create the table.
|
||||||
|
*/
|
||||||
|
static const char* createTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the ID of the Verb.
|
||||||
|
*
|
||||||
|
* @return int& Returns the ID.
|
||||||
|
*/
|
||||||
|
int& getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the ID of the Verb.
|
||||||
|
*
|
||||||
|
* @param[in] id Set the ID of the Verb.
|
||||||
|
*/
|
||||||
|
void setId(int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the name of the Verb.
|
||||||
|
*
|
||||||
|
* @return std::string& The Verb name.
|
||||||
|
*/
|
||||||
|
std::string& getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the name of the Verb.
|
||||||
|
*
|
||||||
|
* @param[in] name The Verb name.
|
||||||
|
*/
|
||||||
|
void setName(std::string name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Select a verb by name from the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void selectByName(sqlite3* dbConnection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Insert a new verb into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] dbConnection The database connection to use.
|
||||||
|
*/
|
||||||
|
void insert(sqlite3* dbConnection);
|
||||||
|
};
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
41
src/lib/obelisk.c
Normal file
41
src/lib/obelisk.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "obelisk_c.h"
|
||||||
|
#include "obelisk_wrapper.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
CObelisk* obelisk_open(const char* filename)
|
||||||
|
{
|
||||||
|
return create_obelisk(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void obelisk_close(CObelisk* obelisk)
|
||||||
|
{
|
||||||
|
destroy_obelisk(obelisk);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* obelisk_get_version(CObelisk* obelisk)
|
||||||
|
{
|
||||||
|
return call_obelisk_getVersion(obelisk);
|
||||||
|
}
|
||||||
|
|
||||||
|
int obelisk_get_lib_version(CObelisk* obelisk)
|
||||||
|
{
|
||||||
|
return call_obelisk_getLibVersion(obelisk);
|
||||||
|
}
|
||||||
|
|
||||||
|
double obelisk_query(CObelisk* obelisk,
|
||||||
|
const char* left_entity,
|
||||||
|
const char* verb,
|
||||||
|
const char* right_entity)
|
||||||
|
{
|
||||||
|
return call_obelisk_query(obelisk, left_entity, verb, right_entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* obelisk_query_action(CObelisk* obelisk,
|
||||||
|
const char* left_entity,
|
||||||
|
const char* verb,
|
||||||
|
const char* right_entity)
|
||||||
|
{
|
||||||
|
return call_obelisk_queryAction(obelisk, left_entity, verb, right_entity);
|
||||||
|
}
|
47
src/lib/obelisk.cpp
Normal file
47
src/lib/obelisk.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "include/obelisk.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
obelisk::Obelisk::Obelisk(std::string filename)
|
||||||
|
{
|
||||||
|
kb_ = std::unique_ptr<obelisk::KnowledgeBase> {
|
||||||
|
new obelisk::KnowledgeBase(filename.c_str())};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string obelisk::Obelisk::getVersion()
|
||||||
|
{
|
||||||
|
return obelisk::version;
|
||||||
|
}
|
||||||
|
|
||||||
|
int obelisk::Obelisk::getLibVersion()
|
||||||
|
{
|
||||||
|
return obelisk::soVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
double obelisk::Obelisk::query(const std::string& leftEntity,
|
||||||
|
const std::string& verb,
|
||||||
|
const std::string& rightEntity)
|
||||||
|
{
|
||||||
|
obelisk::Fact fact = obelisk::Fact(obelisk::Entity(leftEntity),
|
||||||
|
obelisk::Entity(rightEntity),
|
||||||
|
obelisk::Verb(verb));
|
||||||
|
|
||||||
|
kb_->queryFact(fact);
|
||||||
|
|
||||||
|
return fact.getIsTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string obelisk::Obelisk::queryAction(const std::string& leftEntity,
|
||||||
|
const std::string& verb,
|
||||||
|
const std::string& rightEntity)
|
||||||
|
{
|
||||||
|
obelisk::Fact fact = obelisk::Fact(obelisk::Entity(leftEntity),
|
||||||
|
obelisk::Entity(rightEntity),
|
||||||
|
obelisk::Verb(verb));
|
||||||
|
|
||||||
|
kb_->queryFact(fact);
|
||||||
|
|
||||||
|
obelisk::Action action;
|
||||||
|
kb_->querySuggestAction(fact, action);
|
||||||
|
|
||||||
|
return action.getName();
|
||||||
|
}
|
61
src/lib/obelisk_wrapper.cpp
Normal file
61
src/lib/obelisk_wrapper.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "obelisk.h"
|
||||||
|
#include "obelisk_wrapper.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
CObelisk* create_obelisk(const char* filename)
|
||||||
|
{
|
||||||
|
obelisk::Obelisk* obelisk = new obelisk::Obelisk(filename);
|
||||||
|
return reinterpret_cast<CObelisk*>(obelisk);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* call_obelisk_getVersion(CObelisk* p_obelisk)
|
||||||
|
{
|
||||||
|
obelisk::Obelisk* obelisk
|
||||||
|
= reinterpret_cast<obelisk::Obelisk*>(p_obelisk);
|
||||||
|
auto version = strdup(obelisk->getVersion().c_str());
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
int call_obelisk_getLibVersion(CObelisk* p_obelisk)
|
||||||
|
{
|
||||||
|
obelisk::Obelisk* obelisk
|
||||||
|
= reinterpret_cast<obelisk::Obelisk*>(p_obelisk);
|
||||||
|
return obelisk->getLibVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
double call_obelisk_query(CObelisk* p_obelisk,
|
||||||
|
const char* left_entity,
|
||||||
|
const char* verb,
|
||||||
|
const char* right_entity)
|
||||||
|
{
|
||||||
|
obelisk::Obelisk* obelisk
|
||||||
|
= reinterpret_cast<obelisk::Obelisk*>(p_obelisk);
|
||||||
|
return obelisk->query(std::string(left_entity),
|
||||||
|
std::string(verb),
|
||||||
|
std::string(right_entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
char* call_obelisk_queryAction(CObelisk* p_obelisk,
|
||||||
|
const char* left_entity,
|
||||||
|
const char* verb,
|
||||||
|
const char* right_entity)
|
||||||
|
{
|
||||||
|
obelisk::Obelisk* obelisk
|
||||||
|
= reinterpret_cast<obelisk::Obelisk*>(p_obelisk);
|
||||||
|
auto temp = obelisk->queryAction(std::string(left_entity),
|
||||||
|
std::string(verb),
|
||||||
|
std::string(right_entity));
|
||||||
|
auto action = strdup(temp.c_str());
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_obelisk(CObelisk* p_obelisk)
|
||||||
|
{
|
||||||
|
obelisk::Obelisk* obelisk
|
||||||
|
= reinterpret_cast<obelisk::Obelisk*>(p_obelisk);
|
||||||
|
delete obelisk;
|
||||||
|
}
|
||||||
|
};
|
76
src/lib/obelisk_wrapper.h
Normal file
76
src/lib/obelisk_wrapper.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#ifndef OBELISK_INCLUDE_OBELISK_WRAPPER_H
|
||||||
|
#define OBELISK_INCLUDE_OBELISK_WRAPPER_H
|
||||||
|
|
||||||
|
#include "include/obelisk_c.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a obelisk object.
|
||||||
|
*
|
||||||
|
* @param[in] filename The name of the obelisk KnowledgeBase file to use.
|
||||||
|
* @return CObelisk* Returns the obelisk object.
|
||||||
|
*/
|
||||||
|
CObelisk *create_obelisk(const char *filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calls the obelisk method getVersion.
|
||||||
|
*
|
||||||
|
* @param[in] p_obelisk The obelisk object pointer.
|
||||||
|
* @return char* Returns the version. This must be freed by the
|
||||||
|
* caller.
|
||||||
|
*/
|
||||||
|
char *call_obelisk_getVersion(CObelisk *p_obelisk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calls the obelisk method getLibVersion.
|
||||||
|
*
|
||||||
|
* @param[in] p_obelisk The obelisk object pointer.
|
||||||
|
* @return int Returns the library so version.
|
||||||
|
*/
|
||||||
|
int call_obelisk_getLibVersion(CObelisk *p_obelisk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calls the obelisk method query.
|
||||||
|
*
|
||||||
|
* @param[in] p_obelisk The obelisk object pointer.
|
||||||
|
* @param[in] left_entity The left entity.
|
||||||
|
* @param[in] verb The verb.
|
||||||
|
* @param[in] right_entity The right entity.
|
||||||
|
* @return double Returns whether or not the Fact is true.
|
||||||
|
*/
|
||||||
|
double call_obelisk_query(CObelisk *p_obelisk,
|
||||||
|
const char *left_entity,
|
||||||
|
const char *verb,
|
||||||
|
const char *right_entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calls the obelisk method queryAction.
|
||||||
|
*
|
||||||
|
* @param[in] p_obelisk The obelisk object pointer.
|
||||||
|
* @param[in] left_entity The left entity.
|
||||||
|
* @param[in] verb The verb.
|
||||||
|
* @param[in] right_entity The right entity.
|
||||||
|
* @return char* Returns the sugggested action to take or an empty string if
|
||||||
|
* no action is found. This must be freed by the caller.
|
||||||
|
*/
|
||||||
|
char *call_obelisk_queryAction(CObelisk *p_obelisk,
|
||||||
|
const char *left_entity,
|
||||||
|
const char *verb,
|
||||||
|
const char *right_entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete a obelisk object.
|
||||||
|
*
|
||||||
|
* @param[in] p_obelisk The obelisk object pointer.
|
||||||
|
*/
|
||||||
|
void destroy_obelisk(CObelisk *p_obelisk);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
21
src/lib/version.h.in
Normal file
21
src/lib/version.h.in
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef OBELISK_VERSION_H
|
||||||
|
#define OBELISK_VERSION_H
|
||||||
|
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The current version of obelisk.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const std::string version = "@version@";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The current library version of obelisk.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// clang-format off
|
||||||
|
const int soVersion = @so_version@;
|
||||||
|
// clang-format on
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
190
src/main.cpp
Normal file
190
src/main.cpp
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
#include "knowledge_base.h"
|
||||||
|
#include "lexer.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "obelisk.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
int obelisk::mainLoop(const std::vector<std::string>& sourceFiles,
|
||||||
|
const std::string& kbFile)
|
||||||
|
{
|
||||||
|
std::unique_ptr<obelisk::KnowledgeBase> kb;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
kb = std::unique_ptr<obelisk::KnowledgeBase> {
|
||||||
|
new obelisk::KnowledgeBase(kbFile.c_str())};
|
||||||
|
}
|
||||||
|
catch (obelisk::KnowledgeBaseException& exception)
|
||||||
|
{
|
||||||
|
std::cout << exception.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t file = 0;
|
||||||
|
std::shared_ptr<obelisk::Lexer> lexer;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lexer = std::shared_ptr<obelisk::Lexer> {
|
||||||
|
new obelisk::Lexer(sourceFiles[file++])};
|
||||||
|
}
|
||||||
|
catch (obelisk::LexerException& exception)
|
||||||
|
{
|
||||||
|
std::cout << exception.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
auto parser = std::unique_ptr<obelisk::Parser> {new obelisk::Parser(lexer)};
|
||||||
|
|
||||||
|
// prime the first token
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parser->getNextToken();
|
||||||
|
}
|
||||||
|
catch (obelisk::LexerException& exception)
|
||||||
|
{
|
||||||
|
std::cout << "Error: " << exception.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
switch (parser->getCurrentToken())
|
||||||
|
{
|
||||||
|
case obelisk::Lexer::kTokenEof :
|
||||||
|
// end of source file found, create a new lexer and pass it to
|
||||||
|
// the parser to use
|
||||||
|
if (file >= sourceFiles.size())
|
||||||
|
{
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lexer = std::shared_ptr<obelisk::Lexer> {
|
||||||
|
new obelisk::Lexer(sourceFiles[file++])};
|
||||||
|
parser->setLexer(lexer);
|
||||||
|
// prime the first token in the parser
|
||||||
|
parser->getNextToken();
|
||||||
|
}
|
||||||
|
catch (obelisk::LexerException& exception)
|
||||||
|
{
|
||||||
|
std::cout << exception.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ';' :
|
||||||
|
// semicolon found, the end of a statement
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parser->getNextToken();
|
||||||
|
}
|
||||||
|
catch (obelisk::LexerException& exception)
|
||||||
|
{
|
||||||
|
std::cout << "Error: " << exception.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case obelisk::Lexer::kTokenFact :
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parser->handleFact(kb);
|
||||||
|
}
|
||||||
|
catch (obelisk::ParserException& exception)
|
||||||
|
{
|
||||||
|
std::cout << "Error: " << exception.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case obelisk::Lexer::kTokenRule :
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parser->handleRule(kb);
|
||||||
|
}
|
||||||
|
catch (obelisk::ParserException& exception)
|
||||||
|
{
|
||||||
|
std::cout << "Error: " << exception.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case obelisk::Lexer::kTokenAction :
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parser->handleAction(kb);
|
||||||
|
}
|
||||||
|
catch (obelisk::ParserException& exception)
|
||||||
|
{
|
||||||
|
std::cout << "Error: " << exception.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
parser->getNextToken();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void obelisk::showUsage()
|
||||||
|
{
|
||||||
|
std::cout << obelisk::usageMessage << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
std::vector<std::string> sourceFiles;
|
||||||
|
std::string kbFile = "obelisk.kb";
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int option_index = 0;
|
||||||
|
switch (getopt_long(argc,
|
||||||
|
argv,
|
||||||
|
"k:hv",
|
||||||
|
obelisk::long_options,
|
||||||
|
&option_index))
|
||||||
|
{
|
||||||
|
case 'k' :
|
||||||
|
kbFile = std::string(optarg);
|
||||||
|
continue;
|
||||||
|
case 'h' :
|
||||||
|
obelisk::showUsage();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
break;
|
||||||
|
case 'v' :
|
||||||
|
std::cout << "obelisk " << obelisk::version << std::endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
obelisk::showUsage();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case -1 :
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc)
|
||||||
|
{
|
||||||
|
while (optind < argc)
|
||||||
|
{
|
||||||
|
sourceFiles.push_back(argv[optind++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceFiles.size() == 0)
|
||||||
|
{
|
||||||
|
obelisk::showUsage();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obelisk::mainLoop(sourceFiles, kbFile);
|
||||||
|
}
|
53
src/main.h
Normal file
53
src/main.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef OBELISK_MAIN_H
|
||||||
|
#define OBELISK_MAIN_H
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The obelisk namespace contains everything needed to compile obelisk
|
||||||
|
* code.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace obelisk
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief The usage messsage displayed during help or incorrect usage.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::string usageMessage = R"(Usage: obelisk [OPTION]... [FILE]...
|
||||||
|
Compile the obelisk source FILE(s) into knoweldge base and library.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help shows this help/usage message
|
||||||
|
-k, --kb=FILENAME output knowldege base filename
|
||||||
|
-v, --version shows the version of obelisk)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The command line arguments that obelisk accepts.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
|
{"kb", required_argument, 0, 'k'},
|
||||||
|
{"version", no_argument, 0, 'v'},
|
||||||
|
{0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints out the usage of obelisk to the stdin.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void showUsage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This is the main loop for obelisk.
|
||||||
|
*
|
||||||
|
* This loop handles lexing and parsing of obelisk source code.
|
||||||
|
*
|
||||||
|
* @return int Returns EXIT_SUCCESS or EXIT_FAILURE.
|
||||||
|
*/
|
||||||
|
int mainLoop(const std::vector<std::string> &sourceFiles,
|
||||||
|
const std::string &kbFile);
|
||||||
|
} // namespace obelisk
|
||||||
|
|
||||||
|
#endif
|
@ -1,8 +1,9 @@
|
|||||||
|
subdir('lib')
|
||||||
|
|
||||||
obelisk_sources = files(
|
obelisk_sources = files(
|
||||||
'obelisk.cpp',
|
'main.cpp',
|
||||||
'lexer.cpp',
|
'lexer.cpp',
|
||||||
'parser.cpp',
|
'parser.cpp'
|
||||||
'knowledge_base.cpp'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
sqlite3 = dependency('sqlite3')
|
sqlite3 = dependency('sqlite3')
|
||||||
@ -10,9 +11,6 @@ sqlite3 = dependency('sqlite3')
|
|||||||
subdir('ast')
|
subdir('ast')
|
||||||
obelisk_sources += obelisk_ast_sources
|
obelisk_sources += obelisk_ast_sources
|
||||||
|
|
||||||
subdir('models')
|
|
||||||
obelisk_sources += obelisk_model_sources
|
|
||||||
|
|
||||||
r = run_command('llvm-config', '--cppflags', check : true)
|
r = run_command('llvm-config', '--cppflags', check : true)
|
||||||
cpp_args = ' ' + r.stdout().replace('\n', ' ').replace('-I', '-isystem')
|
cpp_args = ' ' + r.stdout().replace('\n', ' ').replace('-I', '-isystem')
|
||||||
|
|
||||||
@ -21,7 +19,7 @@ link_args = ' ' + r.stdout().replace('\n', ' ')
|
|||||||
|
|
||||||
executable('obelisk',
|
executable('obelisk',
|
||||||
obelisk_sources,
|
obelisk_sources,
|
||||||
dependencies : [sqlite3],
|
dependencies : [libobelisk, sqlite3],
|
||||||
cpp_args : cpp_args.split(),
|
cpp_args : cpp_args.split(),
|
||||||
link_args : link_args.split(),
|
link_args : link_args.split(),
|
||||||
install : true
|
install : true
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
#include "models/action.h"
|
|
||||||
|
|
||||||
const char* obelisk::Action::createTable()
|
|
||||||
{
|
|
||||||
return R"(
|
|
||||||
CREATE TABLE "action" (
|
|
||||||
"id" INTEGER NOT NULL UNIQUE,
|
|
||||||
"name" TEXT NOT NULL CHECK(trim(name) != '') UNIQUE,
|
|
||||||
PRIMARY KEY("id" AUTOINCREMENT)
|
|
||||||
);
|
|
||||||
)";
|
|
||||||
}
|
|
||||||
|
|
||||||
int& obelisk::Action::getId()
|
|
||||||
{
|
|
||||||
return id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void obelisk::Action::setId(int id)
|
|
||||||
{
|
|
||||||
id_ = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string& obelisk::Action::getName()
|
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void obelisk::Action::setName(std::string name)
|
|
||||||
{
|
|
||||||
name_ = name;
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
#ifndef OBELISK_MODELS_ACTION_H
|
|
||||||
#define OBELISK_MODELS_ACTION_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace obelisk
|
|
||||||
{
|
|
||||||
class Action
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int id_;
|
|
||||||
std::string name_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Action() :
|
|
||||||
id_(0),
|
|
||||||
name_("")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Action(int id) :
|
|
||||||
id_(id),
|
|
||||||
name_("")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Action(std::string name) :
|
|
||||||
id_(0),
|
|
||||||
name_(name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Action(int id, std::string name) :
|
|
||||||
id_(id),
|
|
||||||
name_(name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* createTable();
|
|
||||||
|
|
||||||
int& getId();
|
|
||||||
void setId(int id);
|
|
||||||
|
|
||||||
std::string& getName();
|
|
||||||
void setName(std::string name);
|
|
||||||
};
|
|
||||||
} // namespace obelisk
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,54 +0,0 @@
|
|||||||
#ifndef OBELISK_MODELS_ENTITY_H
|
|
||||||
#define OBELISK_MODELS_ENTITY_H
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace obelisk
|
|
||||||
{
|
|
||||||
class Entity
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int id_;
|
|
||||||
std::string name_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Entity() :
|
|
||||||
id_(0),
|
|
||||||
name_("")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity(int id) :
|
|
||||||
id_(id),
|
|
||||||
name_("")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity(std::string name) :
|
|
||||||
id_(0),
|
|
||||||
name_(name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity(int id, std::string name) :
|
|
||||||
id_(id),
|
|
||||||
name_(name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* createTable();
|
|
||||||
|
|
||||||
int& getId();
|
|
||||||
void setId(int id);
|
|
||||||
|
|
||||||
std::string& getName();
|
|
||||||
void setName(std::string name);
|
|
||||||
|
|
||||||
void selectEntity(sqlite3* dbConnection);
|
|
||||||
void insertEntity(sqlite3* dbConnection);
|
|
||||||
};
|
|
||||||
} // namespace obelisk
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,146 +0,0 @@
|
|||||||
#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,77 +0,0 @@
|
|||||||
#ifndef OBELISK_MODELS_FACT_H
|
|
||||||
#define OBELISK_MODELS_FACT_H
|
|
||||||
|
|
||||||
#include "models/entity.h"
|
|
||||||
#include "models/fact.h"
|
|
||||||
#include "models/verb.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace obelisk
|
|
||||||
{
|
|
||||||
class Fact
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int id_;
|
|
||||||
obelisk::Entity leftEntity_;
|
|
||||||
obelisk::Entity rightEntity_;
|
|
||||||
obelisk::Verb verb_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Fact() :
|
|
||||||
id_(0),
|
|
||||||
leftEntity_(),
|
|
||||||
rightEntity_(),
|
|
||||||
verb_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Fact(int id) :
|
|
||||||
id_(id),
|
|
||||||
leftEntity_(),
|
|
||||||
rightEntity_(),
|
|
||||||
verb_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Fact(obelisk::Entity leftEntity,
|
|
||||||
obelisk::Entity rightEntity,
|
|
||||||
obelisk::Verb verb) :
|
|
||||||
id_(0),
|
|
||||||
leftEntity_(leftEntity),
|
|
||||||
rightEntity_(rightEntity),
|
|
||||||
verb_(verb)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Fact(int id,
|
|
||||||
obelisk::Entity leftEntity,
|
|
||||||
obelisk::Entity rightEntity,
|
|
||||||
obelisk::Verb verb) :
|
|
||||||
id_(id),
|
|
||||||
leftEntity_(leftEntity),
|
|
||||||
rightEntity_(rightEntity),
|
|
||||||
verb_(verb)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* createTable();
|
|
||||||
|
|
||||||
int& getId();
|
|
||||||
void setId(int id);
|
|
||||||
|
|
||||||
Entity& getLeftEntity();
|
|
||||||
void setLeftEntity(obelisk::Entity leftEntity);
|
|
||||||
|
|
||||||
Entity& getRightEntity();
|
|
||||||
void setRightEntity(obelisk::Entity leftEntity);
|
|
||||||
|
|
||||||
Verb& getVerb();
|
|
||||||
void setVerb(obelisk::Verb verb);
|
|
||||||
|
|
||||||
void selectFact(sqlite3* dbConnection);
|
|
||||||
void insertFact(sqlite3* dbConnection);
|
|
||||||
};
|
|
||||||
} // namespace obelisk
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,46 +0,0 @@
|
|||||||
#include "models/rule.h"
|
|
||||||
|
|
||||||
const char* obelisk::Rule::createTable()
|
|
||||||
{
|
|
||||||
return R"(
|
|
||||||
CREATE TABLE "rule" (
|
|
||||||
"id" INTEGER NOT NULL UNIQUE,
|
|
||||||
"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()
|
|
||||||
{
|
|
||||||
return id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void obelisk::Rule::setId(int id)
|
|
||||||
{
|
|
||||||
id_ = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
obelisk::Fact& obelisk::Rule::getFact()
|
|
||||||
{
|
|
||||||
return fact_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void obelisk::Rule::setFact(obelisk::Fact fact)
|
|
||||||
{
|
|
||||||
fact_ = fact;
|
|
||||||
}
|
|
||||||
|
|
||||||
obelisk::Fact& obelisk::Rule::getReason()
|
|
||||||
{
|
|
||||||
return reason_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void obelisk::Rule::setReason(obelisk::Fact reason)
|
|
||||||
{
|
|
||||||
reason_ = reason;
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
#ifndef OBELISK_MODELS_RULE_H
|
|
||||||
#define OBELISK_MODELS_RULE_H
|
|
||||||
|
|
||||||
#include "models/fact.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace obelisk
|
|
||||||
{
|
|
||||||
class Rule
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int id_;
|
|
||||||
obelisk::Fact fact_;
|
|
||||||
obelisk::Fact reason_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Rule() :
|
|
||||||
id_(0),
|
|
||||||
fact_(),
|
|
||||||
reason_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Rule(int id) :
|
|
||||||
id_(id),
|
|
||||||
fact_(),
|
|
||||||
reason_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Rule(obelisk::Fact fact, obelisk::Fact reason) :
|
|
||||||
id_(0),
|
|
||||||
fact_(fact),
|
|
||||||
reason_(reason)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Rule(int id, obelisk::Fact fact, obelisk::Fact reason) :
|
|
||||||
id_(id),
|
|
||||||
fact_(fact),
|
|
||||||
reason_(reason)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* createTable();
|
|
||||||
|
|
||||||
int& getId();
|
|
||||||
void setId(int id);
|
|
||||||
|
|
||||||
obelisk::Fact& getFact();
|
|
||||||
void setFact(obelisk::Fact fact);
|
|
||||||
|
|
||||||
obelisk::Fact& getReason();
|
|
||||||
void setReason(obelisk::Fact reason);
|
|
||||||
};
|
|
||||||
} // namespace obelisk
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,58 +0,0 @@
|
|||||||
#include "models/suggest_action.h"
|
|
||||||
|
|
||||||
const char* obelisk::SuggestAction::createTable()
|
|
||||||
{
|
|
||||||
return R"(
|
|
||||||
CREATE TABLE "suggest_action" (
|
|
||||||
"id" INTEGER NOT NULL UNIQUE,
|
|
||||||
"fact" INTEGER NOT NULL,
|
|
||||||
"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
|
|
||||||
);
|
|
||||||
)";
|
|
||||||
}
|
|
||||||
|
|
||||||
int& obelisk::SuggestAction::getId()
|
|
||||||
{
|
|
||||||
return id_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void obelisk::SuggestAction::setId(int id)
|
|
||||||
{
|
|
||||||
id_ = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
obelisk::Fact& obelisk::SuggestAction::getFact()
|
|
||||||
{
|
|
||||||
return fact_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void obelisk::SuggestAction::setFact(obelisk::Fact fact)
|
|
||||||
{
|
|
||||||
fact_ = fact;
|
|
||||||
}
|
|
||||||
|
|
||||||
obelisk::Action& obelisk::SuggestAction::getTrueAction()
|
|
||||||
{
|
|
||||||
return trueAction_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void obelisk::SuggestAction::setTrueAction(obelisk::Action trueAction)
|
|
||||||
{
|
|
||||||
trueAction_ = trueAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
obelisk::Action& obelisk::SuggestAction::getFalseAction()
|
|
||||||
{
|
|
||||||
return falseAction_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void obelisk::SuggestAction::setFalseAction(obelisk::Action falseAction)
|
|
||||||
{
|
|
||||||
falseAction_ = falseAction;
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
#ifndef OBELISK_MODELS_SUGGEST_ACTION_H
|
|
||||||
#define OBELISK_MODELS_SUGGEST_ACTION_H
|
|
||||||
|
|
||||||
#include "models/action.h"
|
|
||||||
#include "models/fact.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace obelisk
|
|
||||||
{
|
|
||||||
class SuggestAction
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int id_;
|
|
||||||
obelisk::Fact fact_;
|
|
||||||
obelisk::Action trueAction_;
|
|
||||||
obelisk::Action falseAction_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SuggestAction() :
|
|
||||||
id_(0),
|
|
||||||
fact_(),
|
|
||||||
trueAction_(),
|
|
||||||
falseAction_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SuggestAction(int id) :
|
|
||||||
id_(id),
|
|
||||||
fact_(),
|
|
||||||
trueAction_(),
|
|
||||||
falseAction_()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SuggestAction(obelisk::Fact fact,
|
|
||||||
obelisk::Action trueAction,
|
|
||||||
obelisk::Action falseAction) :
|
|
||||||
id_(0),
|
|
||||||
fact_(fact),
|
|
||||||
trueAction_(trueAction),
|
|
||||||
falseAction_(falseAction)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
SuggestAction(int id,
|
|
||||||
obelisk::Fact fact,
|
|
||||||
obelisk::Action trueAction,
|
|
||||||
obelisk::Action falseAction) :
|
|
||||||
id_(id),
|
|
||||||
fact_(fact),
|
|
||||||
trueAction_(trueAction),
|
|
||||||
falseAction_(falseAction)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* createTable();
|
|
||||||
|
|
||||||
int& getId();
|
|
||||||
void setId(int id);
|
|
||||||
|
|
||||||
obelisk::Fact& getFact();
|
|
||||||
void setFact(obelisk::Fact fact);
|
|
||||||
|
|
||||||
obelisk::Action& getTrueAction();
|
|
||||||
void setTrueAction(obelisk::Action trueAction);
|
|
||||||
|
|
||||||
obelisk::Action& getFalseAction();
|
|
||||||
void setFalseAction(obelisk::Action falseAction);
|
|
||||||
};
|
|
||||||
} // namespace obelisk
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,54 +0,0 @@
|
|||||||
#ifndef OBELISK_MODELS_VERB_H
|
|
||||||
#define OBELISK_MODELS_VERB_H
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace obelisk
|
|
||||||
{
|
|
||||||
class Verb
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int id_;
|
|
||||||
std::string name_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Verb() :
|
|
||||||
id_(0),
|
|
||||||
name_("")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Verb(int id) :
|
|
||||||
id_(id),
|
|
||||||
name_("")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Verb(std::string name) :
|
|
||||||
id_(0),
|
|
||||||
name_(name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Verb(int id, std::string name) :
|
|
||||||
id_(id),
|
|
||||||
name_(name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* createTable();
|
|
||||||
|
|
||||||
int& getId();
|
|
||||||
void setId(int id);
|
|
||||||
|
|
||||||
std::string& getName();
|
|
||||||
void setName(std::string name);
|
|
||||||
|
|
||||||
void selectVerb(sqlite3* dbConnection);
|
|
||||||
void insertVerb(sqlite3* dbConnection);
|
|
||||||
};
|
|
||||||
} // namespace obelisk
|
|
||||||
|
|
||||||
#endif
|
|
113
src/obelisk.cpp
113
src/obelisk.cpp
@ -1,113 +0,0 @@
|
|||||||
#include "knowledge_base.h"
|
|
||||||
#include "lexer.h"
|
|
||||||
#include "obelisk.h"
|
|
||||||
#include "parser.h"
|
|
||||||
|
|
||||||
#include <iomanip>
|
|
||||||
#include <iostream>
|
|
||||||
#include <limits>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
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> ");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
parser->getNextToken();
|
|
||||||
}
|
|
||||||
catch (obelisk::LexerException& exception)
|
|
||||||
{
|
|
||||||
std::cout << "Error: " << exception.what() << std::endl;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "ready> ");
|
|
||||||
switch (parser->getCurrentToken())
|
|
||||||
{
|
|
||||||
case obelisk::Lexer::kTokenEof :
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
case ';' : // ignore top-level semicolons.
|
|
||||||
std::cout << "Identifier: "
|
|
||||||
<< parser->getLexer()->getIdentifier() << std::endl;
|
|
||||||
std::cout << "Num: " << parser->getLexer()->getNumberValue()
|
|
||||||
<< std::endl;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
parser->getNextToken();
|
|
||||||
}
|
|
||||||
catch (obelisk::LexerException& exception)
|
|
||||||
{
|
|
||||||
std::cout << "Error: " << exception.what() << std::endl;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case obelisk::Lexer::kTokenFact :
|
|
||||||
parser->handleFact(kb);
|
|
||||||
break;
|
|
||||||
case obelisk::Lexer::kTokenRule :
|
|
||||||
// parser->handleRule();
|
|
||||||
break;
|
|
||||||
case obelisk::Lexer::kTokenAction :
|
|
||||||
// parser->handleAction();
|
|
||||||
break;
|
|
||||||
default :
|
|
||||||
parser->getNextToken();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
for (int i = 1; i < argc; i++)
|
|
||||||
{
|
|
||||||
std::cout << argv[i] << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This can be used to store a double as 2 floats in the database, then restore it back to a double.
|
|
||||||
// Inspired by Godot's double precision on the GPU to render large worlds.
|
|
||||||
/*try
|
|
||||||
{
|
|
||||||
float first;
|
|
||||||
float second;
|
|
||||||
double var = 0.123456789012345;
|
|
||||||
|
|
||||||
obelisk::KnowledgeBase* kb = new obelisk::KnowledgeBase("cromer.kb");
|
|
||||||
kb->getFloat(first, second, var);
|
|
||||||
std::cout << std::setprecision(std::numeric_limits<double>::digits10)
|
|
||||||
<< "Double: " << var << std::endl
|
|
||||||
<< "First: " << first << std::endl
|
|
||||||
<< "Second: " << second << std::endl;
|
|
||||||
var = 0.0;
|
|
||||||
kb->getDouble(var, first, second);
|
|
||||||
std::cout << std::setprecision(std::numeric_limits<double>::digits10)
|
|
||||||
<< "Double: " << var << std::endl
|
|
||||||
<< "First: " << first << std::endl
|
|
||||||
<< "Second: " << second << std::endl;
|
|
||||||
}
|
|
||||||
catch (obelisk::KnowledgeBaseException& exception)
|
|
||||||
{
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return mainLoop();
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
static int mainLoop();
|
|
703
src/parser.cpp
703
src/parser.cpp
@ -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>
|
||||||
@ -11,16 +8,17 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
obelisk::Parser::Parser()
|
std::shared_ptr<obelisk::Lexer> obelisk::Parser::getLexer()
|
||||||
{
|
|
||||||
lexer_ = std::unique_ptr<obelisk::Lexer> {new obelisk::Lexer()};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<obelisk::Lexer>& obelisk::Parser::getLexer()
|
|
||||||
{
|
{
|
||||||
return lexer_;
|
return lexer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void obelisk::Parser::setLexer(std::shared_ptr<obelisk::Lexer> lexer)
|
||||||
|
{
|
||||||
|
lexer_ = lexer;
|
||||||
|
currentToken_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
int obelisk::Parser::getNextToken()
|
int obelisk::Parser::getNextToken()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -222,18 +220,416 @@ std::unique_ptr<obelisk::PrototypeAST> obelisk::Parser::parseExtern()
|
|||||||
return parsePrototype();
|
return parsePrototype();
|
||||||
}
|
}
|
||||||
|
|
||||||
//action("martin" is "dangerous" then "avoid" or "ignore");
|
void obelisk::Parser::parseAction(obelisk::SuggestAction& suggestAction)
|
||||||
std::unique_ptr<obelisk::ExpressionAST> obelisk::Parser::parseAction()
|
|
||||||
{
|
{
|
||||||
|
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 = 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
//rule("chris" and "martin" is "happy" if "chris" plays "playstation");
|
void obelisk::Parser::parseRule(obelisk::Rule& rule)
|
||||||
std::unique_ptr<obelisk::ExpressionAST> obelisk::Parser::parseRule()
|
|
||||||
{
|
{
|
||||||
|
std::stack<char> 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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// fact("chris cromer" and "martin" and "Isabella" can "program" and "speak english");
|
|
||||||
// fact("" and "martin")
|
|
||||||
void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
|
void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
|
||||||
{
|
{
|
||||||
std::stack<char> syntax;
|
std::stack<char> syntax;
|
||||||
@ -247,15 +643,13 @@ void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
|
|||||||
|
|
||||||
syntax.push('(');
|
syntax.push('(');
|
||||||
|
|
||||||
// ("
|
|
||||||
|
|
||||||
bool getEntity {true};
|
bool getEntity {true};
|
||||||
std::vector<std::string> leftEntities;
|
std::vector<std::string> leftEntities;
|
||||||
std::vector<std::string> rightEntities;
|
std::vector<std::string> rightEntities;
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -300,7 +694,17 @@ 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");
|
||||||
@ -317,13 +721,19 @@ void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
|
|||||||
throw obelisk::ParserException(
|
throw obelisk::ParserException(
|
||||||
"missing right side entities");
|
"missing right side entities");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNextToken();
|
||||||
|
if (getCurrentToken() != ';')
|
||||||
|
{
|
||||||
|
throw obelisk::ParserException("missing ';'");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getCurrentToken() == '"')
|
if (getCurrentToken() == '"')
|
||||||
{
|
{
|
||||||
throw obelisk::ParserException("unexpected '\"'");
|
throw obelisk::ParserException("unexpected '\"'");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getLexer()->getIdentifier() == "and")
|
if (getLexer()->getIdentifier() == "and")
|
||||||
@ -335,7 +745,14 @@ void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
verb = getLexer()->getIdentifier();
|
verb = getLexer()->getIdentifier();
|
||||||
// TODO: make sure verb is alphabetic
|
for (const auto& letter : verb)
|
||||||
|
{
|
||||||
|
if (!isalpha(letter))
|
||||||
|
{
|
||||||
|
throw new obelisk::ParserException(
|
||||||
|
"non alphabetic symbol in verb");
|
||||||
|
}
|
||||||
|
}
|
||||||
getEntity = true;
|
getEntity = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -348,100 +765,186 @@ void obelisk::Parser::parseFact(std::vector<obelisk::Fact>& facts)
|
|||||||
{
|
{
|
||||||
facts.push_back(obelisk::Fact(obelisk::Entity(leftEntity),
|
facts.push_back(obelisk::Fact(obelisk::Entity(leftEntity),
|
||||||
obelisk::Entity(rightEntity),
|
obelisk::Entity(rightEntity),
|
||||||
obelisk::Verb(verb)));
|
obelisk::Verb(verb),
|
||||||
|
true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void obelisk::Parser::handleAction(std::unique_ptr<obelisk::KnowledgeBase>& kb)
|
void obelisk::Parser::handleAction(std::unique_ptr<obelisk::KnowledgeBase>& 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<obelisk::KnowledgeBase>& kb)
|
void obelisk::Parser::handleRule(std::unique_ptr<obelisk::KnowledgeBase>& 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<obelisk::KnowledgeBase>& kb)
|
void obelisk::Parser::handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb)
|
||||||
{
|
{
|
||||||
std::vector<obelisk::Fact> facts;
|
std::vector<obelisk::Fact> facts;
|
||||||
|
try
|
||||||
|
{
|
||||||
parseFact(facts);
|
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
|
catch (obelisk::ParserException& exception)
|
||||||
{
|
{
|
||||||
fact.setLeftEntity(entity);
|
throw;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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());
|
||||||
|
}
|
||||||
|
catch (obelisk::ParserException& exception)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
verbId = fact.getVerb().getId();
|
verbId = fact.getVerb().getId();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
fact.getVerb().setId(verbId);
|
fact.getVerb().setId(verbId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
insertFact(kb, fact, true);
|
||||||
|
}
|
||||||
|
catch (obelisk::ParserException& exception)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
kb->checkRule(fact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::insertAction(std::unique_ptr<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::Action& action)
|
||||||
|
{
|
||||||
|
std::vector<obelisk::Action> 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<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::Fact& fact,
|
||||||
|
bool updateIsTrue)
|
||||||
|
{
|
||||||
std::vector<obelisk::Fact> facts {fact};
|
std::vector<obelisk::Fact> facts {fact};
|
||||||
kb->addFacts(facts);
|
kb->addFacts(facts);
|
||||||
fact = facts.front();
|
fact = std::move(facts.front());
|
||||||
|
|
||||||
|
// the id was not inserted, so check if it exists in the database
|
||||||
if (fact.getId() == 0)
|
if (fact.getId() == 0)
|
||||||
{
|
{
|
||||||
kb->getFact(fact);
|
kb->getFact(fact);
|
||||||
@ -450,8 +953,52 @@ void obelisk::Parser::handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb)
|
|||||||
throw obelisk::ParserException(
|
throw obelisk::ParserException(
|
||||||
"fact could not be inserted into the database");
|
"fact could not be inserted into the database");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (updateIsTrue)
|
||||||
|
{
|
||||||
|
fact.setIsTrue(1.0);
|
||||||
|
kb->updateIsTrue(fact);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fact("chris cromer" and "martin" and "Isabella" can "program" and "speak english");
|
void obelisk::Parser::insertSuggestAction(
|
||||||
|
std::unique_ptr<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::SuggestAction& suggestAction)
|
||||||
|
{
|
||||||
|
std::vector<obelisk::SuggestAction> 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<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::Rule& rule)
|
||||||
|
{
|
||||||
|
std::vector<obelisk::Rule> 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
272
src/parser.h
272
src/parser.h
@ -6,71 +6,325 @@
|
|||||||
#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>
|
||||||
|
|
||||||
namespace obelisk
|
namespace obelisk
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @brief The Parser is responsible for analyzing the language's key words
|
||||||
|
* and taking action based on its analysis.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class Parser
|
class Parser
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<obelisk::Lexer> lexer_;
|
/**
|
||||||
int currentToken_;
|
* @brief The Lexer object that the Parser is using to Parse a
|
||||||
|
* specific source file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
std::shared_ptr<obelisk::Lexer> lexer_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The current token that the lexer has retrieved.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int currentToken_ = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the current token.
|
||||||
|
*
|
||||||
|
* @param[in] currentToken The token should be ASCII character.
|
||||||
|
*/
|
||||||
void setCurrentToken(int currentToken);
|
void setCurrentToken(int currentToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Log errors from the LLVM parsing.
|
||||||
|
*
|
||||||
|
* @param[in] str The error message.
|
||||||
|
* @return std::unique_ptr<obelisk::ExpressionAST> Returns the AST
|
||||||
|
* expression that caused the error.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::ExpressionAST> logError(const char* str);
|
std::unique_ptr<obelisk::ExpressionAST> logError(const char* str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Log errors from the LLVM parsing involving the prototypes.
|
||||||
|
*
|
||||||
|
* @param[in] str The error message.
|
||||||
|
* @return std::unique_ptr<obelisk::PrototypeAST> Returns the AST
|
||||||
|
* for the prototype.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::PrototypeAST> logErrorPrototype(
|
std::unique_ptr<obelisk::PrototypeAST> logErrorPrototype(
|
||||||
const char* str);
|
const char* str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The AST expression parser.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<obelisk::ExpressionAST> Returns the
|
||||||
|
* parsed AST expression.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::ExpressionAST> parseExpression();
|
std::unique_ptr<obelisk::ExpressionAST> parseExpression();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The AST number expression parser.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<obelisk::ExpressionAST> Returns the
|
||||||
|
* parsed AST expression.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::ExpressionAST> parseNumberExpression();
|
std::unique_ptr<obelisk::ExpressionAST> parseNumberExpression();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The AST parenthesis expression parser.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<obelisk::ExpressionAST> Returns the
|
||||||
|
* parsed AST expression.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::ExpressionAST>
|
std::unique_ptr<obelisk::ExpressionAST>
|
||||||
parseParenthesisExpression();
|
parseParenthesisExpression();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The AST identifier expression parser.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<obelisk::ExpressionAST> Returns the
|
||||||
|
* parsed AST expression.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::ExpressionAST> parseIdentifierExpression();
|
std::unique_ptr<obelisk::ExpressionAST> parseIdentifierExpression();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The AST primary expression parser.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<obelisk::ExpressionAST> Returns the
|
||||||
|
* parsed AST expression.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::ExpressionAST> parsePrimary();
|
std::unique_ptr<obelisk::ExpressionAST> parsePrimary();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The AST prototype parser.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<obelisk::PrototypeAST> Returns the parsed
|
||||||
|
* AST prototype expression.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::PrototypeAST> parsePrototype();
|
std::unique_ptr<obelisk::PrototypeAST> parsePrototype();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The AST definition parser.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<obelisk::FunctionAST> Returns the parsed
|
||||||
|
* AST definition expression.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::FunctionAST> parseDefinition();
|
std::unique_ptr<obelisk::FunctionAST> parseDefinition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The AST top level expression parser.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<obelisk::FunctionAST> Returns the parsed
|
||||||
|
* AST top level expression.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::FunctionAST> parseTopLevelExpression();
|
std::unique_ptr<obelisk::FunctionAST> parseTopLevelExpression();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The AST external definition parser.
|
||||||
|
*
|
||||||
|
* @return std::unique_ptr<obelisk::PrototypeAST> Returns the parsed
|
||||||
|
* AST external definition.
|
||||||
|
*/
|
||||||
std::unique_ptr<obelisk::PrototypeAST> parseExtern();
|
std::unique_ptr<obelisk::PrototypeAST> parseExtern();
|
||||||
std::unique_ptr<obelisk::ExpressionAST> parseAction();
|
|
||||||
std::unique_ptr<obelisk::ExpressionAST> parseRule();
|
/**
|
||||||
|
* @brief Parse a SuggestAction.
|
||||||
|
*
|
||||||
|
* @param[out] suggestAction The parsed SuggestAction.
|
||||||
|
*/
|
||||||
|
void parseAction(obelisk::SuggestAction& suggestAction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse a Rule.
|
||||||
|
*
|
||||||
|
* @param[out] rule The parsed Rule.
|
||||||
|
*/
|
||||||
|
void parseRule(obelisk::Rule& rule);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse Facts.
|
||||||
|
*
|
||||||
|
* @param[out] facts The parsed Facts.
|
||||||
|
*/
|
||||||
void parseFact(std::vector<obelisk::Fact>& facts);
|
void parseFact(std::vector<obelisk::Fact>& facts);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Parser();
|
/**
|
||||||
|
* @brief Construct a new Parser object.
|
||||||
|
*
|
||||||
|
* @param[in] lexer The lexer the parser uses to retrieve parts of
|
||||||
|
* the language.
|
||||||
|
*/
|
||||||
|
Parser(std::shared_ptr<obelisk::Lexer> lexer) :
|
||||||
|
lexer_(lexer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<obelisk::Lexer>& getLexer();
|
/**
|
||||||
|
* @brief Get the Lexer.
|
||||||
|
*
|
||||||
|
* @return std::shared_ptr<obelisk::Lexer> Returns the current Lexer
|
||||||
|
* in use by the Parser.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<obelisk::Lexer> getLexer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the Lexer to use during the parsing phase.
|
||||||
|
*
|
||||||
|
* @param[in] lexer The Lexer.
|
||||||
|
*/
|
||||||
|
void setLexer(std::shared_ptr<obelisk::Lexer> lexer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current token held inside the Lexer.
|
||||||
|
*
|
||||||
|
* @return int Returns the current token.
|
||||||
|
*/
|
||||||
int getCurrentToken();
|
int getCurrentToken();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Instructs the Lexer to retrieve a new token.
|
||||||
|
*
|
||||||
|
* @return int Returns the next token.
|
||||||
|
*/
|
||||||
int getNextToken();
|
int getNextToken();
|
||||||
|
|
||||||
void handleDefinition();
|
/**
|
||||||
void handleExtern();
|
* @brief Parse the SuggestAction and then insert it into the
|
||||||
void handleTopLevelExpression();
|
* KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] kb The KnowledgeBase to insert the SuggestAction into.
|
||||||
|
*/
|
||||||
void handleAction(std::unique_ptr<obelisk::KnowledgeBase>& kb);
|
void handleAction(std::unique_ptr<obelisk::KnowledgeBase>& kb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse the Rule and then insert it into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] kb The KnowledgeBase to insert the Rule into.
|
||||||
|
*/
|
||||||
void handleRule(std::unique_ptr<obelisk::KnowledgeBase>& kb);
|
void handleRule(std::unique_ptr<obelisk::KnowledgeBase>& kb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse the Fact and then insert it into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] kb The KnowledgeBase to insert the Fact into.
|
||||||
|
*/
|
||||||
void handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb);
|
void handleFact(std::unique_ptr<obelisk::KnowledgeBase>& kb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper used to insert an Entity into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] kb The KnowledgeBase to use.
|
||||||
|
* @param[in,out] entity The Entity to insert. It will contain the
|
||||||
|
* ID of the Entity after inserting it.
|
||||||
|
*/
|
||||||
|
void insertEntity(std::unique_ptr<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::Entity& entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper used to insert a Verb into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] kb The KnowledegeBase to use.
|
||||||
|
* @param[in,out] verb The Verb to insert. It will contain the ID of
|
||||||
|
* the Verb after inserting it.
|
||||||
|
*/
|
||||||
|
void insertVerb(std::unique_ptr<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::Verb& verb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper used to insert an Action into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] kb The KnowledgeBase to use.
|
||||||
|
* @param[in,out] action The Action to insert. It will contain the
|
||||||
|
* ID of the Action after inserting it.
|
||||||
|
*/
|
||||||
|
void insertAction(std::unique_ptr<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::Action& action);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper used to insert a Fact into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] kb The KnowledgeBase to use.
|
||||||
|
* @param[in,out] fact The Fact to insert. It will contain the ID of
|
||||||
|
* the Fact after inserting it.
|
||||||
|
* @param[in] updateIsTrue If true, it will update the value of
|
||||||
|
* is_true in the KnowledgeBase if the Fact already exists.
|
||||||
|
*/
|
||||||
|
void insertFact(std::unique_ptr<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::Fact& fact,
|
||||||
|
bool updateIsTrue = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper used to insert a SuggestAction into the
|
||||||
|
* KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] kb The KnowledgeBase to use.
|
||||||
|
* @param[in,out] suggestAction The SuggestAction to insert. It will
|
||||||
|
* contain the ID of the SuggestAction after inserting it.
|
||||||
|
*/
|
||||||
|
void insertSuggestAction(
|
||||||
|
std::unique_ptr<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::SuggestAction& suggestAction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Helper usedto insert a Rule into the KnowledgeBase.
|
||||||
|
*
|
||||||
|
* @param[in] kb The KnowledgeBase to use.
|
||||||
|
* @param[in,out] rule The Rule to insert. It will contain the ID of
|
||||||
|
* the Rule after inserting it.
|
||||||
|
*/
|
||||||
|
void insertRule(std::unique_ptr<obelisk::KnowledgeBase>& kb,
|
||||||
|
obelisk::Rule& rule);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The exceptions thrown by the Parser.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class ParserException : public std::exception
|
class ParserException : public std::exception
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief The error message.
|
||||||
|
*
|
||||||
|
*/
|
||||||
const std::string errorMessage_;
|
const std::string errorMessage_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new ParserException object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
ParserException() :
|
ParserException() :
|
||||||
errorMessage_("an unknown error ocurred")
|
errorMessage_("an unknown error ocurred")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new ParserException object.
|
||||||
|
*
|
||||||
|
* @param[in] errorMessage The error message.
|
||||||
|
*/
|
||||||
ParserException(const std::string& errorMessage) :
|
ParserException(const std::string& errorMessage) :
|
||||||
errorMessage_(errorMessage)
|
errorMessage_(errorMessage)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the error message as a C style string.
|
||||||
|
*
|
||||||
|
* @return const char* Returns the error message.
|
||||||
|
*/
|
||||||
const char* what() const noexcept
|
const char* what() const noexcept
|
||||||
{
|
{
|
||||||
return errorMessage_.c_str();
|
return errorMessage_.c_str();
|
||||||
|
Loading…
Reference in New Issue
Block a user