query engine can now generate, compile and run dummy code, everything is ready to generate code for dummy the query: CREATE (n {...}) RETURN n
This commit is contained in:
parent
dbe1464f9b
commit
7d8c5a7f7e
11
config/config.hpp
Normal file
11
config/config.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/config/config.hpp"
|
||||
|
||||
namespace config
|
||||
{
|
||||
|
||||
constexpr const char * COMPILE_CPU_PATH = "compile_cpu_path";
|
||||
constexpr const char * TEMPLATE_CPU_PATH = "template_cpu_path";
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/command_line/arguments.hpp"
|
||||
#include "utils/string/filereader.hpp"
|
||||
#include "utils/string/file.hpp"
|
||||
|
||||
std::string extract_query(const vector_str& arguments)
|
||||
{
|
||||
@ -10,6 +10,6 @@ std::string extract_query(const vector_str& arguments)
|
||||
auto default_file = "query.cypher";
|
||||
auto file = get_argument(arguments, "-f", default_file);
|
||||
// TODO: error handling
|
||||
return read_file(file.c_str());
|
||||
return utils::read_file(file.c_str());
|
||||
}
|
||||
|
||||
|
29
dc/test.cpp
29
dc/test.cpp
@ -1,38 +1,15 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
#include <cstdlib>
|
||||
#include "example/db.hpp"
|
||||
#include "dynamic_lib.hpp"
|
||||
#include "utils/string/file.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
void write(const std::string& path, const std::string& content)
|
||||
{
|
||||
ofstream stream;
|
||||
stream.open (path.c_str());
|
||||
stream << content;
|
||||
stream.close();
|
||||
}
|
||||
|
||||
std::string join(const std::vector<std::string>& strings, const char *separator)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
std::copy(strings.begin(), strings.end(),
|
||||
std::ostream_iterator<std::string>(oss, separator));
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
std::string prints(const Args&... args)
|
||||
{
|
||||
std::vector<std::string> strings = {args...};
|
||||
return join(strings, " ");
|
||||
}
|
||||
|
||||
// dependent on specific dynamic code
|
||||
// "configuration" of DynamicLib
|
||||
// DynamicLib<MemgraphDynamicLib>
|
||||
@ -47,10 +24,9 @@ public:
|
||||
const std::string MemgraphDynamicLib::produce_name = "produce";
|
||||
const std::string MemgraphDynamicLib::destruct_name = "destruct";
|
||||
|
||||
int main()
|
||||
int main()
|
||||
{
|
||||
// -- compile example
|
||||
|
||||
// string tmp_file_path = "tmp/tmp.cpp";
|
||||
// string tmp_so_path = "tmp/tmp.so";
|
||||
// string for_compile = "#include <iostream>\nint main() { std::cout << \"test\" << std::endl; return 0; }";
|
||||
@ -58,7 +34,6 @@ int main()
|
||||
// write(tmp_file_path, for_compile);
|
||||
// string test_command = prints("clang++", tmp_file_path, "-o", "test.out");
|
||||
// system(test_command.c_str());
|
||||
|
||||
// -- end compile example
|
||||
|
||||
// -- load example
|
||||
|
@ -1,5 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "utils/string/join.hpp"
|
||||
|
||||
class CodeCompiler
|
||||
{
|
||||
public:
|
||||
void compile(const std::string& in_file, const std::string& out_file)
|
||||
{
|
||||
auto compile_command = utils::prints(
|
||||
"clang++",
|
||||
"-std=c++1y",
|
||||
in_file,
|
||||
"-o", out_file,
|
||||
"-I../",
|
||||
"-shared -fPIC"
|
||||
);
|
||||
system(compile_command.c_str());
|
||||
}
|
||||
};
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "i_code_cpu.hpp"
|
||||
#include "database/db.hpp"
|
||||
#include "utils/log/logger.hpp"
|
||||
|
||||
class CodeExecutor
|
||||
{
|
||||
@ -11,10 +12,11 @@ public:
|
||||
|
||||
void execute(ICodeCPU *code_cpu)
|
||||
{
|
||||
code_cpu->name();
|
||||
log.info(code_cpu->query());
|
||||
code_cpu->run(db);
|
||||
}
|
||||
|
||||
private:
|
||||
Db db;
|
||||
Logger log;
|
||||
};
|
||||
|
@ -1,5 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/string/file.hpp"
|
||||
#include "template_engine/engine.hpp"
|
||||
#include "config/config.hpp"
|
||||
#include "utils/log/logger.hpp"
|
||||
|
||||
using std::string;
|
||||
|
||||
class CodeGenerator
|
||||
{
|
||||
public:
|
||||
void generate(const std::string& query, const std::string& path)
|
||||
{
|
||||
string template_path =
|
||||
config::Config::instance()[config::TEMPLATE_CPU_PATH];
|
||||
string template_file = utils::read_file(template_path.c_str());
|
||||
// TODO instead of code should be generated code
|
||||
// use query visitor to build the code
|
||||
string generated = template_engine.render(
|
||||
template_file,
|
||||
{
|
||||
{"class_name", "Code"},
|
||||
{"query", "\"" + query + "\""},
|
||||
{"code", "cout << \"test code\" << endl;"}
|
||||
}
|
||||
);
|
||||
utils::write_file(generated, path);
|
||||
}
|
||||
private:
|
||||
template_engine::TemplateEngine template_engine;
|
||||
Logger log;
|
||||
};
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "code_compiler.hpp"
|
||||
#include "code_generator.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "utils/log/logger.hpp"
|
||||
#include "config/config.hpp"
|
||||
|
||||
using std::string;
|
||||
using std::cout;
|
||||
@ -27,19 +29,35 @@ public:
|
||||
|
||||
ICodeCPU* load_code_cpu(const string& query)
|
||||
{
|
||||
// TODO implement me
|
||||
// for now returns already compiled code
|
||||
|
||||
auto stripped = stripper.strip(query);
|
||||
// TODO move to logger
|
||||
cout << "Stripped query is: " << stripped << endl;
|
||||
log.info("stripped_query=" + stripped);
|
||||
auto stripped_hash = fnv(stripped);
|
||||
// TODO move to logger
|
||||
cout << "Query hash is: " << stripped_hash << endl;
|
||||
|
||||
auto code_lib = load_code_lib("./compiled/cpu/create_return.so");
|
||||
auto hash_string = std::to_string(stripped_hash);
|
||||
log.info("query_hash=" + hash_string);
|
||||
|
||||
auto code_lib_iter = code_libs.find(stripped_hash);
|
||||
|
||||
// code is already compiled and loaded, just return runnable
|
||||
// instance
|
||||
if (code_lib_iter != code_libs.end())
|
||||
// TODO also return extracted arguments
|
||||
return code_lib_iter->second->instance();
|
||||
|
||||
// code has to be generated, compiled and loaded
|
||||
// TODO load output path from config
|
||||
auto base_path = config::Config::instance()[config::COMPILE_CPU_PATH];
|
||||
auto path_cpp = base_path + hash_string + ".cpp";
|
||||
code_generator.generate(query, path_cpp);
|
||||
|
||||
// TODO compile generated code
|
||||
auto path_so = base_path + hash_string + ".so";
|
||||
code_compiler.compile(path_cpp, path_so);
|
||||
|
||||
// loads dynamic lib and store it
|
||||
auto code_lib = load_code_lib(path_so);
|
||||
code_libs.insert({{stripped_hash, code_lib}});
|
||||
|
||||
// return instance of runnable code (ICodeCPU)
|
||||
return code_lib->instance();
|
||||
}
|
||||
|
||||
@ -53,6 +71,7 @@ private:
|
||||
|
||||
CodeGenerator code_generator;
|
||||
CodeCompiler code_compiler;
|
||||
Logger log;
|
||||
|
||||
sptr_code_lib load_code_lib(const string& path)
|
||||
{
|
||||
|
@ -4,4 +4,5 @@
|
||||
cd compiled/cpu
|
||||
clang++ -std=c++1y create_return.cpp -o create_return.so -I../../../ -shared -fPIC
|
||||
cd ../..
|
||||
clang++ -std=c++1y -g -I../ main.cpp ../cypher/cypher.cpp -o engine -ldl
|
||||
# clang++ -std=c++1y -g -I../ -I ../lib/yaml-cpp/include main.cpp ../cypher/cypher.cpp -o engine -L ../lib/yaml-cpp/build -l yaml-cpp -l dl
|
||||
clang++ -std=c++1y -g -I../ main.cpp ../cypher/cypher.cpp -o engine -l dl
|
||||
|
4
query_engine/compiled/cpu/.gitignore
vendored
Normal file
4
query_engine/compiled/cpu/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "query_engine/i_code_cpu.hpp"
|
||||
|
||||
@ -9,9 +10,9 @@ class CreateReturn : public ICodeCPU
|
||||
{
|
||||
public:
|
||||
|
||||
void name() const override
|
||||
std::string query() const override
|
||||
{
|
||||
cout << "CRETE RETURN QUERY" << endl;
|
||||
return "CRETE RETURN QUERY";
|
||||
}
|
||||
|
||||
void run(Db& db) const override
|
||||
|
4
query_engine/compiled/gpu/.gitignore
vendored
Normal file
4
query_engine/compiled/gpu/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
3
query_engine/config.yaml
Normal file
3
query_engine/config.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
# Memgraph test config
|
||||
|
||||
compile_cpu_path: ./compiled/cpu/
|
Binary file not shown.
@ -1,11 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "database/db.hpp"
|
||||
|
||||
class ICodeCPU
|
||||
{
|
||||
public:
|
||||
virtual void name() const = 0;
|
||||
virtual std::string query() const = 0;
|
||||
virtual void run(Db& db) const = 0;
|
||||
virtual ~ICodeCPU() {}
|
||||
};
|
||||
|
@ -29,6 +29,7 @@ public:
|
||||
|
||||
decltype(auto) strip(const std::string& query)
|
||||
{
|
||||
// TODO return hash and arguments
|
||||
auto tokenizer = lexer->tokenize(query);
|
||||
std::string stripped = "";
|
||||
int counter = 0;
|
||||
|
34
query_engine/template/template_code_cpu.cpp
Normal file
34
query_engine/template/template_code_cpu.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "query_engine/i_code_cpu.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
class {{class_name}} : public ICodeCPU
|
||||
{
|
||||
public:
|
||||
|
||||
std::string query() const override
|
||||
{
|
||||
return {{query}};
|
||||
}
|
||||
|
||||
void run(Db& db) const override
|
||||
{
|
||||
{{code}}
|
||||
}
|
||||
|
||||
~{{class_name}}() {}
|
||||
};
|
||||
|
||||
extern "C" ICodeCPU* produce()
|
||||
{
|
||||
return new {{class_name}}();
|
||||
}
|
||||
|
||||
extern "C" void destruct(ICodeCPU* p)
|
||||
{
|
||||
delete p;
|
||||
}
|
32
template_engine/engine.hpp
Normal file
32
template_engine/engine.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "utils/string/replace.hpp"
|
||||
|
||||
namespace template_engine
|
||||
{
|
||||
|
||||
using std::string;
|
||||
using data = std::unordered_map<string, string>;
|
||||
|
||||
class TemplateEngine
|
||||
{
|
||||
public:
|
||||
string render(const string& form, const data& partials)
|
||||
{
|
||||
// TODO more optimal implementation
|
||||
// if more optimal implementation is to expensive
|
||||
// use some templating engine like https://github.com/no1msd/mstch
|
||||
// but it has to be wrapped
|
||||
string rendered = form;
|
||||
for (auto partial : partials) {
|
||||
string key = "{{" + partial.first + "}}";
|
||||
rendered = utils::replace(rendered, key, partial.second);
|
||||
}
|
||||
return rendered;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
58
utils/config/config.hpp
Normal file
58
utils/config/config.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
// #define YAML_CPP_DLL
|
||||
// there are some problems with the yaml-cpp linking, something is missing
|
||||
// cmake and make have passed fine
|
||||
// and it seems that everything is included and linked
|
||||
// the yaml-cpp lib is strange
|
||||
// TODO debug yaml-cpp installation or write own yaml parser like a boss
|
||||
// #include "yaml-cpp/yaml.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace config
|
||||
{
|
||||
|
||||
class Config
|
||||
{
|
||||
private:
|
||||
// YAML::Node _config;
|
||||
Config()
|
||||
{
|
||||
// TODO: config places: priority
|
||||
// 1. default system |
|
||||
// 2. default user |
|
||||
// 3. ENV var |
|
||||
// 4. program argument \ /
|
||||
// _config = YAML::LoadFile("config.yaml");
|
||||
}
|
||||
|
||||
public:
|
||||
static Config& instance()
|
||||
{
|
||||
// TODO resolve multithreading problems
|
||||
static Config config;
|
||||
return config;
|
||||
}
|
||||
|
||||
std::string operator[](const char* key)
|
||||
{
|
||||
// TODO write proper implementation, remove memgraph dependant
|
||||
// stuff from here
|
||||
|
||||
if (0 == std::strcmp(key, "compile_cpu_path"))
|
||||
return "./compiled/cpu/";
|
||||
|
||||
if (std::strcmp(key, "template_cpu_path") == 0)
|
||||
return "./template/template_code_cpu.cpp";
|
||||
|
||||
throw std::runtime_error("implement me");
|
||||
|
||||
// TODO optimize access
|
||||
// return _config[key].as<std::string>();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
37
utils/log/logger.hpp
Normal file
37
utils/log/logger.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
Logger() = default;
|
||||
|
||||
// TODO logger name support
|
||||
|
||||
// TODO level support
|
||||
|
||||
// TODO handlers support:
|
||||
// * log format support
|
||||
|
||||
void info(const std::string& text)
|
||||
{
|
||||
stdout_log(text);
|
||||
}
|
||||
|
||||
void debug(const std::string& text)
|
||||
{
|
||||
stdout_log(text);
|
||||
}
|
||||
|
||||
private:
|
||||
void stdout_log(const std::string& text)
|
||||
{
|
||||
auto now = std::time(nullptr);
|
||||
std::cout << std::put_time(std::gmtime(&now), "[%F %T]: ")
|
||||
<< text << std::endl;
|
||||
}
|
||||
};
|
@ -1,10 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
#include <cerrno>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
|
||||
std::string read_file(const char *filename)
|
||||
{
|
||||
std::ifstream in(filename, std::ios::in | std::ios::binary);
|
||||
@ -13,3 +17,13 @@ std::string read_file(const char *filename)
|
||||
std::istreambuf_iterator<char>());
|
||||
throw(errno);
|
||||
}
|
||||
|
||||
void write_file(const std::string& content, const std::string& path)
|
||||
{
|
||||
std::ofstream stream;
|
||||
stream.open(path.c_str());
|
||||
stream << content;
|
||||
stream.close();
|
||||
}
|
||||
|
||||
}
|
26
utils/string/join.hpp
Normal file
26
utils/string/join.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
|
||||
std::string join(const std::vector<std::string>& strings, const char *separator)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
std::copy(strings.begin(), strings.end(),
|
||||
std::ostream_iterator<std::string>(oss, separator));
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
std::string prints(const Args&... args)
|
||||
{
|
||||
std::vector<std::string> strings = {args...};
|
||||
return join(strings, " ");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user