antlr integration, *.hpp and *.cpp inside src dir, cleanup

Summary: antlr integration, *.hpp and *.cpp inside src dir, cleanup

Test Plan: manual

Reviewers: mislav.bradac, dgleich, florijan

Reviewed By: florijan

Subscribers: pullbot, buda

Differential Revision: https://phabricator.memgraph.io/D49
This commit is contained in:
Marko Budiselic 2017-02-17 16:11:57 +01:00
parent 95dcb4c1ba
commit e7f5bd4c21
403 changed files with 15788 additions and 5879 deletions

1
.gitignore vendored
View File

@ -25,3 +25,4 @@ build/compiled/
cmake-build-*
.idea
cmake/DownloadProject/
dist/

View File

@ -5,12 +5,14 @@ cmake_minimum_required(VERSION 3.1)
# !! IMPORTANT !! run ./project_root/init.sh before cmake command
# to download dependencies
if(NOT UNIX)
message(FATAL "Unsupported operating system.")
endif()
# choose a compiler
# NOTE: must be choosen before use of project() or enable_language()
if (UNIX)
# NOTE: must be choosen before use of project() or enable_language() ----------
set(CMAKE_C_COMPILER "clang")
set(CMAKE_CXX_COMPILER "clang++")
endif (UNIX)
# -----------------------------------------------------------------------------
# set project name
@ -50,11 +52,28 @@ set(test_include_dir ${CMAKE_BINARY_DIR}/tests/include)
set(test_src_dir ${CMAKE_BINARY_DIR}/tests/src)
# -----------------------------------------------------------------------------
# setup external dependencies
# lemon & lempar
set(lemon_dir ${libs_dir}/lemon)
# lexertl
set(lexertl_dir ${libs_dir}/lexertl)
# build flags -----------------------------------------------------------------
# release flags
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
#debug flags
set(CMAKE_CXX_FLAGS_DEBUG "-g")
# compiler specific flags
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# set(CMAKE_CXX_FLAGS_DEBUG "-Wl,--export-dynamic ${CMAKE_CXX_FLAGS_DEBUG}")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# set(CMAKE_CXX_FLAGS_DEBUG "-rdynamic ${CMAKE_CXX_FLAGS_DEBUG}")
endif()
# default build type is debug
if ("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE "debug")
endif()
message(STATUS "CMake build type: ${CMAKE_BUILD_TYPE}")
# -----------------------------------------------------------------------------
# setup external dependencies -------------------------------------------------
add_subdirectory(libs)
# fmt
set(fmt_source_dir ${libs_dir}/fmt)
set(fmt_static_lib ${fmt_source_dir}/fmt/libfmt.a)
@ -62,31 +81,8 @@ set(fmt_static_lib ${fmt_source_dir}/fmt/libfmt.a)
set(yaml_source_dir ${libs_dir}/yaml-cpp)
set(yaml_include_dir ${yaml_source_dir}/include)
set(yaml_static_lib ${yaml_source_dir}/libyaml-cpp.a)
# Catch (C++ Automated Test Cases in Headers)
set(catch_source_dir "${libs_dir}/Catch")
# -----------------------------------------------------------------------------
# load cmake modules: cmake/*.cmake
include(gtest)
include(gbenchmark)
# -----------------------------------------------------------------------------
# build memgraph's cypher grammar
# copy grammar file to the build directory
FILE(COPY ${include_dir}/query/language/cypher/cypher.y
DESTINATION ${CMAKE_BINARY_DIR})
# build cypher parser (only c file - cypher.c)
EXECUTE_PROCESS(
COMMAND ${lemon_dir}/lemon ${CMAKE_BINARY_DIR}/cypher.y -s
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
# change cypher parser c extension to cpp (cypher.c -> cypher.cpp)
FILE(RENAME ${CMAKE_BINARY_DIR}/cypher.c ${CMAKE_BINARY_DIR}/cypher.cpp)
# add include file (cypher.h) to build include dir
SET(cypher_build_include_dir ${build_include_dir}/cypher)
FILE(MAKE_DIRECTORY ${cypher_build_include_dir})
FILE(RENAME ${CMAKE_BINARY_DIR}/cypher.h ${cypher_build_include_dir}/cypher.h)
# -----------------------------------------------------------------------------
# antlr
set(antlr_static_lib ${CMAKE_SOURCE_DIR}/dist/libantlr4-runtime.a)
# prepare template and destination folders for query engine (tests)
# and memgraph server binary
@ -111,7 +107,8 @@ FILE(COPY ${tests_dir}/integration/stream
# -----------------------------------------------------------------------------
# copy files needed for query engine (headers)
include(copy_includes)
# TODO: copy includes for runtime compilation
# include(copy_includes)
# -----------------------------------------------------------------------------
# linter setup (clang-tidy)
@ -137,27 +134,7 @@ if(CLANG_TIDY)
endif()
# -----------------------------------------------------------------------------
# TODO: add specific flags
# release flags
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
#debug flags
set(CMAKE_CXX_FLAGS_DEBUG "-g")
# compiler specific flags
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# set(CMAKE_CXX_FLAGS_DEBUG "-Wl,--export-dynamic ${CMAKE_CXX_FLAGS_DEBUG}")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# set(CMAKE_CXX_FLAGS_DEBUG "-rdynamic ${CMAKE_CXX_FLAGS_DEBUG}")
endif()
# default build type is debug
if ("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE "debug")
endif()
message(STATUS "CMake build type: ${CMAKE_BUILD_TYPE}")
# -----------------------------------------------------------------------------
# logging levels
# logging levels --------------------------------------------------------------
option(LOG_NO_TRACE "Disable trace logging" OFF)
message(STATUS "LOG_NO_TRACE: ${LOG_NO_TRACE}")
if (LOG_NO_TRACE)
@ -187,7 +164,6 @@ message(STATUS "LOG_NO_ERROR: ${LOG_NO_ERROR}")
if (LOG_NO_ERROR)
add_definitions(-DLOG_NO_ERROR)
endif()
# TODO: find a way how to applay those defines at the query compile time
# -----------------------------------------------------------------------------
# logger type
@ -269,24 +245,54 @@ include_directories(${src_dir})
include_directories(${build_include_dir})
include_directories(${fmt_source_dir})
include_directories(${yaml_include_dir})
include_directories(${http_parser_source_dir})
include_directories(${lexertl_dir})
include_directories(${libuv_source_dir}/include)
include_directories(${rapidjson_source_dir}/include)
include_directories(${r3_source_dir}/include)
# -----------------------------------------------------------------------------
# creates build/libcypher_lib.a
add_library(cypher_lib STATIC ${CMAKE_BINARY_DIR}/cypher.cpp)
# -----------------------------------------------------------------------------
# openCypher parser -----------------------------------------------------------
set(antlr_src ${CMAKE_SOURCE_DIR}/libs/antlr4/runtime/Cpp/runtime/src)
set(opencypher_frontend ${CMAKE_SOURCE_DIR}/src/query/frontend/opencypher)
set(opencypher_generated ${opencypher_frontend}/generated)
set(opencypher_grammar ${opencypher_frontend}/grammar/Cypher.g4)
# TODO: remove from here (isolate HTTP server)
# # REST API preprocessor
# EXECUTE_PROCESS(
# COMMAND python link_resources.py
# WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src/api
# enumerate all files that are generated from antlr
set(antlr_opencypher_generated_src
${opencypher_frontend}/generated/CypherLexer.cpp
${opencypher_frontend}/generated/CypherParser.cpp
${opencypher_frontend}/generated/CypherBaseVisitor.cpp
${opencypher_frontend}/generated/CypherVisitor.cpp
)
# set generated flag to true
# foreach(src_file ${antlr_opencypher_generated_src})
# set_source_files_properties(
# ${src_file}
# PROPERTIES
# GENERATED TRUE
# )
# # ---------------------------------------------------------------------------
# endforeach(src_file ${antlr_opencypher_generated_src})
# add custom target for generation
add_custom_target(generate_opencypher_parser
COMMAND
${CMAKE_COMMAND} -E make_directory ${opencypher_generated}
COMMAND
java -jar ${CMAKE_BINARY_DIR}/antlr-4.6-complete.jar -Dlanguage=Cpp -visitor -o ${opencypher_generated} -package antlrcpptest ${opencypher_grammar}
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
DEPENDS ${opencypher_grammar}
)
# include antlr header files
include_directories(
${antlr_src}
${antlr_src}/misc
${antlr_src}/atn
${antlr_src}/dfa
${antlr_src}/tree
${antlr_src}/support
)
add_library(antlr_opencypher_parser_lib STATIC ${antlr_opencypher_generated_src})
target_link_libraries(antlr_opencypher_parser_lib ${antlr_static_lib})
# -----------------------------------------------------------------------------
# all memgraph src files
set(memgraph_src_files
@ -357,6 +363,11 @@ if (ALL_TESTS OR BENCHMARK_TESTS OR CONCURRENT_TEST OR INTEGRATION_TEST
endif()
# -----------------------------------------------------------------------------
execute_process(
COMMAND python recursive_include.py --root ${src_dir} --start ${src_dir}/query/plan_interface.hpp --copy ${CMAKE_BINARY_DIR}/include
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/cmake
)
# memgraph build name
execute_process(
OUTPUT_VARIABLE COMMIT_BRANCH
@ -384,14 +395,20 @@ if (MEMGRAPH)
target_link_libraries(${MEMGRAPH_BUILD_NAME} memgraph_lib)
target_link_libraries(${MEMGRAPH_BUILD_NAME} stdc++fs)
target_link_libraries(${MEMGRAPH_BUILD_NAME} Threads::Threads)
target_link_libraries(${MEMGRAPH_BUILD_NAME} cypher_lib)
if (UNIX)
# target_link_libraries(${MEMGRAPH_BUILD_NAME} crypto)
# target_link_libraries(${MEMGRAPH_BUILD_NAME} ssl)
target_link_libraries(${MEMGRAPH_BUILD_NAME} ${fmt_static_lib})
target_link_libraries(${MEMGRAPH_BUILD_NAME} ${yaml_static_lib})
target_link_libraries(${MEMGRAPH_BUILD_NAME} ${antlr_static_lib})
target_link_libraries(${MEMGRAPH_BUILD_NAME} antlr_opencypher_parser_lib)
target_link_libraries(${MEMGRAPH_BUILD_NAME} dl)
endif (UNIX)
endif()
# add_dependencies(${MEMGRAPH_BUILD_NAME} generate_opencypher_parser)
# -----------------------------------------------------------------------------
# make CLion aware of all source files so we get refactoring etc
# TODO: fix snapshots and everything from src and then add custom target
#file(GLOB_RECURSE __SOURCES ${CMAKE_SOURCE_DIR}/src/*.hpp ${CMAKE_SOURCE_DIR}/src/*.cpp)
#add_executable(__refactor_target ${__SOURCES})
#target_link_libraries(__refactor_target memgraph_lib stdc++fs Threads::Threads ${fmt_static_lib} ${yaml_static_lib} ${antlr_static_lib} antlr_opencypher_parser_lib dl)
#add_dependencies(__refactor_target generate_opencypher_parser)

View File

@ -837,6 +837,7 @@ EXCLUDE_PATTERNS += */libs/*
EXCLUDE_PATTERNS += */release/*
EXCLUDE_PATTERNS += */Testing/*
EXCLUDE_PATTERNS += */tests/*
EXCLUDE_PATTERNS += */dist/*
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the

View File

@ -1,139 +0,0 @@
# -----------------------------------------------------------------------------
# COPY header files required by query engine (query compiler)
# TODO: create a copy function, COPY_RELATIVE(base relative_path dst)
# TODO: somehow automate (in destination dir should be only required include files)
FILE(COPY ${include_dir}/database/graph_db.hpp DESTINATION ${build_include_dir}/database)
FILE(COPY ${include_dir}/storage/edge.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/edge_accessor.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/vertex.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/vertex_accessor.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/record_accessor.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/locking/record_lock.hpp DESTINATION ${build_include_dir}/storage/locking)
FILE(COPY ${include_dir}/storage/locking/lock_status.hpp DESTINATION ${build_include_dir}/storage/locking)
FILE(COPY ${include_dir}/query/util.hpp DESTINATION ${build_include_dir}/query)
FILE(COPY ${include_dir}/query/plan_interface.hpp DESTINATION ${build_include_dir}/query)
FILE(COPY ${include_dir}/query/stripper.hpp DESTINATION ${build_include_dir}/query)
FILE(COPY ${include_dir}/data_structures/concurrent/concurrent_map.hpp DESTINATION ${build_include_dir}/data_structures/concurrent)
FILE(COPY ${include_dir}/data_structures/concurrent/concurrent_set.hpp DESTINATION ${build_include_dir}/data_structures/concurrent)
FILE(COPY ${include_dir}/data_structures/concurrent/concurrent_list.hpp DESTINATION ${build_include_dir}/data_structures/concurrent)
FILE(COPY ${include_dir}/data_structures/concurrent/common.hpp DESTINATION ${build_include_dir}/data_structures/concurrent)
FILE(COPY ${include_dir}/data_structures/concurrent/skiplist.hpp DESTINATION ${build_include_dir}/data_structures/concurrent)
FILE(COPY ${include_dir}/data_structures/concurrent/skiplist_gc.hpp DESTINATION ${build_include_dir}/data_structures/concurrent)
FILE(COPY ${include_dir}/data_structures/map/rh_hashmultimap.hpp DESTINATION ${build_include_dir}/data_structures/map)
FILE(COPY ${include_dir}/data_structures/map/rh_common.hpp DESTINATION ${build_include_dir}/data_structures/map)
FILE(COPY ${include_dir}/data_structures/bitset/dynamic_bitset.hpp DESTINATION ${build_include_dir}/data_structures/bitset)
FILE(COPY ${include_dir}/threading/sync/lockable.hpp DESTINATION ${build_include_dir}/threading/sync)
FILE(COPY ${include_dir}/threading/sync/spinlock.hpp DESTINATION ${build_include_dir}/threading/sync)
FILE(COPY ${include_dir}/threading/sync/futex.hpp DESTINATION ${build_include_dir}/threading/sync)
FILE(COPY ${include_dir}/threading/sync/lock_timeout_error.hpp DESTINATION ${build_include_dir}/threading/sync)
FILE(COPY ${include_dir}/memory/freelist.hpp DESTINATION ${build_include_dir}/memory)
FILE(COPY ${include_dir}/memory/lazy_gc.hpp DESTINATION ${build_include_dir}/memory)
FILE(COPY ${include_dir}/mvcc/cre_exp.hpp DESTINATION ${build_include_dir}/mvcc)
FILE(COPY ${include_dir}/mvcc/hints.hpp DESTINATION ${build_include_dir}/mvcc)
FILE(COPY ${include_dir}/mvcc/id.hpp DESTINATION ${build_include_dir}/mvcc)
FILE(COPY ${include_dir}/mvcc/mvcc_error.hpp DESTINATION ${build_include_dir}/mvcc)
FILE(COPY ${include_dir}/mvcc/record.hpp DESTINATION ${build_include_dir}/mvcc)
FILE(COPY ${include_dir}/mvcc/serialization_error.hpp DESTINATION ${build_include_dir}/mvcc)
FILE(COPY ${include_dir}/mvcc/version.hpp DESTINATION ${build_include_dir}/mvcc)
FILE(COPY ${include_dir}/mvcc/version_list.hpp DESTINATION ${build_include_dir}/mvcc)
FILE(COPY ${include_dir}/transactions/transaction.hpp DESTINATION ${build_include_dir}/transactions)
FILE(COPY ${include_dir}/transactions/lock_store.hpp DESTINATION ${build_include_dir}/transactions)
FILE(COPY ${include_dir}/transactions/snapshot.hpp DESTINATION ${build_include_dir}/transactions)
FILE(COPY ${include_dir}/transactions/commit_log.hpp DESTINATION ${build_include_dir}/transactions)
FILE(COPY ${include_dir}/transactions/engine.hpp DESTINATION ${build_include_dir}/transactions)
FILE(COPY ${include_dir}/transactions/transaction_store.hpp DESTINATION ${build_include_dir}/transactions)
FILE(COPY ${include_dir}/transactions/transaction_read.hpp DESTINATION ${build_include_dir}/transactions)
FILE(COPY ${include_dir}/storage/typed_value.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/typed_value_store.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/typed_value_utils.hpp DESTINATION ${build_include_dir}/storage)
FILE(COPY ${include_dir}/storage/garbage/delete_sensitive.hpp DESTINATION ${build_include_dir}/storage/garbage)
FILE(COPY ${include_dir}/storage/garbage/garbage.hpp DESTINATION ${build_include_dir}/storage/garbage)
FILE(COPY ${include_dir}/utils/string_buffer.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/handle_write.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/sys.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/char_str.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/void.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/array_store.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/bswap.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/stacktrace/stacktrace.hpp DESTINATION ${build_include_dir}/utils/stacktrace)
FILE(COPY ${include_dir}/utils/stacktrace/log.hpp DESTINATION ${build_include_dir}/utils/stacktrace)
FILE(COPY ${include_dir}/utils/auto_scope.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/assert.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/reference_wrapper.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/underlying_cast.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/total_ordering.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/crtp.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/placeholder.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/likely.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/cpu_relax.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/counters/atomic_counter.hpp DESTINATION ${build_include_dir}/utils/counters)
FILE(COPY ${include_dir}/utils/counters/simple_counter.hpp DESTINATION ${build_include_dir}/utils/counters)
FILE(COPY ${include_dir}/utils/random/fast_binomial.hpp DESTINATION ${build_include_dir}/utils/random)
FILE(COPY ${include_dir}/utils/random/xorshift128plus.hpp DESTINATION ${build_include_dir}/utils/random)
FILE(COPY ${include_dir}/utils/datetime/timestamp.hpp DESTINATION ${build_include_dir}/utils/datetime)
FILE(COPY ${include_dir}/utils/datetime/datetime_error.hpp DESTINATION ${build_include_dir}/utils/datetime)
FILE(COPY ${include_dir}/utils/types/byte.hpp DESTINATION ${build_include_dir}/utils/types)
FILE(COPY ${include_dir}/utils/option_ptr.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/option.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/border.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/order.hpp DESTINATION ${build_include_dir}/utils)
FILE(COPY ${include_dir}/utils/numerics/saturate.hpp DESTINATION ${build_include_dir}/utils/numerics)
FILE(COPY ${include_dir}/utils/memory/stack_allocator.hpp DESTINATION ${build_include_dir}/utils/memory)
FILE(COPY ${include_dir}/utils/memory/block_allocator.hpp DESTINATION ${build_include_dir}/utils/memory)
FILE(COPY ${include_dir}/utils/exceptions/basic_exception.hpp DESTINATION ${build_include_dir}/utils/exceptions)
FILE(COPY ${include_dir}/utils/exceptions/out_of_memory.hpp DESTINATION ${build_include_dir}/utils/exceptions)
FILE(COPY ${include_dir}/utils/iterator/iterator_base.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/virtual_iter.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/iterator.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/composable.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/count.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/accessor.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/combined.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/count.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/filter.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/flat_map.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/for_all.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/inspect.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/iterator_accessor.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/lambda_iterator.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/limited_map.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/map.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/utils/iterator/range_iterator.hpp DESTINATION ${build_include_dir}/utils/iterator)
FILE(COPY ${include_dir}/communication/communication.hpp DESTINATION ${build_include_dir}/communication)
FILE(COPY ${include_dir}/communication/bolt/v1/config.hpp DESTINATION ${build_include_dir}/communication/bolt/v1)
FILE(COPY ${include_dir}/communication/bolt/v1/serialization/record_stream.hpp DESTINATION ${build_include_dir}/communication/bolt/v1/serialization)
FILE(COPY ${include_dir}/communication/bolt/v1/serialization/bolt_serializer.hpp DESTINATION ${build_include_dir}/communication/bolt/v1/serialization)
FILE(COPY ${include_dir}/communication/bolt/v1/transport/bolt_encoder.hpp DESTINATION ${build_include_dir}/communication/bolt/v1/transport)
FILE(COPY ${include_dir}/communication/bolt/v1/transport/chunked_buffer.hpp DESTINATION ${build_include_dir}/communication/bolt/v1/transport)
FILE(COPY ${include_dir}/communication/bolt/v1/transport/chunked_encoder.hpp DESTINATION ${build_include_dir}/communication/bolt/v1/transport)
FILE(COPY ${include_dir}/communication/bolt/v1/transport/socket_stream.hpp DESTINATION ${build_include_dir}/communication/bolt/v1/transport)
FILE(COPY ${include_dir}/communication/bolt/v1/transport/stream_error.hpp DESTINATION ${build_include_dir}/communication/bolt/v1/transport)
FILE(COPY ${include_dir}/communication/bolt/v1/packing/codes.hpp DESTINATION ${build_include_dir}/communication/bolt/v1/packing)
FILE(COPY ${include_dir}/communication/bolt/v1/messaging/codes.hpp DESTINATION ${build_include_dir}/communication/bolt/v1/messaging)
FILE(COPY ${include_dir}/io/network/socket.hpp DESTINATION ${build_include_dir}/io/network)
FILE(COPY ${include_dir}/io/network/addrinfo.hpp DESTINATION ${build_include_dir}/io/network)
FILE(COPY ${include_dir}/io/network/network_error.hpp DESTINATION ${build_include_dir}/io/network)
FILE(COPY ${include_dir}/io/network/socket.hpp DESTINATION ${build_include_dir}/io/network)
FILE(COPY ${include_dir}/logging/default.hpp DESTINATION ${build_include_dir}/logging)
FILE(COPY ${include_dir}/logging/log.hpp DESTINATION ${build_include_dir}/logging)
FILE(COPY ${include_dir}/logging/logger.hpp DESTINATION ${build_include_dir}/logging)
FILE(COPY ${include_dir}/logging/levels.hpp DESTINATION ${build_include_dir}/logging)
FILE(COPY ${include_dir}/logging/loggable.hpp DESTINATION ${build_include_dir}/logging)
FILE(COPY ${include_dir}/snapshot/snapshot_engine.hpp DESTINATION ${build_include_dir}/snapshot)
# -----------------------------------------------------------------------------

View File

@ -1,18 +0,0 @@
if (CMAKE_VERSION VERSION_LESS 3.2)
set(UPDATE_DISCONNECTED_IF_AVAILABLE "")
else()
set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1")
endif()
include(DownloadProject/DownloadProject)
download_project(
PROJ googlebenchmark
GIT_REPOSITORY https://github.com/google/benchmark.git
GIT_TAG master
${UPDATE_DISCONNECTED_IF_AVAILABLE}
)
add_subdirectory(${googlebenchmark_SOURCE_DIR} ${googlebenchmark_BINARY_DIR})
include_directories("${googlebenchmark_SOURCE_DIR}/include")

View File

@ -1,19 +0,0 @@
if (CMAKE_VERSION VERSION_LESS 3.2)
set(UPDATE_DISCONNECTED_IF_AVAILABLE "")
else()
set(UPDATE_DISCONNECTED_IF_AVAILABLE "UPDATE_DISCONNECTED 1")
endif()
include(DownloadProject/DownloadProject)
download_project(
PROJ googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
${UPDATE_DISCONNECTED_IF_AVAILABLE}
)
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})
include_directories("${googletest_SOURCE_DIR}/googletest/include")
include_directories("${googletest_SOURCE_DIR}/googlemock/include")

View File

@ -1,8 +0,0 @@
#!/bin/bash
# DownloadProject
git clone https://github.com/Crascit/DownloadProject
download_project_tag="master"
cd DownloadProject
git checkout ${download_project_tag}
cd ..

View File

@ -1,9 +0,0 @@
FROM python:3.5
COPY src/crash_analysis/server /server
RUN pip install -r /server/requirements.txt
WORKDIR /server
CMD python app.py

View File

@ -1,12 +0,0 @@
#include <iostream>
#include "utils/terminate_handler.hpp"
int main()
{
std::set_terminate(&terminate_handler);
throw std::runtime_error("runtime error");
return 0;
}

View File

@ -1,6 +0,0 @@
#pragma once
/* Memgraph communication protocol
* gate is the first name proposal for the protocol */
// TODO

View File

@ -1,3 +0,0 @@
#pragma once
/* TODO: HTTP & HTTPS implementations */

View File

@ -1,25 +0,0 @@
#pragma once
#include "io/network/socket.hpp"
namespace io
{
class TcpConnection
{
};
class EventLoop
{
public:
EventLoop()
{
}
private:
Even
};
}

View File

@ -1,12 +0,0 @@
#pragma once
namespace io
{
class StreamDispatcher
{
};
}

View File

@ -1,125 +0,0 @@
#pragma once
#include <cstring>
#include <uv.h>
#include "utils/memory/block_allocator.hpp"
namespace uv
{
template <size_t block_size>
class BlockBuffer
{
static BlockAllocator<block_size> allocator;
struct Block : public uv_buf_t
{
Block()
{
// acquire a new block of memory for this buffer
base = static_cast<char*>(allocator.acquire());
len = 0;
}
~Block()
{
// release the block of memory previously acquired
allocator.release(base);
}
size_t append(const char* data, size_t size)
{
// compute the remaining capacity for this block
auto capacity = block_size - len;
// if the capacity is smaller than the requested size, copy only
// up to the remaining capacity
if(size > capacity)
size = capacity;
std::memcpy(base + len, data, size);
len += size;
// return how much we've copied
return size;
}
};
public:
BlockBuffer()
{
// create the first buffer
buffers.emplace_back();
}
~BlockBuffer()
{
buffers.clear();
}
BlockBuffer(BlockBuffer&) = delete;
BlockBuffer(BlockBuffer&&) = delete;
size_t count() const
{
return buffers.size();
}
void clear()
{
// pop all buffers except for the first one since we need to allocate
// it again anyway so why not keep it in the first place
while(count() > 1)
buffers.pop_back();
// pretend we just allocated our first buffer and set it's length to 0
buffers.back().len = 0;
}
BlockBuffer& operator<<(const std::string& data)
{
append(data);
return *this;
}
void append(const std::string& data)
{
append(data.c_str(), data.size());
}
void append(const char* data, size_t size)
{
while(true)
{
// try to copy as much data as possible
auto copied = buffers.back().append(data, size);
// if we managed to copy everything, we're done
if(copied == size)
break;
// move the pointer past the copied part
data += copied;
// reduce the total size by the number of copied items
size -= copied;
// since we ran out of space, construct a new buffer
buffers.emplace_back();
}
}
operator uv_buf_t*()
{
return buffers.data();
}
private:
std::vector<Block> buffers;
};
template <size_t block_size>
BlockAllocator<block_size> BlockBuffer<block_size>::allocator;
}

View File

@ -1,10 +0,0 @@
#pragma once
#include <uv.h>
namespace uv
{
using callback_t = void (*)(uv_handle_t *);
}

View File

@ -1,32 +0,0 @@
#pragma once
#include <uv.h>
#include "core.hpp"
#include "uvloop.hpp"
namespace uv
{
class TcpStream
{
public:
TcpStream(UvLoop& loop);
template <typename T>
T* data();
template <typename T>
void data(T* value);
void close(callback_t callback);
operator uv_handle_t*();
operator uv_tcp_t*();
operator uv_stream_t*();
private:
uv_tcp_t stream;
};
}

View File

@ -1,7 +0,0 @@
#include "tcpstream.hpp"
#include "uvbuffer.hpp"
#include "uvloop.hpp"
#include "blockbuffer.hpp"
#include "tcpstream.inl"
#include "uvbuffer.inl"

View File

@ -1,16 +0,0 @@
#pragma once
#include <stdexcept>
#include <string>
namespace uv
{
class UvError : public std::runtime_error
{
public:
UvError(const std::string& message)
: std::runtime_error(message) {}
};
}

View File

@ -1,35 +0,0 @@
#pragma once
#include <string>
#include <uv.h>
namespace uv
{
class UvBuffer
{
public:
UvBuffer();
UvBuffer(size_t capacity);
UvBuffer(const std::string& data);
~UvBuffer();
size_t size() const noexcept;
size_t length() const noexcept;
void clear();
UvBuffer& append(const std::string& data);
UvBuffer& append(const char* data, size_t n);
UvBuffer& operator<<(const std::string& data);
operator uv_buf_t*();
private:
uv_buf_t buffer;
size_t capacity;
};
}

View File

@ -1,59 +0,0 @@
#pragma once
#include <memory>
#include <uv.h>
#include "uv_error.hpp"
namespace uv
{
class UvLoop final
{
public:
using sptr = std::shared_ptr<UvLoop>;
enum Mode {
Default = UV_RUN_DEFAULT,
Once = UV_RUN_ONCE,
NoWait = UV_RUN_NOWAIT
};
UvLoop()
{
uv_loop = uv_default_loop();
if(uv_loop == nullptr)
throw UvError("Failed to initialize libuv event loop");
}
~UvLoop()
{
uv_loop_close(uv_loop);
}
bool run(Mode mode)
{
return uv_run(uv_loop, static_cast<uv_run_mode>(mode));
}
bool alive()
{
return uv_loop_alive(uv_loop);
}
void stop()
{
uv_stop(uv_loop);
}
operator uv_loop_t*()
{
return uv_loop;
}
private:
uv_loop_t* uv_loop;
};
}

View File

@ -1,10 +0,0 @@
#pragma once
#include "query/ir/tree/node.hpp"
class Backend
{
public:
virtual void process(ir::Node *node) = 0;
virtual ~Backend() {}
};

View File

@ -1,40 +0,0 @@
#pragma once
#include <stdexcept>
#include <string>
#include "query/backend/backend.hpp"
class CodeGenerator : public Backend
{
private:
struct Code
{
public:
void println(const std::string &line)
{
code.append(line + "\n");
line_no++;
}
void save(const std::string &)
{
throw std::runtime_error("TODO: implementation");
}
void reset() { code = ""; }
std::string code;
uint64_t line_no;
};
protected:
Code code;
public:
void emit(const std::string &line) { code.println(line); }
void save(const std::string &path) { code.save(path); }
void reset() { code.reset(); }
};

View File

@ -1,22 +0,0 @@
#pragma once
#include "query/backend/code_generator.hpp"
/*
* Traverses the intermediate representation tree and generates
* C++ code.
*/
class CppCodeGenerator : public CodeGenerator
{
public:
CppCodeGenerator()
{
throw std::runtime_error("TODO: implementation");
}
void process(ir::Node *) override
{
throw std::runtime_error("TODO: implementation");
}
};

View File

@ -1,3 +0,0 @@
#pragma once
// TODO: implementation

View File

@ -1,222 +0,0 @@
#pragma once
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#include "utils/exceptions/not_yet_implemented.hpp"
#include "config/config.hpp"
#include "database/graph_db.hpp"
#include "logging/loggable.hpp"
#include "query/exception/query_engine.hpp"
#include "query/plan_compiler.hpp"
#include "query/plan_interface.hpp"
#include "query/preprocessor.hpp"
#include "utils/dynamic_lib.hpp"
#include "data_structures/concurrent/concurrent_map.hpp"
// TODO: replace with openCypher and Antlr
#include "query/frontend/cypher.hpp"
/**
* Responsible for query execution.
*
* Current Query Engine arhitecture:
* query -> query_stripper -> [plan_generator] -> [plan_compiler] -> execution
*
* @tparam Stream the query engine has to be aware of the Stream because Stream
* is passed to the dynamic shared library because that is the way how
* the results should be returned (more optimal then just return
* the whole result set)
*/
template <typename Stream>
class QueryEngine : public Loggable
{
private:
using QueryPlanLib = DynamicLib<QueryPlanTrait<Stream>>;
public:
QueryEngine() : Loggable("QueryEngine") {}
/**
* Reloads query plan (plan_path contains compiled query plan).
* This methdo just calculates stripped query and offloads everything else
* to the LoadCpp method.
*
* @param query a query for which the plan will be loaded
* @param plan_path a custom made cpp query plan
*
* @return void
*/
auto ReloadCustom(const std::string &query, const fs::path &plan_path)
{
auto preprocessed = preprocessor.preprocess(query);
Unload(query);
LoadCpp(plan_path, preprocessed.hash);
}
/**
* Executes query on the database with the stream. If a query plan is cached
* (based on query hash) it will be used.
*
* @param query a query that is going to be executed
* @param db database againt the query is going to be executed
* @param stream the resuts will be send to the stream
*
* @return query execution status:
* false if query wasn't executed successfully
* true if query execution was successfull
*/
auto Run(const std::string &query, GraphDbAccessor &db_accessor, Stream &stream)
{
try
{
auto preprocessed = preprocessor.preprocess(query);
auto plan = LoadCypher(preprocessed);
auto result = plan->run(db_accessor, preprocessed.arguments, stream);
if (UNLIKELY(!result))
{
// info because it might be something like deadlock in which
// case one thread is stopped and user has try again
logger.info(
"Unable to execute query (execution returned false)");
}
return result;
}
catch (CypherLexicalError &e)
{
logger.error("CypherLexicalError: {}", std::string(e.what()));
throw e;
}
catch (QueryEngineException &e)
{
logger.error("QueryEngineException: {}", std::string(e.what()));
throw e;
}
catch (std::exception &e)
{
throw BasicException(e.what());
}
catch (...)
{
throw BasicException("unknown query engine exception");
}
}
/**
* Unloads query plan and release the resources (should be automatically).
*
* @param query a query for which the query plan will be unloaded.
*
* return bool is the plan unloaded
*/
auto Unload(const std::string &query)
{
return query_plans.access().remove(preprocessor.preprocess(query).hash);
}
/**
* Checks is a plan for the query loaded.
*
* @param query for which a plan existance will be checked
*
* return bool
*/
auto Loaded(const std::string &query)
{
auto plans_accessor = query_plans.access();
return plans_accessor.find(preprocessor.preprocess(query).hash) !=
plans_accessor.end();
}
/**
* The number of loaded query plans.
*
* @return size_t the number of loaded query plans
*/
auto Size() { // TODO: const once whan ConcurrentMap::Accessor becomes const
return query_plans.access().size();
}
// return query_plans.access().size(); }
private:
/**
* Loads query plan eather from hardcoded folder or from the file that is
* generated in this method.
*
* @param stripped a stripped query
*
* @return runnable query plan
*/
auto LoadCypher(const StrippedQuery &stripped)
{
auto plans_accessor = query_plans.access();
// code is already compiled and loaded, just return runnable
// instance
auto query_plan_it = plans_accessor.find(stripped.hash);
if (query_plan_it != plans_accessor.end())
return query_plan_it->second->instance();
// find hardcoded query plan if exists
auto hardcoded_path =
fs::path(CONFIG(config::COMPILE_PATH) + "hardcode/" +
std::to_string(stripped.hash) + ".cpp");
if (fs::exists(hardcoded_path))
return LoadCpp(hardcoded_path, stripped.hash);
// generate query plan
auto generated_path =
fs::path(CONFIG(config::COMPILE_PATH) + std::to_string(stripped.hash) + ".cpp");
// TODO implement CPP generator
// plan_generator.generate_plan(stripped.query, stripped.hash, generated_path);
throw NotYetImplemented();
return LoadCpp(generated_path, stripped.hash);
}
/**
* Load cpp query plan from a file. Or if plan is already cached from the
* cache.
*
* @param path_cpp a path to query plan
* @param hash query hash
*
* @return runnable query plan
*/
auto LoadCpp(const fs::path &path_cpp, const HashType hash)
{
auto plans_accessor = query_plans.access();
// code is already compiled and loaded, just return runnable
// instance
auto query_plan_it = plans_accessor.find(hash);
if (query_plan_it != plans_accessor.end())
return query_plan_it->second->instance();
// generate dynamic lib path
// The timestamp has been added here because dlopen
// uses path and returns the same handler for the same path
// and that is a problem because at this point we want brand new
// dynamic lib. That is the tmp solution. The right solution would be
// to deal with this problem in DynamicLib
auto path_so = CONFIG(config::COMPILE_PATH) + std::to_string(hash) +
"_" + (std::string)Timestamp::now() + ".so";
plan_compiler.compile(path_cpp, path_so);
auto query_plan = std::make_unique<QueryPlanLib>(path_so);
// TODO: underlying object has to be live during query execution
// fix that when Antler will be introduced into the database
auto query_plan_instance = query_plan->instance(); // because of move
plans_accessor.insert(hash, std::move(query_plan));
// return an instance of runnable code (PlanInterface)
return query_plan_instance;
}
QueryPreprocessor preprocessor;
PlanCompiler plan_compiler;
ConcurrentMap<HashType, std::unique_ptr<QueryPlanLib>>
query_plans;
};

View File

@ -1,33 +0,0 @@
#pragma once
#include <string>
#include "logging/loggable.hpp"
#include "query/language/cypher/compiler.hpp"
// DEPRICATED
namespace cypher
{
class Frontend
{
public:
Frontend() {}
auto generate_ir(const std::string& query)
{
try {
return compiler.syntax_tree(query);
} catch (const BasicException &e) {
// logger.error("Parsing error while processing query: {}", query);
// logger.error(std::string(e.what()));
throw e;
}
}
private:
cypher::Compiler compiler;
};
}

View File

@ -1,611 +0,0 @@
#pragma once
#include <string>
#include "logging/default.hpp"
#include "query/backend/cpp_old/code.hpp"
#include "query/backend/cpp_old/cpp_generator.hpp"
#include "query/backend/cpp_old/entity_search.hpp"
#include "query/backend/cpp_old/structures.hpp"
#include "query/language/cypher/errors.hpp"
#include "query/language/cypher/visitor/traverser.hpp"
struct SetElementState
{
std::string set_entity;
std::string set_prop;
int64_t set_index;
SetElementState() { clear(); }
bool is_defined() const
{
if (set_entity.empty()) return false;
if (set_prop.empty()) return false;
if (set_index < 0) return false;
return true;
}
void clear()
{
set_entity = "";
set_prop = "";
set_index = -1;
}
};
struct PropertyState
{
std::string property_name;
int64_t property_index;
PropertyState() { clear(); }
bool is_defined() const
{
if (property_name.empty()) return false;
if (property_index < 0) return false;
return true;
}
void clear()
{
property_name = "";
property_index = -1;
}
};
// TODO: another idea is to user ast history in order to choose appropriate
// action
class CppTraverser : public Traverser, public Code
{
private:
// currently active entity name (node or relationship name)
std::string entity;
// currently active state
CypherState state; // TODO: move to generator
QueryAction query_action;
ClauseAction clause_action;
// linearization
CppGenerator generator;
Vector<std::string> visited_nodes;
RelationshipData::Direction direction;
SetElementState set_element_state;
LabelSetElement labels_set_element;
PropertyState property_state;
void clear_state()
{
set_element_state.clear();
property_state.clear();
}
// for the first release every query has to have a RETURN clause
// problem is where to put t.commit()
// TODO: remove this constraint
bool has_return;
void finish_query_execution()
{
generator.add_action(QueryAction::TransactionCommit);
code += generator.generate();
generator.clear();
}
Logger logger;
public:
CppTraverser() : logger(logging::log->logger("CppTraverser")) {}
void semantic_check() const
{
if (!has_return)
throw CypherSemanticError(
"The query doesn't have RETURN clause. Next "
"releases will support query without RETURN "
"clause");
}
void visit(ast::WriteQuery &write_query) override
{
// TODO: crate top level node (TransactionBegin can be
// only at the one place)
generator.add_action(QueryAction::TransactionBegin);
Traverser::visit(write_query);
// TODO: put this inside the top level mentioned above
finish_query_execution();
}
void visit(ast::ReadQuery &read_query) override
{
generator.add_action(QueryAction::TransactionBegin);
Traverser::visit(read_query);
finish_query_execution();
}
void visit(ast::UpdateQuery &update_query) override
{
generator.add_action(QueryAction::TransactionBegin);
Traverser::visit(update_query);
finish_query_execution();
}
void visit(ast::DeleteQuery &delete_query) override
{
generator.add_action(QueryAction::TransactionBegin);
Traverser::visit(delete_query);
finish_query_execution();
}
void visit(ast::ReadWriteQuery &read_write_query) override
{
generator.add_action(QueryAction::TransactionBegin);
Traverser::visit(read_write_query);
finish_query_execution();
}
void visit(ast::Match &ast_match) override
{
state = CypherState::Match;
generator.add_action(QueryAction::Match);
Traverser::visit(ast_match);
}
void visit(ast::Where &ast_where) override
{
state = CypherState::Where;
Traverser::visit(ast_where);
}
void visit(ast::Create &ast_create) override
{
code += generator.generate();
generator.add_action(QueryAction::Create);
state = CypherState::Create;
query_action = QueryAction::Create;
Traverser::visit(ast_create);
}
void visit(ast::Set &ast_set) override
{
code += generator.generate();
generator.add_action(QueryAction::Set);
state = CypherState::Set;
query_action = QueryAction::Set;
Traverser::visit(ast_set);
code += generator.generate();
}
void visit(ast::Return &ast_return) override
{
has_return = true;
generator.add_action(QueryAction::Return);
state = CypherState::Return;
query_action = QueryAction::Return;
Traverser::visit(ast_return);
}
void visit(ast::ReturnList &ast_return_list) override
{
Traverser::visit(ast_return_list);
}
void visit(ast::PatternList &ast_pattern_list) override
{
Traverser::visit(ast_pattern_list);
}
void visit(ast::Pattern &ast_pattern) override
{
// TODO: Is that traversal order OK for all cases? Probably NOT.
if (ast_pattern.has_next())
{
visit(*ast_pattern.next);
visit(*ast_pattern.node);
visit(*ast_pattern.relationship);
}
else
{
Traverser::visit(ast_pattern);
}
}
void visit(ast::Node &ast_node) override
{
auto &action_data = generator.action_data();
auto &cypher_data = generator.cypher_data();
if (!ast_node.has_identifier()) return;
auto name = ast_node.idn->name;
entity = name;
visited_nodes.push_back(name);
if (state == CypherState::Match)
{
action_data.actions[name] = ClauseAction::MatchNode;
}
if (state == CypherState::Create)
{
if (cypher_data.status(name) == EntityStatus::Matched)
{
action_data.actions[name] = ClauseAction::MatchNode;
}
else
{
action_data.actions[name] = ClauseAction::CreateNode;
}
}
Traverser::visit(ast_node);
if (cypher_data.status(name) != EntityStatus::Matched &&
state == CypherState::Create)
{
cypher_data.node_created(name);
}
}
void visit(ast::And &ast_and) override { Traverser::visit(ast_and); }
void visit(ast::InternalIdExpr &internal_id_expr) override
{
if (!internal_id_expr.has_entity()) return;
if (!internal_id_expr.has_id()) return;
auto name = internal_id_expr.entity_name();
// because entity_id value will be index inside the parameters array
auto index = internal_id_expr.entity_id();
auto &data = generator.action_data();
data.parameter_index[ParameterIndexKey(InternalId, name)] = index;
data.csm.search_cost(name, entity_search::search_internal_id,
entity_search::internal_id_cost);
}
// -- RELATIONSHIP --
void create_relationship(const std::string &name)
{
auto &data = generator.action_data();
data.actions[name] = ClauseAction::CreateRelationship;
auto nodes = visited_nodes.last_two();
data.relationship_data.emplace(name,
RelationshipData(nodes, direction));
}
void visit(ast::Relationship &ast_relationship) override
{
auto &cypher_data = generator.cypher_data();
auto &action_data = generator.action_data();
if (!ast_relationship.has_name()) return;
entity = ast_relationship.name();
using ast_direction = ast::Relationship::Direction;
using generator_direction = RelationshipData::Direction;
if (ast_relationship.direction == ast_direction::Left)
direction = generator_direction::Left;
if (ast_relationship.direction == ast_direction::Right)
direction = generator_direction::Right;
// TODO: add suport for Direction::Both
// TODO: simplify somehow
if (state == CypherState::Create)
{
if (!cypher_data.exist(entity))
{
clause_action = ClauseAction::CreateRelationship;
create_relationship(entity);
}
}
if (state == CypherState::Match)
{
if (!cypher_data.exist(entity))
{
action_data.actions[entity] = ClauseAction::MatchRelationship;
}
}
Traverser::visit(ast_relationship);
}
void visit(ast::RelationshipSpecs &ast_relationship_specs) override
{
if (state == CypherState::Match)
{
if (ast_relationship_specs.has_identifier())
{
auto name = ast_relationship_specs.name();
auto &cypher_data = generator.cypher_data();
if (!cypher_data.exist(name))
{
clause_action = ClauseAction::MatchRelationship;
auto &data = generator.action_data();
data.actions[name] = ClauseAction::MatchRelationship;
}
}
}
if (state == CypherState::Create)
{
if (ast_relationship_specs.has_identifier())
{
entity = ast_relationship_specs.name();
}
}
Traverser::visit(ast_relationship_specs);
}
void visit(ast::RelationshipTypeList &ast_relationship_type_list) override
{
auto &action_data = generator.action_data();
if (ast_relationship_type_list.has_value())
{
auto type = ast_relationship_type_list.value->name;
action_data.add_entity_tag(entity, type);
action_data.csm.search_cost(entity,
entity_search::search_type_index,
entity_search::type_cost);
}
Traverser::visit(ast_relationship_type_list);
}
void visit(ast::LabelList &ast_label_list) override
{
if (state == CypherState::Set)
{
clause_action = ClauseAction::UpdateEntityLabels_Labels;
Traverser::visit(ast_label_list);
return;
}
auto &action_data = generator.action_data();
auto &cypher_data = generator.cypher_data();
if (!ast_label_list.has_value()) return;
auto label = ast_label_list.value->name;
action_data.add_entity_tag(entity, label);
action_data.csm.search_cost(entity, entity_search::search_label_index,
entity_search::label_cost);
cypher_data.tag(entity, label);
// TODO: it shouldn't be decided here
cypher_data.source(entity, EntitySource::LabelIndex);
Traverser::visit(ast_label_list);
}
void visit(ast::PropertyList &ast_property_list) override
{
Traverser::visit(ast_property_list);
}
void visit(ast::Property &ast_property) override
{
clear_state();
Traverser::visit(ast_property);
// TODO: too ugly refactor somehow (clear_state part is awful)
if (entity.empty() || !property_state.is_defined())
{
clear_state();
return;
}
auto prop = property_state.property_name;
auto index = property_state.property_index;
// update action data
auto &action_data = generator.action_data();
action_data.parameter_index.emplace(ParameterIndexKey(entity, prop),
index);
action_data.add_entitiy_property(entity, prop);
// update cypher data
auto &cypher_data = generator.cypher_data();
cypher_data.index(entity, prop, index);
clear_state();
}
void visit(ast::Identifier &ast_identifier) override
{
property_state.property_name = ast_identifier.name;
if (state == CypherState::Delete)
{
auto &action_data = generator.action_data();
auto name = ast_identifier.name;
auto &cypher_data = generator.cypher_data();
if (cypher_data.type(name) == EntityType::Node)
action_data.actions[name] = ClauseAction::DeleteNode;
if (cypher_data.type(name) == EntityType::Relationship)
action_data.actions[name] = ClauseAction::DeleteRelationship;
}
if (state == CypherState::Set &&
clause_action == ClauseAction::UpdateEntityLabels_Identifier)
{
labels_set_element.entity = ast_identifier.name;
}
if (state == CypherState::Set &&
clause_action == ClauseAction::UpdateEntityLabels_Labels)
{
labels_set_element.labels.emplace_back(ast_identifier.name);
}
}
void visit(ast::Long &ast_long) override
{
set_element_state.set_index = ast_long.value;
property_state.property_index = ast_long.value;
}
// -- SET subtree (node)
// QUERY: SET n.name = "bla", ...
// STRIP: SET n.name = 0, ...
// STATE: entity: n; prop: name; set_index: 0
void visit(ast::SetList &ast_set_list) override
{
Traverser::visit(ast_set_list);
}
void visit(ast::SetElement &ast_set_element) override
{
Traverser::visit(ast_set_element);
if (!set_element_state.is_defined())
{
clear_state();
return;
}
auto entity = set_element_state.set_entity;
auto prop = set_element_state.set_prop;
auto index = set_element_state.set_index;
auto &cypher_data = generator.cypher_data();
auto entity_type = cypher_data.type(entity);
if (entity_type == EntityType::None)
throw CypherSemanticError("Entity (" + entity + ") doesn't exist");
auto &action_data = generator.action_data();
if (entity_type == EntityType::Node)
action_data.actions[entity] = ClauseAction::UpdateNode;
if (entity_type == EntityType::Relationship)
action_data.actions[entity] = ClauseAction::UpdateRelationship;
action_data.parameter_index.emplace(ParameterIndexKey(entity, prop),
index);
action_data.add_entitiy_property(entity, prop);
clear_state();
}
void visit(ast::Accessor &ast_accessor) override
{
if (!ast_accessor.has_entity()) return;
auto &action_data = generator.action_data();
if (state == CypherState::Return)
{
auto &return_elements = action_data.return_elements;
auto &entity = ast_accessor.entity_name();
if (!ast_accessor.has_prop())
{
return_elements.emplace_back(ReturnElement(entity));
}
else
{
auto &property = ast_accessor.entity_prop();
return_elements.emplace_back(ReturnElement(entity, property));
}
}
if (!ast_accessor.has_prop()) return;
if (state == CypherState::Set)
{
set_element_state.set_entity = ast_accessor.entity_name();
set_element_state.set_prop = ast_accessor.entity_prop();
}
}
void visit(ast::SetValue &ast_set_value) override
{
Traverser::visit(ast_set_value);
}
void visit(ast::LabelSetElement &ast_label_set_element) override
{
clause_action = ClauseAction::UpdateEntityLabels_Identifier;
labels_set_element.clear();
Traverser::visit(ast_label_set_element);
auto &action_data = generator.action_data();
action_data.label_set_elements.emplace_back(std::move(labels_set_element));
clause_action = ClauseAction::Undefined;
}
void visit(ast::Delete &ast_delete) override
{
code += generator.generate();
state = CypherState::Delete;
auto &action_data = generator.add_action(QueryAction::Delete);
Traverser::visit(ast_delete);
code += generator.generate();
}
void visit(ast::CountFunction &ast_count) override
{
auto &action_data = generator.action_data();
auto &cypher_data = generator.cypher_data();
// if (state == CypherState::Return)
// {
action_data.actions[ast_count.argument] = ClauseAction::ReturnCount;
// }
}
void visit(ast::LabelsFunction &ast_label) override
{
auto &action_data = generator.action_data();
action_data.actions[ast_label.argument] = ClauseAction::ReturnLabels;
}
};

View File

@ -1,10 +0,0 @@
#pragma once
namespace opencypher
{
class Fronted
{
};
}

View File

@ -1,3 +0,0 @@
#pragma once
// TODO: implementation

View File

@ -1,8 +0,0 @@
*.o
cypher.cpp
cypher.h
cypher.hpp
parser
cypher.out
parser
sqlite.y

View File

@ -1,27 +0,0 @@
#pragma once
#include <memory>
#include <string>
#include "expr.hpp"
#include "identifier.hpp"
namespace ast
{
struct Accessor : public ValueExpr<Accessor>
{
Accessor(Identifier* entity, Identifier* prop)
: entity(entity), prop(prop) {}
Identifier* entity;
Identifier* prop;
bool has_entity() const { return entity != nullptr; }
bool has_prop() const { return prop != nullptr; }
std::string &entity_name() const { return entity->name; }
std::string &entity_prop() const { return prop->name; }
};
}

View File

@ -1,20 +0,0 @@
#pragma once
#include <string>
#include "ast_node.hpp"
namespace ast
{
// TODO: set identifier as base class
struct Alias : public AstNode<Alias>
{
Alias(std::string name, std::string alias)
: name(name), alias(alias) {}
std::string name;
std::string alias;
};
}

View File

@ -1,23 +0,0 @@
#pragma once
#include "accessor.hpp"
#include "values.hpp"
#include "identifier.hpp"
#include "alias.hpp"
#include "operators.hpp"
#include "property.hpp"
#include "relationship.hpp"
#include "node.hpp"
#include "distinct.hpp"
#include "return.hpp"
#include "pattern.hpp"
#include "return.hpp"
#include "delete.hpp"
#include "match.hpp"
#include "queries.hpp"
#include "start.hpp"
#include "set.hpp"
#include "expr.hpp"
#include "with.hpp"
#include "functions.hpp"
#include "merge.hpp"

View File

@ -1,21 +0,0 @@
#pragma once
#include <iostream>
#include "ast_visitor.hpp"
#include "values.hpp"
namespace ast
{
class AstEcho : public AstVisitor
{
public:
virtual void visit(Boolean& node)
{
std::cout << "Boolean: " << node.value << std::endl;
}
};
}

View File

@ -1,30 +0,0 @@
#pragma once
#include <memory>
#include "utils/visitor/visitable.hpp"
#include "utils/crtp.hpp"
#include "ast_visitor.hpp"
namespace ast
{
struct AstVisitor;
struct AstVisitable : public Visitable<AstVisitor>
{
using uptr = std::unique_ptr<AstVisitable>;
};
template <class Derived>
struct AstNode : public Crtp<Derived>, public AstVisitable
{
using uptr = std::unique_ptr<Derived>;
void accept(AstVisitor& visitor) override
{
visitor.visit(this->derived());
}
};
}

View File

@ -1,97 +0,0 @@
#pragma once
#include "utils/visitor/visitor.hpp"
namespace ast
{
struct Identifier;
struct IdentifierList;
struct Alias;
// properties
struct Property;
struct PropertyList;
struct Accessor;
// values
struct Boolean;
struct Float;
struct Integer;
struct String;
struct Long;
// operators
struct And;
struct Or;
struct Lt;
struct Gt;
struct Ge;
struct Le;
struct Eq;
struct Ne;
struct Plus;
struct Minus;
struct Star;
struct Slash;
struct Rem;
// functions
struct CountFunction;
struct LabelsFunction;
struct RelationshipSpecs;
struct RelationshipTypeList;
struct Relationship;
struct Node;
struct LabelList;
struct Pattern;
struct PatternExpr;
struct PatternList;
struct Return;
struct ReturnList;
struct Distinct;
struct Create;
struct Merge;
struct Match;
struct Where;
struct Set;
struct Delete;
struct Start;
struct WriteQuery;
struct ReadQuery;
struct UpdateQuery;
struct DeleteQuery;
struct ReadWriteQuery;
struct MergeQuery;
struct SetKey;
struct SetValue;
struct SetElement;
struct LabelSetElement;
struct SetList;
struct WithList;
struct WithClause;
struct WithQuery;
struct InternalIdExpr;
struct AstVisitor
: public Visitor<
Accessor, Boolean, Float, Identifier, Alias, Integer, String,
Property, And, Or, Lt, Gt, Ge, Le, Eq, Ne, Plus, Minus, Star, Slash,
Rem, PropertyList, RelationshipTypeList, Relationship, Node,
RelationshipSpecs, LabelList, ReturnList, Pattern, PatternExpr,
PatternList, Match, ReadQuery, Start, Where, WriteQuery, Create,
Return, Distinct, Delete, DeleteQuery, UpdateQuery, Set, SetKey,
ReadWriteQuery, IdentifierList, WithList, WithClause, WithQuery, Long,
CountFunction, LabelsFunction, InternalIdExpr, SetValue, SetElement,
MergeQuery, Merge, LabelSetElement, SetList>
{
};
}

View File

@ -1,18 +0,0 @@
#pragma once
#include "ast_node.hpp"
#include "pattern.hpp"
#include "return.hpp"
namespace ast
{
struct Create : public AstNode<Create>
{
Create(Pattern* pattern)
: pattern(pattern) {}
Pattern* pattern;
};
}

View File

@ -1,18 +0,0 @@
#pragma once
#include "ast_node.hpp"
#include "identifier.hpp"
namespace ast
{
struct Delete : public AstNode<Delete>
{
Delete(Identifier* identifier, bool is_detached = false)
: identifier(identifier), is_detached(is_detached) {}
Identifier* identifier;
bool is_detached;
};
}

View File

@ -1,17 +0,0 @@
#pragma once
#include "ast_node.hpp"
#include "identifier.hpp"
namespace ast
{
struct Distinct : public AstNode<Distinct>
{
Distinct(Identifier* identifier)
: identifier(identifier) {}
Identifier* identifier;
};
}

View File

@ -1,57 +0,0 @@
#pragma once
#include "ast_node.hpp"
namespace ast
{
struct Expr : public AstVisitable
{
};
template <class Derived>
struct ValueExpr : public Crtp<Derived>, public Expr
{
using uptr = std::unique_ptr<Derived>;
virtual void accept(AstVisitor &visitor) { visitor.visit(this->derived()); }
};
template <class T, class Derived>
struct LeafExpr : public ValueExpr<Derived>
{
LeafExpr(T value) : value(value) {}
T value;
};
// T is argument type
template <class T, class Derived>
struct FunctionExpr : public ValueExpr<Derived>
{
FunctionExpr(const std::string& name, T argument) : name(name), argument(argument) {}
std::string name;
T argument;
};
template <class Derived>
struct BinaryExpr : public ValueExpr<Derived>
{
BinaryExpr(Expr *left, Expr *right) : left(left), right(right) {}
Expr *left;
Expr *right;
};
struct PatternExpr : public Expr
{
using uptr = std::unique_ptr<PatternExpr>;
PatternExpr(Pattern *pattern) : pattern(pattern) {}
virtual void accept(AstVisitor &visitor) { visitor.visit(*this); }
Pattern *pattern;
};
}

View File

@ -1,22 +0,0 @@
#pragma once
#include "expr.hpp"
namespace ast
{
struct CountFunction : public FunctionExpr<std::string, CountFunction>
{
CountFunction(const std::string &argument) : FunctionExpr("count", argument)
{
}
};
struct LabelsFunction : public FunctionExpr<std::string, LabelsFunction>
{
LabelsFunction(const std::string &argument) : FunctionExpr("labels", argument)
{
}
};
}

View File

@ -1,24 +0,0 @@
#pragma once
#include <string>
#include "ast_node.hpp"
#include "list.hpp"
namespace ast
{
struct Identifier : public AstNode<Identifier>
{
Identifier(std::string name)
: name(name) {}
std::string name;
};
struct IdentifierList : public List<Identifier, IdentifierList>
{
using List::List;
};
}

View File

@ -1,21 +0,0 @@
#pragma once
#include "ast_node.hpp"
namespace ast
{
template <class T, class Derived>
struct List : public AstNode<Derived>
{
List(T* value, Derived* next)
: value(value), next(next) {}
T* value;
Derived* next;
bool has_value() const { return value != nullptr; }
bool has_next() const { return next != nullptr; }
};
}

View File

@ -1,19 +0,0 @@
#pragma once
#include "ast_node.hpp"
#include "pattern.hpp"
#include "where.hpp"
namespace ast
{
struct Match : public AstNode<Match>
{
Match(PatternList* pattern_list, Where* where)
: pattern_list(pattern_list), where(where) {}
PatternList* pattern_list;
Where* where;
};
}

View File

@ -1,18 +0,0 @@
#pragma once
#include "ast_node.hpp"
#include "pattern.hpp"
#include "return.hpp"
namespace ast
{
struct Merge : public AstNode<Merge>
{
Merge(Pattern* pattern)
: pattern(pattern) {}
Pattern* pattern;
};
}

View File

@ -1,29 +0,0 @@
#pragma once
#include "list.hpp"
#include "identifier.hpp"
namespace ast
{
struct LabelList : public List<Identifier, LabelList>
{
using List::List;
};
struct Node : public AstNode<Node>
{
Node(Identifier* idn, LabelList* labels, PropertyList* props)
: idn(idn), labels(labels), props(props) {}
Identifier* idn;
LabelList* labels;
PropertyList* props;
bool has_identifier() const
{
return idn != nullptr;
}
};
}

View File

@ -1,73 +0,0 @@
#pragma once
#include "expr.hpp"
namespace ast
{
struct And : public BinaryExpr<And>
{
using BinaryExpr::BinaryExpr;
};
struct Or : public BinaryExpr<Or>
{
using BinaryExpr::BinaryExpr;
};
struct Lt : public BinaryExpr<Lt>
{
using BinaryExpr::BinaryExpr;
};
struct Gt : public BinaryExpr<Gt>
{
using BinaryExpr::BinaryExpr;
};
struct Ge : public BinaryExpr<Ge>
{
using BinaryExpr::BinaryExpr;
};
struct Le : public BinaryExpr<Le>
{
using BinaryExpr::BinaryExpr;
};
struct Eq : public BinaryExpr<Eq>
{
using BinaryExpr::BinaryExpr;
};
struct Ne : public BinaryExpr<Ne>
{
using BinaryExpr::BinaryExpr;
};
struct Plus : public BinaryExpr<Plus>
{
using BinaryExpr::BinaryExpr;
};
struct Minus : public BinaryExpr<Minus>
{
using BinaryExpr::BinaryExpr;
};
struct Star : public BinaryExpr<Star>
{
using BinaryExpr::BinaryExpr;
};
struct Slash : public BinaryExpr<Slash>
{
using BinaryExpr::BinaryExpr;
};
struct Rem : public BinaryExpr<Rem>
{
using BinaryExpr::BinaryExpr;
};
}

View File

@ -1,29 +0,0 @@
#pragma once
#include "ast_node.hpp"
#include "node.hpp"
#include "relationship.hpp"
namespace ast
{
struct Pattern : public AstNode<Pattern>
{
Pattern(Node *node, Relationship *relationship, Pattern *next)
: node(node), relationship(relationship), next(next)
{
}
Node *node;
Relationship *relationship;
Pattern *next;
bool has_node() const { return node != nullptr; }
bool has_relationship() const { return relationship != nullptr; }
bool has_next() const { return next != nullptr; }
};
struct PatternList : public List<Pattern, PatternList>
{
using List::List;
};
}

View File

@ -1,29 +0,0 @@
#pragma once
#include "list.hpp"
#include "identifier.hpp"
#include "expr.hpp"
namespace ast
{
struct Property : public AstNode<Property>
{
Property(Identifier* idn, Expr* value)
: idn(idn), value(value) {}
Identifier* idn;
Expr* value;
bool has_name() const { return idn != nullptr; }
bool has_value() const { return value != nullptr; }
std::string name() const { return idn->name; }
};
struct PropertyList : public List<Property, PropertyList>
{
using List::List;
};
}

View File

@ -1,87 +0,0 @@
#pragma once
#include "ast_node.hpp"
#include "create.hpp"
#include "delete.hpp"
#include "match.hpp"
#include "return.hpp"
#include "set.hpp"
#include "merge.hpp"
namespace ast
{
struct WriteQuery : public AstNode<WriteQuery>
{
WriteQuery(Create *create, Return *return_clause)
: create(create), return_clause(return_clause)
{
}
Create *create;
Return *return_clause;
};
struct ReadQuery : public AstNode<ReadQuery>
{
ReadQuery(Match *match, Return *return_clause)
: match(match), return_clause(return_clause)
{
}
Match *match;
Return *return_clause;
};
struct UpdateQuery : public AstNode<UpdateQuery>
{
UpdateQuery(Match *match_clause, Set *set_clause, Return *return_clause)
: match_clause(match_clause), set_clause(set_clause),
return_clause(return_clause)
{
}
Match *match_clause;
Set *set_clause;
Return *return_clause;
};
struct DeleteQuery : public AstNode<DeleteQuery>
{
DeleteQuery(Match *match, Delete *delete_clause)
: match(match), delete_clause(delete_clause)
{
}
Match *match;
Delete *delete_clause;
};
struct ReadWriteQuery : public AstNode<ReadWriteQuery>
{
ReadWriteQuery(Match *match_clause,
Create *create_clause, Return *return_clause)
: match_clause(match_clause),
create_clause(create_clause), return_clause(return_clause)
{
}
Match *match_clause;
Create *create_clause;
Return *return_clause;
};
struct MergeQuery : public AstNode<MergeQuery>
{
MergeQuery(Merge* merge_clause, Set* set_clause, Return* return_clause) :
merge_clause(merge_clause), set_clause(set_clause),
return_clause(return_clause)
{
}
Merge *merge_clause;
Set *set_clause;
Return *return_clause;
};
}

View File

@ -1,56 +0,0 @@
#pragma once
#include "identifier.hpp"
#include "list.hpp"
namespace ast
{
struct RelationshipTypeList : public List<Identifier, RelationshipTypeList>
{
using List::List;
};
struct RelationshipSpecs : public AstNode<RelationshipSpecs>
{
RelationshipSpecs(Identifier *idn, RelationshipTypeList *types,
PropertyList *props)
: idn(idn), types(types), props(props)
{
}
Identifier *idn;
RelationshipTypeList *types;
PropertyList *props;
bool has_identifier() const { return idn != nullptr; }
std::string name() const { return idn->name; }
};
struct Relationship : public AstNode<Relationship>
{
enum Direction
{
Left,
Right,
Both
};
Relationship(RelationshipSpecs *specs, Direction direction)
: specs(specs), direction(direction)
{
}
RelationshipSpecs *specs;
Direction direction;
bool has_relationship_specs() const { return specs != nullptr; }
bool has_name() const
{
return has_relationship_specs() && specs->has_identifier();
}
std::string name() const { return specs->name(); }
};
}

View File

@ -1,32 +0,0 @@
#pragma once
#include "list.hpp"
#include "expr.hpp"
#include "identifier.hpp"
#include "distinct.hpp"
namespace ast
{
struct ReturnList : public List<Expr, ReturnList>
{
using List::List;
};
struct Return : public AstNode<Return>
{
Return(ReturnList* return_list)
: return_list(return_list), distinct(nullptr)
{
}
Return(Distinct* distinct)
: return_list(nullptr), distinct(distinct)
{
}
ReturnList* return_list;
Distinct* distinct;
};
};

View File

@ -1,87 +0,0 @@
#pragma once
#include "accessor.hpp"
#include "list.hpp"
#include "expr.hpp"
namespace ast
{
//
// SetList
// ^
// |
// |------------------------------------|
// SetElement
// ^
// |
// |-------------------|
// Accessor SetValue
// ^ ^
// | |
// |-------| |-------|
// SET n.name = "Paul", n.surname = "Scholes"
// ^ ^
// | |
// element entity element property
//
struct SetValue : public AstNode<SetValue>
{
SetValue(Expr* value)
: value(value) {}
Expr* value;
bool has_value() const { return value != nullptr; }
};
struct SetElementBase : public AstVisitable
{
};
template <class Derived>
struct SetElementDerivedBase : public Crtp<Derived>, public SetElementBase
{
using uptr = std::unique_ptr<Derived>;
virtual void accept(AstVisitor &visitor) { visitor.visit(this->derived()); }
};
struct SetElement : public SetElementDerivedBase<SetElement>
{
SetElement(Accessor* accessor, SetValue* set_value)
: accessor(accessor), set_value(set_value) {}
Accessor* accessor;
SetValue* set_value;
bool has_accessor() const { return accessor != nullptr; }
bool has_value() const { return set_value != nullptr; }
};
struct LabelSetElement : public SetElementDerivedBase<LabelSetElement>
{
LabelSetElement(Identifier* identifier, LabelList* label_list)
: identifier(identifier), label_list(label_list) {}
Identifier* identifier;
LabelList* label_list;
bool has_identifier() const { return identifier != nullptr; }
bool has_label_list() const { return label_list != nullptr; }
};
struct SetList : public List<SetElementBase, SetList>
{
using List::List;
};
struct Set : public AstNode<Set>
{
Set(SetList* set_list)
: set_list(set_list) {}
SetList* set_list;
};
}

View File

@ -1,13 +0,0 @@
#pragma once
#include "ast_node.hpp"
#include "queries.hpp"
namespace ast
{
struct Start : public AstNode<Start>
{
};
};

View File

@ -1,56 +0,0 @@
#pragma once
#include <vector>
#include "ast_node.hpp"
namespace ast
{
class Ast
{
public:
Ast() = default;
Ast(const Ast&) = delete;
Ast(Ast&& other) : root(other.root), items(std::move(other.items))
{
other.root = nullptr;
}
Ast& operator=(Ast&& other)
{
// TODO: write this more appropriate
// here is CP of above code
if(this != &other) {
this->root = other.root;
other.root = nullptr;
this->items = std::move(other.items);
}
return *this;
}
AstVisitable* root;
void traverse(AstVisitor& visitor)
{
root->accept(visitor);
}
template <class T, typename... Args>
T* create(Args&&... args)
{
auto node = new T(std::forward<Args>(args)...);
items.push_back(std::unique_ptr<AstVisitable>(node));
return node;
}
private:
// basically a gc vector that destroys all ast nodes once this object is
// destroyed. parser generator is written in c and works only with raw
// pointers so this is what makes it leak free after the parser finishes
// parsing without using shared pointers
std::vector<AstVisitable::uptr> items;
};
}

View File

@ -1,61 +0,0 @@
#pragma once
#include <string>
#include "expr.hpp"
namespace ast
{
struct Float : public LeafExpr<double, Float>
{
using LeafExpr::LeafExpr;
};
struct Integer : public LeafExpr<int, Integer>
{
using LeafExpr::LeafExpr;
};
struct Long : public LeafExpr<int64_t, Long>
{
using LeafExpr::LeafExpr;
};
struct ULong : public LeafExpr<uint64_t, ULong>
{
using LeafExpr::LeafExpr;
};
struct Boolean : public LeafExpr<bool, Boolean>
{
using LeafExpr::LeafExpr;
};
struct String : public LeafExpr<std::string, String>
{
using LeafExpr::LeafExpr;
};
struct InternalIdExpr : public Expr
{
InternalIdExpr(Identifier *entity, Long *id)
: entity(entity), id(id)
{
}
Identifier *entity;
Long *id;
virtual void accept(AstVisitor &visitor) { visitor.visit(*this); }
bool has_entity() const { return entity != nullptr; }
bool has_id() const { return id != nullptr; }
std::string entity_name() const { return entity->name; }
int64_t entity_id() const { return id->value; }
};
}

View File

@ -1,17 +0,0 @@
#pragma once
#include "ast_node.hpp"
#include "expr.hpp"
namespace ast
{
struct Where : public AstNode<Where>
{
Where(Expr* expr)
: expr(expr) {}
Expr* expr;
};
}

View File

@ -1,41 +0,0 @@
#pragma once
#include <string>
#include "ast_node.hpp"
#include "identifier.hpp"
#include "match.hpp"
namespace ast
{
struct WithClause : public AstNode<WithClause>
{
WithClause(IdentifierList *identifier_list, Match *match_clause)
: identifier_list(identifier_list), match_clause(match_clause)
{
}
IdentifierList *identifier_list;
Match *match_clause;
};
struct WithList : public List<WithClause, WithList>
{
using List::List;
};
struct WithQuery : public AstNode<WithQuery>
{
WithQuery(Match *match_clause, WithList *with_list, Return *return_clause)
: match_clause(match_clause), with_list(with_list),
return_clause(return_clause)
{
}
Match *match_clause;
WithList *with_list;
Return *return_clause;
};
}

View File

@ -1,24 +0,0 @@
#pragma once
#include <vector>
#include "utils/command_line/arguments.hpp"
#include "utils/string/file.hpp"
auto extract_queries(const std::vector<std::string>& arguments)
{
std::vector<std::string> queries;
// load single query
if (contains_argument(arguments, "-q"))
{
queries.emplace_back(get_argument(arguments, "-q", "CREATE (n) RETURN n"));
return queries;
}
// load multiple queries from file
auto default_file = "queries.cypher";
auto file = get_argument(arguments, "-f", default_file);
return utils::read_lines(file.c_str());
}

View File

@ -1,26 +0,0 @@
#pragma once
#include "tokenizer/cypher_lexer.hpp"
#include "parser.hpp"
namespace cypher
{
class Compiler
{
public:
Compiler() = default;
ast::Ast syntax_tree(const std::string& input)
{
auto parser = cypher::Parser();
auto tokenizer = lexer.tokenize(input);
auto tree = parser.parse(tokenizer);
return tree;
}
private:
CypherLexer lexer;
};
}

View File

@ -1,589 +0,0 @@
/*
** This file contains memgraph's grammar for Cypher. Process this file
** using the lemon parser generator to generate C code that runs
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
*/
%token_prefix TK_
%token_type {Token*}
%extra_argument {ast::Ast* ast}
%syntax_error
{
#ifndef NDEBUG
int n = sizeof(yyTokenName) / sizeof(yyTokenName[0]);
for (int i = 0; i < n; ++i) {
int a = yy_find_shift_action(yypParser, (YYCODETYPE)i);
if (a < YYNSTATE + YYNRULE) {
printf("possible token: %s\n", yyTokenName[i]);
}
}
throw CypherSyntaxError(TOKEN->value);
#endif
}
%stack_overflow
{
throw CypherParsingError("Parser stack overflow");
}
%name cypher_parser
%include
{
#include <iostream>
#include <cassert>
#include <cstdlib>
#include "query/language/cypher/token.hpp"
#include "query/language/cypher/errors.hpp"
#include "query/language/cypher/ast/ast.hpp"
#include "query/language/cypher/ast/tree.hpp"
#define DEBUG(X) std::cout << "PARSER: " << X << std::endl
}
// define operator precedence
%left OR.
%left AND.
%right NOT.
%left IN IS_NULL IS_NOT_NULL NE EQ.
%left GT LE LT GE.
%left PLUS MINUS.
%left STAR SLASH REM.
// -- start structure
start ::= with_query(Q). {
ast->root = Q;
}
start ::= write_query(Q). {
ast->root = Q;
}
start ::= read_query(Q). {
ast->root = Q;
}
start ::= update_query(Q). {
ast->root = Q;
}
start ::= delete_query(Q). {
ast->root = Q;
}
start ::= read_write_query(Q). {
ast->root = Q;
}
start ::= merge_query(Q). {
ast->root = Q;
}
// -- merge query
%type merge_query {ast::MergeQuery*}
merge_query(MQ) ::= merge_clause(MC) set_clause(SC) return_clause(RC). {
MQ = ast->create<ast::MergeQuery>(MC, SC, RC);
}
merge_query(MQ) ::= merge_clause(MC) return_clause(RC). {
MQ = ast->create<ast::MergeQuery>(MC, nullptr, RC);
}
// -- with query
%type with_query {ast::WithQuery*}
with_query(WQ) ::= with_start_clause(SQ) with_list(WL) return_clause(RC). {
WQ = ast->create<ast::WithQuery>(SQ, WL, RC);
}
%type with_list {ast::WithList*}
with_list(L) ::= WITH with_clause(WC) with_list(N). {
L = ast->create<ast::WithList>(WC, N);
}
with_list(L) ::= . {
L = nullptr;
}
// TODO: replace Match with something that has Match, Create, etc.
%type with_start_clause {ast::Match*}
with_start_clause(WSC) ::= match_clause(MC). {
WSC = MC;
}
%type with_clause {ast::WithClause*}
with_clause(WC) ::= identifier_list(IL) with_match_clause(MC). {
WC = ast->create<ast::WithClause>(IL, MC);
}
%type with_match_clause {ast::Match*}
with_match_clause(WMC) ::= match_clause(M). {
WMC = M;
}
with_match_clause(WMC) ::= where_clause(WC). {
WMC = ast->create<ast::Match>(nullptr, WC);
}
// write query structure
%type write_query {ast::WriteQuery*}
write_query(WQ) ::= create_clause(C) return_clause(R). {
WQ = ast->create<ast::WriteQuery>(C, R);
}
write_query(WQ) ::= create_clause(C). {
WQ = ast->create<ast::WriteQuery>(C, nullptr);
}
// read query structure
%type read_query {ast::ReadQuery*}
read_query(RQ) ::= match_clause(M) return_clause(R). {
RQ = ast->create<ast::ReadQuery>(M, R);
}
// -- match create query
%type read_write_query {ast::ReadWriteQuery*}
read_write_query(Q) ::= match_clause(M) create_clause(C) return_clause(R). {
Q = ast->create<ast::ReadWriteQuery>(M, C, R);
}
read_write_query(Q) ::= match_clause(M) create_clause(C). {
Q = ast->create<ast::ReadWriteQuery>(M, C, nullptr);
}
// ---------------------
// update query structure
%type update_query {ast::UpdateQuery*}
update_query(UQ) ::= match_clause(M) set_clause(S) return_clause(R). {
UQ = ast->create<ast::UpdateQuery>(M, S, R);
}
update_query(UQ) ::= match_clause(M) set_clause(S). {
UQ = ast->create<ast::UpdateQuery>(M, S, nullptr);
}
// set clause
%type set_clause {ast::Set*}
set_clause(S) ::= SET set_list(L). {
S = ast->create<ast::Set>(L);
}
// delete query structure
%type delete_query {ast::DeleteQuery*}
delete_query(DQ) ::= match_clause(M) delete_clause(D). {
DQ = ast->create<ast::DeleteQuery>(M, D);
}
%type create_clause {ast::Create*}
create_clause(C) ::= CREATE pattern(P). {
C = ast->create<ast::Create>(P);
}
%type merge_clause {ast::Merge*}
merge_clause(M) ::= MERGE pattern(P). {
M = ast->create<ast::Merge>(P);
}
%type match_clause {ast::Match*}
match_clause(M) ::= MATCH pattern_list(P) where_clause(W). {
M = ast->create<ast::Match>(P, W);
}
%type delete_clause {ast::Delete*}
// TODO: expression list support
delete_clause(D) ::= DELETE idn(I). {
D = ast->create<ast::Delete>(I, false);
}
delete_clause(D) ::= DETACH DELETE idn(I). {
D = ast->create<ast::Delete>(I, true);
}
// ---- pattern list
%type pattern_list {ast::PatternList*}
pattern_list(L) ::= pattern(P) COMMA pattern_list(N). {
L = ast->create<ast::PatternList>(P, N);
}
pattern_list(L) ::= pattern(P). {
L = ast->create<ast::PatternList>(P, nullptr);
}
// ----
%type pattern {ast::Pattern*}
pattern(P) ::= node(N) rel(R) pattern(NEXT). {
P = ast->create<ast::Pattern>(N, R, NEXT);
}
pattern(P) ::= node(N). {
P = ast->create<ast::Pattern>(N, nullptr, nullptr);
}
// update query
// MATCH ... WITH ... SET ... RETURN
%type rel {ast::Relationship*}
rel(R) ::= MINUS rel_spec(S) MINUS. { // bidirectional
R = ast->create<ast::Relationship>(S, ast::Relationship::Both);
}
rel(R) ::= LT MINUS rel_spec(S) MINUS. { // left
R = ast->create<ast::Relationship>(S, ast::Relationship::Left);
}
rel(R) ::= MINUS rel_spec(S) MINUS GT. { // right
R = ast->create<ast::Relationship>(S, ast::Relationship::Right);
}
%type rel_spec {ast::RelationshipSpecs*}
rel_spec(R) ::= LSP rel_idn(I) rel_type(T) properties(P) RSP. {
R = ast->create<ast::RelationshipSpecs>(I, T, P);
}
rel_spec(R) ::= . {
R = nullptr;
}
%type rel_idn {ast::Identifier*}
rel_idn(R) ::= idn(I). {
R = I;
}
rel_idn(R) ::= . {
R = nullptr;
}
%type rel_type {ast::RelationshipTypeList*}
rel_type(L) ::= COLON rel_list(R). {
L = R;
}
rel_type(L) ::= . {
L = nullptr;
}
%type rel_list {ast::RelationshipTypeList*}
rel_list(L) ::= idn(I) PIPE rel_list(R). {
L = ast->create<ast::RelationshipTypeList>(I, R);
}
rel_list(L) ::= idn(I). {
L = ast->create<ast::RelationshipTypeList>(I, nullptr);
}
%type node {ast::Node*}
// node specification
node(N) ::= LP node_idn(I) label_idn(L) properties(P) RP. {
N = ast->create<ast::Node>(I, L, P);
}
%type node_idn {ast::Identifier*}
// a node identifier can be ommitted
node_idn(N) ::= idn(I). {
N = I;
}
node_idn(N) ::= . {
N = nullptr;
}
%type label_idn {ast::LabelList*}
// a label can be ommited or there can be more of them
label_idn(L) ::= COLON idn(I) label_idn(N). {
L = ast->create<ast::LabelList>(I, N);
}
label_idn(L) ::= . {
L = nullptr;
}
%type where_clause {ast::Where*}
// where clause
where_clause(W) ::= WHERE expr(E). {
W = ast->create<ast::Where>(E);
}
where_clause(W) ::= . {
W = nullptr;
}
%type return_clause {ast::Return*}
return_clause(R) ::= RETURN return_list(L). {
R = ast->create<ast::Return>(L);
}
return_clause(R) ::= RETURN distinct(D). {
R = ast->create<ast::Return>(D);
}
%type return_list {ast::ReturnList*}
return_list(R) ::= return_list(N) COMMA expr(E). {
R = ast->create<ast::ReturnList>(E, N);
}
return_list(R) ::= expr(E). {
R = ast->create<ast::ReturnList>(E, nullptr);
}
%type distinct {ast::Distinct*}
distinct(R) ::= DISTINCT idn(I). {
R = ast->create<ast::Distinct>(I);
}
// list of properties
// e.g. { name: "wayne", surname: "rooney"}
%type properties {ast::PropertyList*}
// '{' <property_list> '}'
properties(P) ::= LCP property_list(L) RCP. {
P = L;
}
properties(P) ::= . {
P = nullptr;
}
%type property_list {ast::PropertyList*}
// <property> [[',' <property>]]*
property_list(L) ::= property(P) COMMA property_list(N). {
L = ast->create<ast::PropertyList>(P, N);
}
property_list(L) ::= property(P). {
L = ast->create<ast::PropertyList>(P, nullptr);
}
%type property {ast::Property*}
// IDENTIFIER ':' <expression>
property(P) ::= idn(I) COLON value_expr(E). {
P = ast->create<ast::Property>(I, E);
}
%type value_expr {ast::Expr*}
value_expr(E) ::= value_expr(L) AND value_expr(R). {
E = ast->create<ast::And>(L, R);
}
value_expr(E) ::= value_expr(L) OR value_expr(R). {
E = ast->create<ast::Or>(L, R);
}
value_expr(E) ::= value_expr(L) LT value_expr(R). {
E = ast->create<ast::Lt>(L, R);
}
value_expr(E) ::= value_expr(L) GT value_expr(R). {
E = ast->create<ast::Gt>(L, R);
}
value_expr(E) ::= value_expr(L) GE value_expr(R). {
E = ast->create<ast::Ge>(L, R);
}
value_expr(E) ::= value_expr(L) LE value_expr(R). {
E = ast->create<ast::Le>(L, R);
}
value_expr(E) ::= value_expr(L) EQ value_expr(R). {
E = ast->create<ast::Eq>(L, R);
}
value_expr(E) ::= value_expr(L) NE value_expr(R). {
E = ast->create<ast::Ne>(L, R);
}
value_expr(E) ::= value_expr(L) PLUS value_expr(R). {
E = ast->create<ast::Plus>(L, R);
}
value_expr(E) ::= value_expr(L) MINUS value_expr(R). {
E = ast->create<ast::Minus>(L, R);
}
value_expr(E) ::= value_expr(L) STAR value_expr(R). {
E = ast->create<ast::Star>(L, R);
}
value_expr(E) ::= value_expr(L) SLASH value_expr(R). {
E = ast->create<ast::Slash>(L, R);
}
value_expr(E) ::= value_expr(L) REM value_expr(R). {
E = ast->create<ast::Rem>(L, R);
}
value_expr(E) ::= idn(I). {
E = ast->create<ast::Accessor>(I, nullptr);
}
value_expr(E) ::= idn(I) DOT idn(P). {
E = ast->create<ast::Accessor>(I, P);
}
value_expr(E) ::= ID LP idn(I) RP EQ LONG(V). {
auto value = std::stol(V->value);
E = ast->create<ast::InternalIdExpr>(I, ast->create<ast::Long>(value));
}
%type idn {ast::Identifier*}
idn(I) ::= IDN(X). {
I = ast->create<ast::Identifier>(X->value);
}
// ---- identifier list
%type identifier_list {ast::IdentifierList*}
identifier_list(L) ::= idn(I) COMMA identifier_list(N). {
L = ast->create<ast::IdentifierList>(I, N);
}
identifier_list(L) ::= idn(I). {
L = ast->create<ast::IdentifierList>(I, nullptr);
}
// ----
value_expr(E) ::= LONG(V). {
auto value = std::stol(V->value);
E = ast->create<ast::Long>(value);
}
value_expr(E) ::= FLOAT(V). {
auto value = std::stod(V->value);
E = ast->create<ast::Float>(value);
}
value_expr(E) ::= STR(V). {
auto value = V->value.substr(1, V->value.size() - 2);
E = ast->create<ast::String>(value);
}
value_expr(E) ::= BOOL(V). {
auto value = V->value[0] == 't' || V->value[0] == 'T' ? true : false;
E = ast->create<ast::Boolean>(value);
}
%type pattern_expr {ast::Expr*}
pattern_expr(E) ::= pattern(P). {
E = ast->create<ast::PatternExpr>(P);
}
%type function_expr {ast::Expr*}
function_expr(E) ::= COUNT LP IDN(A) RP. {
E = ast->create<ast::CountFunction>(A->value);
}
function_expr(E) ::= LABELS LP IDN(A) RP. {
E = ast->create<ast::LabelsFunction>(A->value);
}
%type expr {ast::Expr*}
expr(E) ::= value_expr(V). {
E = V;
}
expr(E) ::= pattern_expr(P). {
E = P;
}
expr(E) ::= function_expr(F). {
E = F;
}
//%type alias {ast::Alias*}
//
//alias(A) ::= IDN(X) AS IDN(Y). {
// A = ast->create<ast::Alias>(X->value, Y->value);
//}
// set list
// e.g. MATCH (n) SET n.name = "Ryan", n.surname = "Giggs" RETURN n
%type set_list {ast::SetList*}
set_list(L) ::= set_element(E) COMMA set_list(N). {
L = ast->create<ast::SetList>(E, N);
}
set_list(L) ::= set_element(E). {
L = ast->create<ast::SetList>(E, nullptr);
}
%type set_element {ast::SetElementBase*}
set_element(E) ::= accessor(A) EQ set_value(V). {
E = ast->create<ast::SetElement>(A, V);
}
set_element(E) ::= idn(I) label_idn(L). {
E = ast->create<ast::LabelSetElement>(I, L);
}
%type accessor {ast::Accessor*}
accessor(A) ::= idn(E) DOT idn(P). {
A = ast->create<ast::Accessor>(E, P);
}
%type set_value {ast::SetValue*}
set_value(V) ::= value_expr(E). {
V = ast->create<ast::SetValue>(E);
}

View File

@ -1,443 +0,0 @@
#pragma once
#include <iostream>
#include <stack>
#include "query/language/cypher/visitor/traverser.hpp"
class PrintVisitor : public Traverser
{
public:
class Printer
{
public:
friend class Entry;
Printer(std::ostream &stream, const std::string &header)
: stream(stream)
{
// stream << header;
}
~Printer() { stream << std::endl; }
class Entry
{
public:
explicit Entry(Printer &printer) : printer(printer), valid(true)
{
printer.level++;
for (size_t i = 1; i < printer.level; ++i)
printer.stream << "| ";
printer.stream << "+--";
}
Entry(const Entry &) = delete;
Entry(Entry &&other) : printer(other.printer), valid(true)
{
other.valid = false;
}
~Entry()
{
if (valid) printer.level--;
}
template <class T>
Entry &operator<<(const T &item)
{
printer.stream << item;
return *this;
}
private:
Printer &printer;
bool valid;
};
Entry advance()
{
stream << std::endl;
return std::move(Entry(*this));
}
Entry advance(const std::string &text)
{
stream << std::endl;
auto entry = Entry(*this);
entry << text;
return std::move(entry);
}
private:
std::ostream &stream;
size_t level = 0;
};
explicit PrintVisitor(std::ostream &stream)
: printer(stream, "Printing AST") {}
void visit(ast::Start &start) override
{
auto entry = printer.advance("Start");
Traverser::visit(start);
}
void visit(ast::ReadQuery &read_query) override
{
auto entry = printer.advance("Read Query");
Traverser::visit(read_query);
}
void visit(ast::ReadWriteQuery &query) override
{
auto entry = printer.advance("Read Write Query");
Traverser::visit(query);
}
void visit(ast::Match &match) override
{
auto entry = printer.advance("Match");
Traverser::visit(match);
}
void visit(ast::Pattern &pattern) override
{
auto entry = printer.advance("Pattern");
Traverser::visit(pattern);
}
void visit(ast::PatternExpr &pattern_expr) override
{
auto entry = printer.advance("Pattern Expression");
Traverser::visit(pattern_expr);
}
void visit(ast::PatternList &pattern_list) override
{
auto entry = printer.advance("Pattern List");
Traverser::visit(pattern_list);
}
void visit(ast::Node &node) override
{
auto entry = printer.advance("Node");
Traverser::visit(node);
}
void visit(ast::Alias &alias) override
{
auto entry = printer.advance();
entry << "Alias: '" << alias.name << "' AS '" << alias.alias << "'";
}
void visit(ast::Identifier &idn) override
{
auto entry = printer.advance();
entry << "Identifier '" << idn.name << "'";
}
void visit(ast::IdentifierList &list) override
{
auto entry = printer.advance("Identifier List");
Traverser::visit(list);
}
void visit(ast::Return &return_clause) override
{
auto entry = printer.advance("Return");
Traverser::visit(return_clause);
}
void visit(ast::Distinct &distinct) override
{
auto entry = printer.advance("Distinct");
Traverser::visit(distinct);
}
void visit(ast::Accessor &accessor) override
{
auto entry = printer.advance("Accessor");
Traverser::visit(accessor);
}
void visit(ast::Boolean &boolean) override
{
auto entry = printer.advance();
entry << "Boolean " << boolean.value;
}
void visit(ast::Float &floating) override
{
auto entry = printer.advance();
entry << "Float " << floating.value;
}
void visit(ast::Integer &integer) override
{
auto entry = printer.advance();
entry << "Integer " << integer.value;
}
void visit(ast::Long &ast_long) override
{
auto entry = printer.advance();
entry << "Long " << ast_long.value;
}
// void visit(ast::ULong& ulong) override
// {
// auto entry = printer.advance();
// entry << "ULong " << ulong.value;
// }
void visit(ast::String &string) override
{
auto entry = printer.advance();
entry << "String " << string.value;
}
void visit(ast::InternalIdExpr &internal_id) override
{
auto entry = printer.advance("InternalId");
Traverser::visit(internal_id);
}
void visit(ast::Property &property) override
{
auto entry = printer.advance("Property");
Traverser::visit(property);
}
void visit(ast::And &and_expr) override
{
auto entry = printer.advance("And");
Traverser::visit(and_expr);
}
void visit(ast::Or &or_expr) override
{
auto entry = printer.advance("Or");
Traverser::visit(or_expr);
}
void visit(ast::Lt &lt_expr) override
{
auto entry = printer.advance("Less Than");
Traverser::visit(lt_expr);
}
void visit(ast::Gt &gt_expr) override
{
auto entry = printer.advance("Greater Than");
Traverser::visit(gt_expr);
}
void visit(ast::Ge &ge_expr) override
{
auto entry = printer.advance("Greater od Equal");
Traverser::visit(ge_expr);
}
void visit(ast::Le &le_expr) override
{
auto entry = printer.advance("Less or Equal");
Traverser::visit(le_expr);
}
void visit(ast::Eq &eq_expr) override
{
auto entry = printer.advance("Equal");
Traverser::visit(eq_expr);
}
void visit(ast::Ne &ne_expr) override
{
auto entry = printer.advance("Not Equal");
Traverser::visit(ne_expr);
}
void visit(ast::Plus &plus) override
{
auto entry = printer.advance("Plus");
Traverser::visit(plus);
}
void visit(ast::Minus &minus) override
{
auto entry = printer.advance("Minus");
Traverser::visit(minus);
}
void visit(ast::Star &star) override
{
auto entry = printer.advance("Star");
Traverser::visit(star);
}
void visit(ast::Slash &slash) override
{
auto entry = printer.advance("Slash");
Traverser::visit(slash);
}
void visit(ast::Rem &rem) override
{
auto entry = printer.advance("Rem (%)");
Traverser::visit(rem);
}
void visit(ast::CountFunction &count) override
{
auto entry = printer.advance("Count ");
entry << count.name << "(" << count.argument << ")";
}
void visit(ast::LabelsFunction &labels) override
{
auto entry = printer.advance("Labels ");
entry << labels.name << "(" << labels.argument << ")";
}
void visit(ast::PropertyList &prop_list) override
{
auto entry = printer.advance("Property List");
Traverser::visit(prop_list);
}
void visit(ast::RelationshipTypeList &rel_list) override
{
auto entry = printer.advance("Relationship Type List");
Traverser::visit(rel_list);
}
void visit(ast::Relationship &rel) override
{
auto entry = printer.advance("Relationship");
entry << " direction: " << rel.direction;
Traverser::visit(rel);
}
void visit(ast::RelationshipSpecs &rel_specs) override
{
auto entry = printer.advance("Relationship Specs");
Traverser::visit(rel_specs);
}
void visit(ast::LabelList &labels) override
{
auto entry = printer.advance("Label List");
Traverser::visit(labels);
}
void visit(ast::ReturnList &return_list) override
{
auto entry = printer.advance("Return List");
Traverser::visit(return_list);
}
void visit(ast::Where &where) override
{
auto entry = printer.advance("Where");
Traverser::visit(where);
}
void visit(ast::WriteQuery &write_query) override
{
auto entry = printer.advance("Write Query");
Traverser::visit(write_query);
}
void visit(ast::MergeQuery &merge_query) override
{
auto entry = printer.advance("Merge Query");
Traverser::visit(merge_query);
}
void visit(ast::DeleteQuery &delete_query) override
{
auto entry = printer.advance("Delete Query");
Traverser::visit(delete_query);
}
void visit(ast::Delete &delete_clause) override
{
auto is_detached = delete_clause.is_detached ? "yes" : "no";
auto text_entry =
std::string("Delete - DETACH: ") + std::string(is_detached);
auto entry = printer.advance(text_entry);
Traverser::visit(delete_clause);
}
void visit(ast::Create &create) override
{
auto entry = printer.advance("Create");
Traverser::visit(create);
}
void visit(ast::Merge &merge) override
{
auto entry = printer.advance("Merge");
Traverser::visit(merge);
}
void visit(ast::UpdateQuery &update_query) override
{
auto entry = printer.advance("Update Query");
Traverser::visit(update_query);
}
void visit(ast::Set &set_clause) override
{
auto entry = printer.advance("Set");
Traverser::visit(set_clause);
}
void visit(ast::SetValue &set_value) override
{
auto entry = printer.advance("Set Value");
Traverser::visit(set_value);
}
void visit(ast::SetElement &set_element) override
{
auto entry = printer.advance("Set Element");
Traverser::visit(set_element);
}
void visit(ast::LabelSetElement &label_set_element) override
{
auto entry = printer.advance("Label Set Element");
Traverser::visit(label_set_element);
}
void visit(ast::SetList &set_list) override
{
auto entry = printer.advance("Set List");
Traverser::visit(set_list);
}
void visit(ast::WithClause &with_clause) override
{
auto entry = printer.advance("With Clause");
Traverser::visit(with_clause);
}
void visit(ast::WithList &with_list) override
{
auto entry = printer.advance("With List");
Traverser::visit(with_list);
}
void visit(ast::WithQuery &with_query) override
{
auto entry = printer.advance("With Query");
Traverser::visit(with_query);
}
private:
Printer printer;
};

View File

@ -1,43 +0,0 @@
#pragma once
#include <stdexcept>
#include "token.hpp"
#include "utils/exceptions/basic_exception.hpp"
class CypherParsingError : public BasicException
{
public:
CypherParsingError(const std::string &what)
: BasicException("Cypher Parsing Error: " + what)
{
}
};
class CypherLexicalError : public BasicException
{
public:
CypherLexicalError(const Token &token)
: BasicException("Cypher Lexical Error: unrecognized token '" +
token.value + "'.")
{
}
};
class CypherSyntaxError : public BasicException
{
public:
CypherSyntaxError(const std::string &near)
: BasicException("Cypher Syntax Error: near '" + near + "'.")
{
}
};
class CypherSemanticError : public BasicException
{
public:
CypherSemanticError(const std::string &what)
: BasicException("Cypher Semanic Error: " + what)
{
}
};

View File

@ -1,54 +0,0 @@
#include <iostream>
#include "cypher_lexer.hpp"
int main()
{
CypherLexer lexer;
auto tokenizer = lexer.tokenize("{name: 'Dominik', lastName: 'Tomicevic', age: 24 }");
while(true)
{
auto token = tokenizer.lookup();
if(token.id == 0)
break;
std::cout << token.id << " -> " << token.value << std::endl;
}
lexertl::rules rules;
lexertl::state_machine sm;
rules.push("\\s+", sm.skip());
rules.push("MATCH", 1);
rules.push("RETURN", 2);
rules.push("'(.*?)'", 4); // string literal TODO single quote escape
rules.push("\\\"(.*?)\\\"", 4); // string literal TODO double quote escape
rules.push("[-+]?(\\d*[.])?\\d+", 5); // number
rules.push("[_a-zA-Z][_a-zA-Z0-9]{0,30}", 3); // identifier
lexertl::generator::build(rules, sm);
std::string input("MATCH (user:User { name: 'Dominik', age: 24})-[has:HAS]->(item:Item) WHERE item.name = 'XPS 13', AND item.price = 14.99 RETURN user, has, item");
lexertl::smatch results(input.begin(), input.end());
// Read ahead
lexertl::lookup(sm, results);
while (results.id != 0)
{
std::cout << "Id: " << results.id << ", Token: '" <<
results.str () << "'\n";
lexertl::lookup(sm, results);
}
std::cout << "-1 to uint64_t = " << uint64_t(-1) << std::endl;
return 0;
}

View File

@ -1,45 +0,0 @@
#include <cstdlib>
#include <vector>
#include <vector>
#include "compiler.hpp"
#include "debug/tree_print.hpp"
#include "utils/command_line/arguments.hpp"
#include "cypher/common.hpp"
#include "utils/terminate_handler.hpp"
using std::cout;
using std::endl;
// * INPUT ARGUMENTS *
// -q -> query
// -v -> visitor
// -f -> file
//
int main(int argc, char *argv[])
{
std::set_terminate(&terminate_handler);
// arguments parsing
auto arguments = all_arguments(argc, argv);
// query extraction
auto cypher_query = extract_query(arguments);
cout << "QUERY: " << cypher_query << endl;
// traversers
auto traverser = get_argument(arguments, "-t", "code");
auto print_traverser = Traverser::sptr(new PrintVisitor(cout));
std::map<std::string, Traverser::sptr> traversers = {
{"print", print_traverser}
};
cypher::Compiler compiler;
auto tree = compiler.syntax_tree(cypher_query);
auto t = traversers[traverser];
tree.root->accept(*t);
return 0;
}

View File

@ -1,54 +0,0 @@
#pragma once
#include "cypher/cypher.h"
#include "token.hpp"
#include "ast/tree.hpp"
#include "tokenizer/cypher_lexer.hpp"
#include "logging/default.hpp"
void* cypher_parserAlloc(void* (*allocProc)(size_t));
void cypher_parser(void*, int, Token*, ast::Ast* ast);
void cypher_parserFree(void*, void(*freeProc)(void*));
namespace cypher
{
class Parser
{
public:
Parser() : logger(logging::log->logger("LexicalParser"))
{
parser = cypher_parserAlloc(malloc);
}
~Parser()
{
cypher_parserFree(parser, free);
}
ast::Ast parse(Lexer::Tokenizer tokenizer)
{
auto tree = ast::Ast();
std::list<Token> tokens;
do
{
tokens.emplace_back(tokenizer.lookup());
auto& token = tokens.back();
// TODO: resolve fmt error with {
// logger.debug(token.repr());
cypher_parser(parser, token.id, &token, &tree);
} while(tokens.back().id != 0);
return tree;
}
protected:
Logger logger;
private:
void* parser;
};
}

View File

@ -1,48 +0,0 @@
#pragma once
#include <iostream>
#include <ostream>
#include <cstdint>
#include <string>
#include <fmt/format.h>
struct Token
{
unsigned long id;
std::string value;
/*
* Token is "True" if it's id is bigger than zero. Because
* lexer ids are all bigger than zero.
*
* This object could be used in while loop as a conditional element.
* E.g.:
* while (auto token = ...)
* {
* }
*/
explicit operator bool() const
{
return id > 0;
}
/*
* String representation.
*/
std::string repr() const
{
// TODO: wrap fmt format
// return fmt::format("TOKEN id = {}, value = {}", id, value);
return "";
}
/*
* Ostream operator
*
* Prints token id and value in single line.
*/
friend std::ostream& operator<<(std::ostream& stream, const Token& token)
{
return stream << token.repr();
}
};

View File

@ -1,90 +0,0 @@
#pragma once
#include "cypher/cypher.h"
#include "lexer.hpp"
class CypherLexer : public Lexer
{
public:
CypherLexer()
{
// whitespace
rule("\\s+", sm->skip());
// special characters
rule("\\.", TK_DOT);
rule(",", TK_COMMA);
rule(":", TK_COLON);
rule("\\|", TK_PIPE);
rule("\\{", TK_LCP);
rule("\\}", TK_RCP);
rule("\\(", TK_LP);
rule("\\)", TK_RP);
rule("\\[", TK_LSP);
rule("\\]", TK_RSP);
// operators
rule("\\+", TK_PLUS);
rule("-", TK_MINUS);
rule("\\*", TK_STAR);
rule("\\/", TK_SLASH);
rule("%", TK_REM);
rule(">", TK_GT);
rule("<", TK_LT);
rule(">=", TK_GE);
rule("<=", TK_LE);
rule("=", TK_EQ);
rule("<>", TK_NE);
// constants
rule("(?i:TRUE)", TK_BOOL);
rule("(?i:FALSE)", TK_BOOL);
// keywords
rule("(?i:CREATE)", TK_CREATE);
rule("(?i:MERGE)", TK_MERGE);
rule("(?i:MATCH)", TK_MATCH);
rule("(?i:WHERE)", TK_WHERE);
rule("(?i:SET)", TK_SET);
rule("(?i:RETURN)", TK_RETURN);
rule("(?i:DISTINCT)", TK_DISTINCT);
rule("(?i:DETACH)", TK_DETACH);
rule("(?i:DELETE)", TK_DELETE);
rule("(?i:WITH)", TK_WITH);
// TODO: here should be better regex
// problem is that id in property list isn't ID from where
// part
rule("(?-i:ID)", TK_ID);
rule("(?i:AND)", TK_AND);
rule("(?i:OR)", TK_OR);
// functions
rule("(?i:COUNT)", TK_COUNT);
rule("(?i:LABELS)", TK_LABELS);
// string literal TODO single quote escape
rule("'(.*?)'", TK_STR);
// string literal TODO double quote escape
rule("\\\"(.*?)\\\"", TK_STR);
// ALL BELOW COMBNATIONS DON'T WORK
// rule("(?#\\\")(.*?)(?#\\\")", TK_STR);
// rule("[\"](.*?)[\"]", TK_STR);
// rule("(?:\")(.*?)(?:\")", TK_STR);
// rule("(?#:\")(.*?)(?#:\")", TK_STR);
// rule("(?#\")(.*?)(?#\")", TK_STR);
// number
rule("\\d+", TK_LONG);
rule("\\d*[.]?\\d+", TK_FLOAT);
// identifier
rule("[_a-zA-Z][_a-zA-Z0-9]{0,30}", TK_IDN);
build();
}
CypherLexer(CypherLexer &other) = delete;
CypherLexer(CypherLexer &&other) = default;
};

View File

@ -1,91 +0,0 @@
#pragma once
#include <cstdint>
#include <memory>
// unfortunatelly, lexertl uses some stuff deprecated in c++11 so we get some
// warnings during compile time, mainly for the auto_ptr
// auto_ptr<lexertl::detail::basic_re_token<char, char> > is deprecated
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#include "lexertl/generator.hpp"
#include "lexertl/lookup.hpp"
#pragma GCC diagnostic pop
#include "query/language/cypher/errors.hpp"
#include "query/language/cypher/token.hpp"
class Lexer
{
public:
// public pointer declarations
using uptr = std::unique_ptr<Lexer>;
using sptr = std::shared_ptr<Lexer>;
// constructors
// default constructor creates unique pointers to object
// members
Lexer() :
rules(std::make_unique<lexertl::rules>()),
sm(std::make_unique<lexertl::state_machine>())
{
}
// copy constructor is deleted
Lexer(Lexer& other) = delete;
// move constructor has default implementation
Lexer(Lexer&& other) :
rules(std::move(other.rules)),
sm(std::move(other.sm))
{
}
// TODO take care of concurrnecy and moving the lexer object when
// some Tokenizer already uses the it (right now I'm not
// sure what is going to happen)
// check this ASAP
class Tokenizer
{
public:
Tokenizer(const Lexer& lexer, const std::string& str)
: lexer(lexer), results(str.begin(), str.end()) {}
Token lookup()
{
lexertl::lookup(*lexer.sm, results);
auto token = Token {results.id, results.str()};
if(results.id == static_cast<decltype(results.id)>(-1))
throw CypherLexicalError(token);
return token;
}
private:
const Lexer& lexer;
lexertl::smatch results;
};
Tokenizer tokenize(const std::string& str)
{
return Tokenizer(*this, str);
}
void build()
{
lexertl::generator::build(*rules, *sm);
}
void rule(const std::string& regex, uint64_t id)
{
rules->push(regex, id);
}
protected:
using uptr_lexertl_rules = std::unique_ptr<lexertl::rules>;
using uptr_lexertl_sm = std::unique_ptr<lexertl::state_machine>;
uptr_lexertl_rules rules;
uptr_lexertl_sm sm;
};

View File

@ -1,317 +0,0 @@
#pragma once
#include "query/language/cypher/ast/ast.hpp"
#include "query/language/cypher/ast/ast_visitor.hpp"
class Traverser : public ast::AstVisitor
{
public:
using uptr = std::unique_ptr<Traverser>;
using sptr = std::shared_ptr<Traverser>;
void visit(ast::Start& start_query) override
{
// DELETE
}
void visit(ast::DeleteQuery& delete_query) override
{
accept(delete_query.match);
accept(delete_query.delete_clause);
}
void visit(ast::ReadQuery& read_query) override
{
accept(read_query.match);
accept(read_query.return_clause);
}
void visit(ast::ReadWriteQuery& query) override
{
accept(query.match_clause);
accept(query.create_clause);
accept(query.return_clause);
}
void visit(ast::MergeQuery& query) override
{
accept(query.merge_clause);
accept(query.set_clause);
accept(query.return_clause);
}
void visit(ast::Match& match) override
{
accept(match.pattern_list);
accept(match.where);
}
void visit(ast::Pattern& pattern) override
{
accept(pattern.node);
accept(pattern.relationship);
accept(pattern.next);
}
void visit(ast::PatternExpr& pattern_expr) override
{
accept(pattern_expr.pattern);
}
void visit(ast::Node& node) override
{
accept(node.idn);
accept(node.labels);
accept(node.props);
}
void visit(ast::Return& return_clause) override
{
accept(return_clause.return_list);
accept(return_clause.distinct);
}
void visit(ast::Accessor& accessor) override
{
accept(accessor.entity);
accept(accessor.prop);
}
void visit(ast::Property& property) override
{
accept(property.idn);
accept(property.value);
}
void visit(ast::And& and_expr) override
{
accept(and_expr.left);
accept(and_expr.right);
}
void visit(ast::Or& or_expr) override
{
accept(or_expr.left);
accept(or_expr.right);
}
void visit(ast::Lt& lt_expr) override
{
accept(lt_expr.left);
accept(lt_expr.right);
}
void visit(ast::Gt& gt_expr) override
{
accept(gt_expr.left);
accept(gt_expr.right);
}
void visit(ast::Ge& ge_expr) override
{
accept(ge_expr.left);
accept(ge_expr.right);
}
void visit(ast::Le& le_expr) override
{
accept(le_expr.left);
accept(le_expr.right);
}
void visit(ast::Eq& eq_expr) override
{
accept(eq_expr.left);
accept(eq_expr.right);
}
void visit(ast::Ne& ne_expr) override
{
accept(ne_expr.left);
accept(ne_expr.right);
}
void visit(ast::Plus& plus) override
{
accept(plus.left);
accept(plus.right);
}
void visit(ast::Minus& minus) override
{
accept(minus.left);
accept(minus.right);
}
void visit(ast::Star& star) override
{
accept(star.left);
accept(star.right);
}
void visit(ast::Slash& slash) override
{
accept(slash.left);
accept(slash.right);
}
void visit(ast::Rem& rem) override
{
accept(rem.left);
accept(rem.right);
}
void visit(ast::CountFunction& count) override
{
}
void visit(ast::LabelsFunction& labels) override
{
}
void visit(ast::PropertyList& prop_list) override
{
accept(prop_list.value);
accept(prop_list.next);
}
void visit(ast::PatternList& pattern_list) override
{
accept(pattern_list.value);
accept(pattern_list.next);
}
void visit(ast::RelationshipTypeList& rel_list) override
{
accept(rel_list.value);
accept(rel_list.next);
}
void visit(ast::IdentifierList& list) override
{
accept(list.value);
accept(list.next);
}
void visit(ast::Relationship& rel) override
{
accept(rel.specs);
}
void visit(ast::RelationshipSpecs& rel_specs) override
{
accept(rel_specs.idn);
accept(rel_specs.types);
accept(rel_specs.props);
}
void visit(ast::LabelList& labels) override
{
accept(labels.value);
accept(labels.next);
}
void visit(ast::ReturnList& return_list) override
{
accept(return_list.value);
accept(return_list.next);
}
void visit(ast::Where& where) override
{
accept(where.expr);
}
void visit(ast::WriteQuery& write_query) override
{
accept(write_query.create);
accept(write_query.return_clause);
}
void visit(ast::UpdateQuery& update_query) override
{
accept(update_query.match_clause);
accept(update_query.set_clause);
accept(update_query.return_clause);
}
void visit(ast::Set& set_clause) override
{
accept(set_clause.set_list);
}
void visit(ast::SetValue& set_value) override
{
accept(set_value.value);
}
void visit(ast::SetElement& set_element) override
{
accept(set_element.accessor);
accept(set_element.set_value);
}
void visit(ast::LabelSetElement& label_set_element) override
{
accept(label_set_element.identifier);
accept(label_set_element.label_list);
}
void visit(ast::SetList& set_list) override
{
accept(set_list.value);
accept(set_list.next);
}
void visit(ast::Create& create) override
{
accept(create.pattern);
}
void visit(ast::Merge& merge) override
{
accept(merge.pattern);
}
void visit(ast::Distinct& distinct) override
{
accept(distinct.identifier);
}
void visit(ast::Delete& delete_clause) override
{
accept(delete_clause.identifier);
}
void visit(ast::WithClause& with_clause) override
{
accept(with_clause.identifier_list);
accept(with_clause.match_clause);
}
void visit(ast::WithList& with_list) override
{
accept(with_list.value);
accept(with_list.next);
}
void visit(ast::WithQuery& with_query) override
{
accept(with_query.match_clause);
accept(with_query.with_list);
accept(with_query.return_clause);
}
void visit(ast::InternalIdExpr& internal_id) override
{
accept(internal_id.entity);
accept(internal_id.id);
}
protected:
template<class T>
void accept(T* node)
{
if(node != nullptr)
node->accept(*this);
}
};

View File

@ -1,93 +0,0 @@
#pragma once
#include <string>
#include "logging/default.hpp"
#include "query/exception/plan_compilation.hpp"
#include "utils/string/join.hpp"
#include "logging/loggable.hpp"
// TODO:
// * all libraries have to be compiled in the server compile time
// * compile command has to be generated
/**
* Compiles code into shared object (.so)
*/
class PlanCompiler : public Loggable
{
public:
PlanCompiler() : Loggable("PlanCompiler") {}
/**
* Compiles in_file into out_file (.cpp -> .so)
*
* @param in_file C++ file that can be compiled into dynamic lib
* @param out_file dynamic lib (on linux .so)
*
* @return void
*/
void compile(const std::string &in_file, const std::string &out_file)
{
std::string flags;
// TODO: sync this with cmake configuration
#ifdef NDEBUG
flags += " -DNDEBUG -O2";
#endif
#ifdef LOG_NO_TRACE
flags += " -DLOG_NO_TRACE";
#endif
#ifdef LOG_NO_DEBUG
flags += " -DLOG_NO_DEBUG";
#endif
#ifdef LOG_NO_INFO
flags += " -DLOG_NO_INFO";
#endif
#ifdef LOG_NO_WARN
flags += " -DLOG_NO_WARN";
#endif
#ifdef LOG_NO_ERROR
flags += " -DLOG_NO_ERROR";
#endif
// TODO: load from config (generate compile command)
// generate compile command
auto compile_command = utils::prints(
"clang++" + flags,
// "-std=c++1y -O2 -DNDEBUG",
"-std=c++1y", // compile flags
in_file, // input file
"-o", out_file, // ouput file
"-I./include", // include paths
"-I../include",
"-I../../include",
"-I../../../include",
"-I../libs/fmt",
"-I../../libs/fmt",
"-I../../../libs/fmt",
"-L./ -L../ -L../../",
"-lmemgraph_pic",
"-shared -fPIC" // shared library flags
);
logger.debug("compile command -> {}", compile_command);
// synchronous call
auto compile_status = system(compile_command.c_str());
logger.debug("compile status {}", compile_status);
// if compilation has failed throw exception
if (compile_status != 0) {
logger.debug("FAIL: Query Code Compilation: {} -> {}", in_file,
out_file);
throw PlanCompilationException(
"Code compilation error. Generated code is not compilable or "
"compilation settings are wrong");
}
logger.debug("SUCCESS: Query Code Compilation: {} -> {}", in_file,
out_file);
}
};

View File

@ -1,49 +0,0 @@
#pragma once
#include "communication/communication.hpp"
#include "database/graph_db_accessor.hpp"
#include "query/stripped.hpp"
/**
* @class PlanInterface
*
* @brief Pure Abstract class that is interface to query plans.
*
* @tparam Stream stream for results writing.
*/
template <typename Stream>
class PlanInterface
{
public:
/**
* In derived classes this method has to be overriden in order to implement
* concrete execution plan.
*
* @param db_accessor Accessor for ihe database.
* @param args plan argument (vector of literal values from the query)
* @param stream stream for results writing
*
* @return bool status after execution (success OR fail)
*/
virtual bool run(GraphDbAccessor &db_accessor, const TypedValueStore<> &args, Stream &stream) = 0;
/**
* Virtual destructor in base class.
*/
virtual ~PlanInterface() {}
};
/**
* Defines type of underlying extern C functions and library object class name.
* (ObjectPrototype).
*
* @tparam underlying object depends on Stream template parameter because
* it will send the results throughout a custom Stream object.
*/
template <typename Stream>
struct QueryPlanTrait
{
using ObjectPrototype = PlanInterface<Stream>;
using ProducePrototype = PlanInterface<Stream> *(*)();
using DestructPrototype = void (*)(PlanInterface<Stream> *);
};

View File

@ -1,57 +0,0 @@
#pragma once
#include "logging/loggable.hpp"
#include "query/stripper.hpp"
/*
* Query preprocessing contains:
* * query stripping
*
* This class is here because conceptually process of query preprocessing
* might have more than one step + in current version of C++ standard
* isn't trivial to instantiate QueryStripper because of template arguments +
* it depends on underlying lexical analyser.
*
* The preprocessing results are:
* * stripped query |
* * stripped arguments |-> StrippedQuery
* * stripped query hash |
*/
class QueryPreprocessor : public Loggable
{
private:
// In C++17 the ints will be removed.
// as far as I understand in C++17 class template parameters
// can be deduced just like function template parameters
// TODO: once C++ 17 will be well suported by comilers
// refactor this piece of code because it is hard to maintain.
using QueryStripperT = QueryStripper<int, int, int, int>;
public:
QueryPreprocessor() : Loggable("QueryPreprocessor"),
stripper(make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL))
{
}
/**
* Preprocess the query:
* * strip parameters
* * calculate query hash
*
* @param query that is going to be stripped
*
* @return QueryStripped object
*/
auto preprocess(const std::string &query)
{
auto preprocessed = stripper.strip(query);
logger.info("stripped_query = {}", preprocessed.query);
logger.info("query_hash = {}", preprocessed.hash);
return stripper.strip(query);
}
private:
QueryStripperT stripper;
};

View File

@ -1,46 +0,0 @@
#pragma once
#include "storage/typed_value_store.hpp"
#include "utils/hashing/fnv.hpp"
/*
* StrippedQuery contains:
* * stripped query
* * plan arguments stripped from query
* * hash of stripped query
*/
struct StrippedQuery {
StrippedQuery(const std::string &&query, TypedValueStore<> &&arguments, HashType hash)
: query(std::forward<const std::string>(query)),
arguments(std::forward<TypedValueStore<>>(arguments)), hash(hash) {}
/**
* Copy constructor is deleted because we don't want to make unecessary
* copies of this object (copying of string and vector could be expensive)
*/
StrippedQuery(const StrippedQuery &other) = delete;
StrippedQuery &operator=(const StrippedQuery &other) = delete;
/**
* Move is allowed operation because it is not expensive and we can
* move the object after it was created.
*/
StrippedQuery(StrippedQuery &&other) = default;
StrippedQuery &operator=(StrippedQuery &&other) = default;
/**
* Stripped query
*/
const std::string query;
/**
* Stripped arguments
*/
const TypedValueStore<> arguments;
/**
* Hash based on stripped query.
*/
const HashType hash;
};

View File

@ -1,122 +0,0 @@
#pragma once
#include <vector>
#include <iostream>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include "cypher/cypher.h"
#include "logging/loggable.hpp"
#include "query/language/cypher/tokenizer/cypher_lexer.hpp"
#include "query/stripped.hpp"
#include "storage/typed_value_store.hpp"
#include "utils/hashing/fnv.hpp"
#include "utils/string/transform.hpp"
#include "utils/variadic/variadic.hpp"
// TODO: all todos will be resolved once Antler will be integrated
template<typename... Ts>
class QueryStripper : public Loggable {
public:
QueryStripper(Ts &&... strip_types)
: Loggable("QueryStripper"),
strip_types(std::make_tuple(std::forward<Ts>(strip_types)...)),
lexer(std::make_unique<CypherLexer>()) {
}
QueryStripper(QueryStripper &other) = delete;
QueryStripper(QueryStripper &&other)
: Loggable("QueryStripper"), strip_types(std::move(other.strip_types)),
lexer(std::move(other.lexer)) {
}
auto strip(const std::string &query, const std::string &separator = " ") {
// -------------------------------------------------------------------
// TODO: write speed tests and then optimize, because this
// function is called before every query execution !
// -------------------------------------------------------------------
// TODO write this more optimal (resplace string
// concatenation with something smarter)
// TODO: in place substring replacement
auto tokenizer = lexer->tokenize(query);
// TMP size of supported token types
constexpr auto size = std::tuple_size<decltype(strip_types)>::value;
TypedValueStore<> stripped_arguments;
std::string stripped_query;
stripped_query.reserve(query.size());
int counter = 0; // how many arguments have we processed so far
while (auto token = tokenizer.lookup()) {
if (_or(token.id, strip_types, std::make_index_sequence < size > {})) {
switch (token.id) {
case TK_LONG:
stripped_arguments.set(counter, std::stoi(token.value));
break;
case TK_STR:
// TODO: remove quotes view lexertl
token.value.erase(0, 1);
token.value.erase(token.value.length() - 1, 1);
// TODO: remove
stripped_arguments.set(counter, token.value);
break;
case TK_BOOL: {
bool value = token.value[0] == 'T' || token.value[0] == 't';
stripped_arguments.set(counter, value);
break;
}
case TK_FLOAT:
stripped_arguments.set(counter, std::stof(token.value));
break;
default:
// TODO: other properties
assert(false);
}
stripped_query += std::to_string(counter++) + separator;
} else {
// if token is keyword then lowercase because query hash
// should be the same
// TODO: probably we shoud do the lowercase before
// or during the tokenization (SPEED TESTS)
if (token.id == TK_OR || token.id == TK_AND ||
token.id == TK_NOT || token.id == TK_WITH ||
token.id == TK_SET || token.id == TK_CREATE ||
token.id == TK_MERGE || token.id == TK_MATCH ||
token.id == TK_DELETE || token.id == TK_DETACH ||
token.id == TK_WHERE || token.id == TK_RETURN ||
token.id == TK_DISTINCT || token.id == TK_COUNT ||
token.id == TK_LABELS) {
std::transform(token.value.begin(), token.value.end(),
token.value.begin(), ::tolower);
}
stripped_query += token.value + separator;
}
}
// TODO: hash function should be a template parameter
HashType hash = fnv(stripped_query);
return StrippedQuery(std::move(stripped_query),
std::move(stripped_arguments), hash);
}
private:
std::tuple<Ts...> strip_types;
CypherLexer::uptr lexer;
template<typename Value, typename Tuple, std::size_t... index>
bool _or(Value &&value, Tuple &&tuple, std::index_sequence<index...>) {
return utils::or_vargs(std::forward<Value>(value),
std::get<index>(std::forward<Tuple>(tuple))...);
}
};
template<typename... Ts>
decltype(auto) make_query_stripper(Ts &&... ts) {
return QueryStripper<Ts...>(std::forward<Ts>(ts)...);
}

View File

@ -1,69 +0,0 @@
#pragma once
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include "fmt/format.h"
#include "logging/default.hpp"
#include "utils/exceptions/basic_exception.hpp"
using std::cout;
using std::endl;
// this is a nice way how to avoid multiple definition problem with
// headers because it will create a unique namespace for each compilation unit
// http://stackoverflow.com/questions/2727582/multiple-definition-in-header-file
// but sometimes that might be a problem
namespace {
class CodeLineFormatException : public BasicException {
public:
using BasicException::BasicException;
};
template<typename... Args>
std::string format(const std::string &format_str, const Args &... args) {
return fmt::format(format_str, args...);
}
template<typename... Args>
std::string code_line(const std::string &format_str, const Args &... args) {
try {
return "\t" + format(format_str, args...) + "\n";
} catch (std::runtime_error &e) {
throw CodeLineFormatException(std::string(e.what()) + " " + format_str);
}
}
class CoutSocket {
public:
CoutSocket() : logger(logging::log->logger("Cout Socket")) {}
int write(const std::string &str) {
logger.info(str);
return str.size();
}
int write(const char *data, size_t len) {
logger.info(std::string(data, len));
return len;
}
int write(const byte *data, size_t len) {
std::stringstream ss;
for (int i = 0; i < len; i++) {
ss << data[i];
}
std::string output(ss.str());
cout << output << endl;
logger.info(output);
return len;
}
private:
Logger logger;
};
}

View File

View File

@ -20,4 +20,8 @@ cd libs
./setup.sh
cd ..
cd build
wget http://www.antlr.org/download/antlr-4.6-complete.jar
cd ..
echo "DONE"

1
libs/.gitignore vendored
View File

@ -2,3 +2,4 @@
!.gitignore
!setup.sh
!cleanup.sh
!CMakeLists.txt

26
libs/CMakeLists.txt Normal file
View File

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.1)
# setup antlr
option(WITH_LIBCXX "" OFF) # because of debian bug
# http://stackoverflow.com/questions/37096062/get-a-basic-c-program-to-compile-using-clang-on-ubuntu-16/38385967#38385967
add_subdirectory(antlr4/runtime/Cpp)
# setup google benchmark
add_subdirectory(benchmark)
# setup cppitertools
include_directories(cppitertools)
# setup fmt format
# fmt uses google test but if fmt isn't top project (here it isn't) fmt tests
# are disabled (reasonable configuration)
add_subdirectory(fmt)
# setup google test
add_subdirectory(googletest)
# setup yaml cpp
# disable tests because yaml doesn't have MASTER_PROJECT flag like fmt has
# to override an option use option :)
option(YAML_CPP_BUILD_TOOLS "" OFF)
add_subdirectory(yaml-cpp)

View File

@ -1,43 +1,47 @@
#!/bin/bash
# Catch
git clone https://github.com/philsquared/Catch.git
catch_tag="master"
cd Catch
git checkout ${catch_tag}
# antlr
git clone https://github.com/antlr/antlr4.git
antlr4_tag="aacd2a2c95816d8dc1c05814051d631bfec4cf3e" # v4.6
cd antlr4
git checkout ${antlr4_tag}
cd ..
# cppitertools
git clone https://github.com/ryanhaining/cppitertools.git
cd cppitertools
cppitertools_tag="394cc4debcd037db199551546b6fbc3ea3066722" # master 7 Oct 2016
# because last release was v0.2 and at the point when
# the lib was added master had 104 commits more than v0.2
git checkout ${cppitertools_tag}
cd ..
# fmt
git clone https://github.com/fmtlib/fmt.git
fmt_tag="e5e4fb370ccf327bbdcdcd782eb3e53580e11094"
fmt_tag="e5e4fb370ccf327bbdcdcd782eb3e53580e11094" # v3.0.0
cd fmt
git checkout ${fmt_tag}
cmake .
make
cd ..
# google benchmark
git clone https://github.com/google/benchmark.git
benchmark_tag="4f8bfeae470950ef005327973f15b0044eceaceb" # v1.1.0
cd benchmark
git checkout ${benchmark_tag}
cd ..
# google test
git clone https://github.com/google/googletest.git
googletest_tag="ec44c6c1675c25b9827aacd08c02433cccde7780" # v1.8.0
cd googletest
git checkout ${googletest_tag}
cd ..
# yaml-cpp
git clone https://github.com/jbeder/yaml-cpp
yaml_cpp_tag="519d33fea3fbcbe7e1f89f97ee0fa539cec33eb7"
yaml_cpp_tag="519d33fea3fbcbe7e1f89f97ee0fa539cec33eb7" # master 18 Aug 2016
# because a bug with link process had been fixed somewhen between
# this commit and v0.5.3
cd yaml-cpp
git checkout ${yaml_cpp_tag}
cmake .
make
cd ..
# lemon
mkdir lemon
cd lemon
lemon_tag="09a96bed19955697a5e20c49ad863ec2005815a2"
wget http://www.sqlite.org/src/raw/tool/lemon.c?name=${lemon_tag} -O lemon.c
lempar_tag="8c4e9d8517e50da391f1d89a519e743dd4afbc09"
wget http://www.sqlite.org/src/raw/tool/lempar.c?name=${lempar_tag} -O lempar.c
clang lemon.c -o lemon -O2
cd ..
# lexertl
git clone https://github.com/BenHanson/lexertl.git
lexertl_tag=7d4d36a357027df0e817453cc9cf948f71047ca9
cd lexertl
git checkout ${lexertl_tag}
cd ..

View File

@ -8,7 +8,7 @@
#include "communication/bolt/v1/states/state.hpp"
#include "communication/bolt/v1/transport/bolt_decoder.hpp"
#include "communication/bolt/v1/transport/bolt_encoder.hpp"
#include "communication/communication.hpp"
#include "communication/bolt/communication.hpp"
#include "logging/default.hpp"

View File

@ -32,14 +32,6 @@ State *Executor::run(Session &session)
return this->run(session, q);
// TODO: RETURN success MAYBE
}
catch (const CypherLexicalError &e)
{
session.output_stream.write_failure(
{{"code", "Memgraph.CypherLexicalError"},
{"message", e.what()}});
session.output_stream.send();
return session.bolt.states.error.get();
}
catch (const QueryEngineException &e)
{
session.output_stream.write_failure(

Some files were not shown because too many files have changed in this diff Show More