diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..10be693d187eed44b2c816d12e486e251e5f036e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +/cmake-build-debug/ +/build/ +/build1/ +.vscode +.idea +CMakeUserPresets.json \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb53bfb98b8acc6ea96465e6171f9e4892326bf6..7c7b798a9cd8c1e677a1e826fa84addaa990c2ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,15 +33,9 @@ jobs: cd build cmake .. make - # tests: - # runs-on: ubuntu-latest - # container: raiden454/cpp-app - # needs: [build] - # steps: - # - uses: actions/checkout@v3 - # - name: Run-Tests - # run: | - # find / -name "test_service" + - name: Run-Tests + run: | + ./build/server/internal/service/tests/test_service linters: runs-on: ubuntu-latest container: raiden454/cpp-app @@ -52,4 +46,4 @@ jobs: cppcheck server --std=c++17 --enable=all - name: Cpplint run: | - cpplint --extensions=cpp,hpp,h --recursive ./server/* + cpplint --extensions=cpp,hpp,h --recursive ./server/* \ No newline at end of file diff --git a/.gitignore b/.gitignore index 870ca9cbdc136f4823abee3dce85671fc5ccd26c..de30b5cd2b696a631c9b3f127129d5b92ba23b21 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ /cmake-build-debug/ /build/ +/build1/ .vscode .idea CMakeUserPresets.json +/metrics/cmake-build-debug" diff --git a/CMakeLists.txt b/CMakeLists.txt index 5054100d4d9df7e09087c90a11fdac68ac7ce761..e51f2bfe1b5440809734dbcce45c2ac87f01a54f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,40 @@ -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) cmake_minimum_required(VERSION 3.16) -set(CMAKE_PREFIX_PATH build) -project(SourcedOut CXX) -# find_package(antlr4-runtime REQUIRED) -find_package(Boost 1.8.1 REQUIRED) -# find_package(libpqxx REQUIRED) -find_package(GTest REQUIRED) -set(THREADS_PREFER_PTHREAD_FLAG ON) -find_package(Threads REQUIRED) -message(STATUS ${Boost_LIBRARIES}) -set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-lpthread -pthread") -add_executable(${PROJECT_NAME} src/main.cpp) -#add_executable(${PROJECT_NAME} text-basic-metrics/tbm_main.cpp text-basic-metrics/tbm_main.cpp) строка для запуска моей части в text-basic-metrics -target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES} ${antlr4-runtime_LIBRARIES} ${libpqxx_LIBRARIES} ${GTest_LIBRARIES}) \ No newline at end of file + +set(PROJECT_NAME "SourcedOut") + +project(${PROJECT_NAME}) + + +set(BUILD_DEV TRUE CACHE BOOL "build dev version") +set(SANITIZE_BUILD TRUE CACHE BOOL "build with sanitizers") + +if(BUILD_DEV) + enable_testing() + message("Building dev version") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -O0 -fprofile-arcs -ftest-coverage") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wextra -pedantic -Wformat=2 -Wfloat-equal -Wconversion \ + -Wlogical-op -Wshift-overflow=2 -Wduplicated-cond -Wcast-qual -Wcast-align -lpq -lpqxx") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov") + + if(SANITIZE_BUILD) + message("Sanitizers ON") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined -fno-sanitize-recover=all -fsanitize-undefined-trap-on-error") + endif(SANITIZE_BUILD) +endif(BUILD_DEV) + +set(BUILD_SERVER "BUILD_SERVER") +set(BUILD_CLIENT "BUILD_CLIENT") +set(BUILD_ALL "BUILD_ALL") + + +message("${BUILD_DEV} ${SANITIZE_BUILD} ${CMAKE_EXE_LINKER_FLAGS}") +set(BUILD_MODE ${BUILD_SERVER}) + +if((BUILD_MODE STREQUAL ${BUILD_CLIENT}) OR (BUILD_MODE STREQUAL ${BUILD_ALL})) + add_subdirectory(client) +endif() + +if((BUILD_MODE STREQUAL ${BUILD_SERVER}) OR (BUILD_MODE STREQUAL ${BUILD_ALL})) + add_subdirectory(server) +endif() diff --git a/Dockerfile b/Dockerfile index fd9957b926a8c123392a74501b8176fc2f51c710..b1c981de381b2a8463edda6c2545bb59d23d4f4d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,44 +1,55 @@ -FROM ubuntu:20.04 AS base +FROM ubuntu:latest ENV TZ=Europe/Moscow RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone -RUN apt update -y -RUN apt install -y gcc -RUN apt install -y libpqxx-dev -RUN apt install -y clang-tidy -RUN apt install -y nlohmann-json3-dev -RUN apt install -y python3-pip -RUN apt install -y cppcheck -RUN apt install -y git -RUN apt-get update -y -RUN apt install -y xvfb -RUN pip install gcovr -RUN pip install cpplint +RUN apt update -y +RUN apt install -y gcc +RUN apt install -y libpqxx-dev +RUN apt install -y clang-tidy +RUN apt-get install -y wget +RUN apt install -y g++ +RUN apt install -y cmake + +RUN wget https://github.com/jtv/libpqxx/archive/refs/tags/7.7.5.tar.gz +RUN tar -zxvf 7.7.5.tar.gz +WORKDIR libpqxx-7.7.5 +RUN ./configure CXXFLAGS=-std=c++17 --disable-dependency-tracking +RUN make +RUN make install + +RUN apt install -y python3-pip +RUN apt install -y cppcheck +RUN apt-get update +RUN apt install -y nlohmann-json3-dev +RUN apt install -y git +RUN apt-get update +RUN apt install -y default-jre +RUN apt -y install curl + +RUN pwd +WORKDIR /usr/local/lib +RUN curl -O https://www.antlr.org/download/antlr-4.12.0-complete.jar + +RUN apt install -y xvfb +RUN pip install gcovr +RUN pip install cpplint -RUN apt-get install wget -RUN apt-get install libssl-dev -RUN wget https://github.com/Kitware/CMake/releases/download/v3.26.3/cmake-3.26.3.tar.gz -RUN tar -zxvf cmake-3.26.3.tar.gz -WORKDIR cmake-3.26.3 -RUN ./bootstrap -RUN make +RUN git clone https://github.com/google/googletest.git -b release-1.11.0 +WORKDIR googletest/build +RUN cmake .. -DBUILD_GMOCK=ON +RUN make RUN make install -RUN cd .. - + RUN wget https://boostorg.jfrog.io/artifactory/main/release/1.82.0/source/boost_1_82_0.tar.gz RUN tar xvf boost_1_82_0.tar.gz WORKDIR boost_1_82_0 RUN ./bootstrap.sh --prefix=/usr/ -RUN ./b2 install - -RUN git clone https://github.com/google/googletest.git -b release-1.11.0 -WORKDIR googletest/build -RUN cmake .. -DBUILD_GMOCK=OFF -RUN make -RUN make install +RUN ./b2 install WORKDIR /project -COPY . . \ No newline at end of file +COPY . . + +EXPOSE 8080 \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0c8001e52fad1c5f3b916360229ae2abd2f97334 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +generate: + mkdir build + cmake -B build/ + +build-project: + cd ./build && make + +clean: + rm -rf build + +rebuild: clean generate build-project + +server-run: + ./build/server/cmd/Server + +test: + ctest --verbose --test-dir build/ + +build-docker: + docker build . -f Dockerfile -t ddt-project + +dev: + docker run --rm -it \ + -v $(PWD):/project \ + --name app \ + raiden454/cpp-app + +stop-docker: + docker stop app diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..83583f19f22d50652553156652ee951e74c716f6 --- /dev/null +++ b/server/CMakeLists.txt @@ -0,0 +1,23 @@ +set(CMAKE_PREFIX_PATH build) +project(SourcedOut CXX) +# find_package(antlr4-runtime REQUIRED) +find_package(Boost 1.8.1 REQUIRED) +find_package(Threads REQUIRED) +find_library(PQXX_LIB pqxx) +find_package(GTest REQUIRED) +#find_package(nlohmann_json REQUIRED) +message(STATUS ${nlohmann_json_LIBRARIES}) + +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +add_subdirectory(pkg) +add_subdirectory(internal) +add_subdirectory(cmd) + +message(STATUS ${Boost_LIBRARIES}) +set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-lpthread -pthread") + +#add_subdirectory(cpp-dotenv) +#add_executable(${PROJECT_NAME} text-basic-metrics/tbm_main.cpp text-basic-metrics/tbm_main.cpp) строка для запуска моей части в text-basic-metrics +# target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES} ${antlr4-runtime_LIBRARIES} ${libpqxx_LIBRARIES} ${GTest_LIBRARIES}) \ No newline at end of file diff --git a/server/cmd/.env b/server/cmd/.env new file mode 100644 index 0000000000000000000000000000000000000000..7cac90d91390a5f095999d7b06b7b0e61d0ffc0a --- /dev/null +++ b/server/cmd/.env @@ -0,0 +1,6 @@ +PGHOSTADDR=0.0.0.0 +PGPORT=5432 +PGDATABASE=mydb +PGUSER=postgres +PGPASSWORD=root +POOL_SIZE=10 \ No newline at end of file diff --git a/server/cmd/CMakeLists.txt b/server/cmd/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8826a8d8b2c62a6414c33e23374f15b2c4fce2c9 --- /dev/null +++ b/server/cmd/CMakeLists.txt @@ -0,0 +1,11 @@ +set(PROJECT_NAME "Server") + +project(${PROJECT_NAME}) + +add_executable(Server main.cpp) +message(STATUS ${libusers}) +message("${SERVICE_LIB}") +target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES} ${libpqxx_LIBRARIES} ${SERVICE_LIB}) +target_include_directories(Server PUBLIC ${SERVICE_lib_INCLUDE_DIRS}) +message("Built server") + diff --git a/server/cmd/main.cpp b/server/cmd/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6f308ab5b7e389efef476a34ad3ead29a78879da --- /dev/null +++ b/server/cmd/main.cpp @@ -0,0 +1,45 @@ +#include + +#include "PythonAntlr.h" +#include "MyCppAntlr.h" +#include "TokenMetricLib.h" +#include "TextMetricsLib.h" +#include "DiffLib.h" + +int main(int argc, const char* argv[]) { + FoundSame foundSame; + + std::ifstream fin3("internal/metrics/testProgs/python/pycode1.txt"); + std::ifstream fin4("internal/metrics/testProgs/python/pycode2.txt"); + + PythonAntlr pyA1 = PythonAntlr(fin3); + PythonAntlr pyA2 = PythonAntlr(fin4); + + //MyCppAntlr cppA1 = MyCppAntlr(fin3); + //MyCppAntlr cppA2 = MyCppAntlr(fin4); + +// std::vector > str_int_tokens2 = cppA2.getTokensNamesWithPosition(); +// std::vector > str_int_tokens1 = cppA1.getTokensNamesWithPosition(); + + std::vector > > str_int_tokens2 = pyA2.getTokensNamesWithFullPosition(); + std::vector > > str_int_tokens1 = pyA1.getTokensNamesWithFullPosition(); + + for (auto & i : str_int_tokens1){ + std::cout << i.first << " {" << i.second.first << " " << i.second.second << "}\n"; + } + + foundSame.setData(str_int_tokens1, str_int_tokens2); + std::pair res = foundSame.getTexts(); + + std::ofstream out1("internal/metrics/testProgs/output/out1.txt"); + std::ofstream out2("internal/metrics/testProgs/output/out2.txt"); + + out1 << res.first; + out2 << res.second; + + out1.close(); + out2.close(); + fin3.close(); + fin4.close(); + return 0; +} \ No newline at end of file diff --git a/server/conanfile.txt b/server/conanfile.txt new file mode 100644 index 0000000000000000000000000000000000000000..e4b350b05b6838cf5c8ae735fc792b5cb408c9a2 --- /dev/null +++ b/server/conanfile.txt @@ -0,0 +1,10 @@ +[requires] +boost/1.81.0 +antlr4-cppruntime/4.12.0 +libpqxx/7.7.5 +gtest/cci.20210126 +nlohmann_json/3.11.2 + +[generators] +CMakeDeps +CMakeToolchain \ No newline at end of file diff --git a/server/internal/CMakeLists.txt b/server/internal/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8fe4e6ad0b05632748e7e578a9c72ba8ca012b80 --- /dev/null +++ b/server/internal/CMakeLists.txt @@ -0,0 +1,22 @@ +add_subdirectory(entities) +add_subdirectory(repository) +add_subdirectory(metrics) +add_subdirectory(service) + + +set(libEntities_LIB ${libEntities_LIB} PARENT_SCOPE) +set(libEntities_INCLUDE_DIRS ${libEntities_INCLUDE_DIRS} PARENT_SCOPE) + +set(METRICS_LIBRARY ${METRICS_LIBRARY} PARENT_SCOPE) +set(METRICS_lib_INCLUDE_DIRS ${METRICS_lib_INCLUDE_DIRS} PARENT_SCOPE) + + + + +set(libRepository_LIB ${libRepository_LIB} PARENT_SCOPE) +set(libRepository_INCLUDE_DIRS ${libRepository_INCLUDE_DIRS} PARENT_SCOPE) + + +set(SERVICE_LIB ${SERVICE_lib_LIBRARY} PARENT_SCOPE) +set(SERVICE_INCLUDE_DIRS ${SERVICE_lib_INCLUDE_DIRS} PARENT_SCOPE) + diff --git a/server/internal/entities/CMakeLists.txt b/server/internal/entities/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b6ad66178ab491134855e3b0327e11e56c73072 --- /dev/null +++ b/server/internal/entities/CMakeLists.txt @@ -0,0 +1,31 @@ +project("EntitiesLib") + +set(LIB_NAME libEntities) + +file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) +file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h) + +message("SOURCES = ${SOURCES}") +message("HEADERS = ${HEADERS}") + + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wextra -O2 -pedantic -Wformat=2 -Wfloat-equal -Wconversion \ +-Wlogical-op -Wshift-overflow=2 -Wduplicated-cond -Wcast-qual -Wcast-align") + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lboost_filesystem") + + +add_library(${LIB_NAME} ${SOURCES} ${HEADERS}) +target_include_directories(${LIB_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +#target_link_libraries(${LIB_NAME} ${Boost_LIBRARIES} nlohmann_json::nlohmann_json) + +set(libEntities_LIB ${LIB_NAME}) +set(libEntities_LIB ${libEntities_LIB} PARENT_SCOPE) +set(libEntities_INCLUDE_DIRS ${LIB_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/include) +set(libEntities_INCLUDE_DIRS ${libEntities_INCLUDE_DIRS} PARENT_SCOPE) + +message("libEntities_LIB = ${libEntities_LIB}") +message("libEntities_INCLUDE_DIRS = ${libEntities_INCLUDE_DIRS}") + +enable_testing() +add_subdirectory(tests) \ No newline at end of file diff --git a/server/internal/entities/include/MetricStat.hpp b/server/internal/entities/include/MetricStat.hpp new file mode 100644 index 0000000000000000000000000000000000000000..491abb7dd3297cc8d2ed31c4c6b010289324932e --- /dev/null +++ b/server/internal/entities/include/MetricStat.hpp @@ -0,0 +1,58 @@ +#ifndef SOURCEDOUT_METRICSTAT_HPP +#define SOURCEDOUT_METRICSTAT_HPP + +#include + +class MetricStat { +public: + MetricStat() noexcept; + + MetricStat(size_t solutionId, float textBasedRes, float tokenBasedRes, float treeBasedRes, bool verdict, + float meanRes) noexcept; + + MetricStat(size_t id, size_t solutionId, float textBasedRes, float tokenBasedRes, float treeBasedRes, bool verdict, + float meanRes) noexcept; + + [[nodiscard]] size_t getId() const noexcept; + + void setId(size_t id); + + [[nodiscard]] size_t getSolutionId() const noexcept; + + void setSolutionId(size_t solutionId) noexcept; + + [[nodiscard]] float getTextBasedRes() const noexcept; + + void setTextBasedRes(float textBasedRes) noexcept; + + [[nodiscard]] float getTokenBasedRes() const noexcept; + + void setTokenBasedRes(float tokenBasedRes) noexcept; + + [[nodiscard]] float getTreeBasedRes() const noexcept; + + void setTreeBasedRes(float treeBasedRes) noexcept; + + [[nodiscard]] bool isVerdict() const noexcept; + + void setVerdict(bool verdict) noexcept; + + [[nodiscard]] float getMeanRes() const noexcept; + + void setMeanRes(float meanRes) noexcept; + + bool operator==(const MetricStat &rhs) const noexcept; + + bool operator!=(const MetricStat &rhs) const noexcept; + +private: + size_t id; + size_t solution_id; + float text_based_res; + float token_based_res; + float tree_based_res; + bool verdict; + float mean_res; +}; + +#endif //SOURCEDOUT_METRICSTAT_HPP diff --git a/server/internal/entities/include/Solution.hpp b/server/internal/entities/include/Solution.hpp new file mode 100644 index 0000000000000000000000000000000000000000..974a560ccdb3e47878e2864707778b1102d41436 --- /dev/null +++ b/server/internal/entities/include/Solution.hpp @@ -0,0 +1,67 @@ +#ifndef SOURCEDOUT_SOLUTION_HPP +#define SOURCEDOUT_SOLUTION_HPP + +#include +#include +#include + +class Solution { +public: + Solution(size_t id, std::string sendDate, size_t senderId, std::string source, + std::string tokens, std::string astTree, size_t taskId, std::string result) noexcept; + + Solution(std::string sendDate, size_t senderId, std::string source, std::string tokens, std::string astTree, + size_t taskId, std::string result) noexcept; + Solution() noexcept; + + [[nodiscard]] size_t getId() const noexcept; + + + [[nodiscard]] const std::string &getSendDate() const noexcept; + + void setSendDate(const std::string &sendDate) noexcept; + + [[nodiscard]] size_t getSenderId() const noexcept; + + void setSenderId(size_t senderId) noexcept; + + [[nodiscard]] const std::string &getSource() const noexcept; + + void setSource(const std::string &source) noexcept; + + [[nodiscard]] const std::string &getTokens() const noexcept; + + void setTokens(const std::string &tokens) noexcept; + + [[nodiscard]] const std::string &getAstTree() const noexcept; + + void setAstTree(const std::string &astTree) noexcept; + + [[nodiscard]] size_t getTaskId() const noexcept; + + void setTaskId(size_t taskId) noexcept; + + [[nodiscard]] const std::string &getResult() const noexcept; + + void setResult(const std::string &result) noexcept; + + void setId(size_t id) noexcept; + + bool operator==(const Solution &rhs) const noexcept; + + bool operator!=(const Solution &rhs) const noexcept; + +private: + size_t id; + std::string send_date; + size_t sender_id; + std::string source; + std::string tokens; + std::string astTree; + size_t task_id; + std::string result; +public: + +}; + +#endif //SOURCEDOUT_SOLUTION_HPP diff --git a/server/internal/entities/include/Task.hpp b/server/internal/entities/include/Task.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e5518044893195135864aee103adbed6f16bb82f --- /dev/null +++ b/server/internal/entities/include/Task.hpp @@ -0,0 +1,35 @@ +#ifndef SOURCEDOUT_TASK_HPP +#define SOURCEDOUT_TASK_HPP +#include +#include +class Task{ +private: + size_t id; + std::string description; + float treshhold; + +public: + Task(size_t id, std::string description_, float treshold_) noexcept; + + Task(std::string description_, float treshold_) noexcept; + + Task() noexcept; + + [[nodiscard]] size_t getId() const noexcept; + + [[nodiscard]] const std::string &getDescription() const noexcept; + + float getTreshhold() const noexcept; + + void setTreshhold(float treshhold) noexcept; + + void setDescription(const std::string &description) noexcept; + + void setId(size_t id) noexcept; + + bool operator==(const Task &rhs) const noexcept; + + bool operator!=(const Task &rhs) const noexcept; + +}; +#endif //SOURCEDOUT_TASK_HPP diff --git a/server/internal/entities/include/User.hpp b/server/internal/entities/include/User.hpp new file mode 100644 index 0000000000000000000000000000000000000000..82e659f9095148269b76d334b43b36117629349b --- /dev/null +++ b/server/internal/entities/include/User.hpp @@ -0,0 +1,45 @@ +#ifndef SOURCEDOUT_USER_HPP + +#include +#include + +#define SOURCEDOUT_USER_HPP + +class User { +private: + size_t id; + std::string login; + std::string password; + std::string username; + +public: + User(size_t id_, std::string login_, std::string password_, std::string username_) noexcept; + + User(std::string login_, std::string password_, std::string username_) noexcept; + + User() noexcept; + + [[nodiscard]] const std::string &getLogin() const noexcept; + + void setLogin(const std::string &login) noexcept; + + [[nodiscard]] const std::string &getPassword() const noexcept; + + void setPassword(const std::string &password) noexcept; + + [[nodiscard]] const std::string &getUsername() const noexcept; + + void setUsername(const std::string &username) noexcept; + + [[nodiscard]] size_t getId() const noexcept; + + friend std::ostream &operator<<(std::ostream &os, const User &user) noexcept; + + void setId(size_t id) noexcept; + + bool operator==(const User &rhs) const noexcept; + + bool operator!=(const User &rhs) const noexcept; +}; + +#endif //SOURCEDOUT_USER_HPP diff --git a/server/internal/entities/src/MetricStat.cpp b/server/internal/entities/src/MetricStat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa0befc71722ddc28778494c1e9d8b3989a249ce --- /dev/null +++ b/server/internal/entities/src/MetricStat.cpp @@ -0,0 +1,81 @@ + +#include "MetricStat.hpp" + +MetricStat::MetricStat(unsigned long solutionId, float textBasedRes, float tokenBasedRes, float treeBasedRes, + bool verdict, float meanRes) noexcept : id(0), solution_id(solutionId), + text_based_res(textBasedRes), token_based_res(tokenBasedRes), + tree_based_res(treeBasedRes), verdict(verdict), + mean_res(meanRes) {} + +MetricStat::MetricStat(size_t id, size_t solutionId, float textBasedRes, float tokenBasedRes, float treeBasedRes, + bool verdict, float meanRes) noexcept : id(id), solution_id(solutionId), text_based_res(textBasedRes), + token_based_res(tokenBasedRes), tree_based_res(treeBasedRes), + verdict(verdict), mean_res(meanRes) {} + +MetricStat::MetricStat() noexcept : id(0), solution_id(0), text_based_res(0), token_based_res(0), tree_based_res(), + verdict(true), mean_res(0) { +} + +size_t MetricStat::getId() const noexcept { + return id; +} + +void MetricStat::setId(size_t id_) { + id = id_; +} + +size_t MetricStat::getSolutionId() const noexcept { + return solution_id; +} + +void MetricStat::setSolutionId(size_t solutionId) noexcept { + solution_id = solutionId; +} + +float MetricStat::getTextBasedRes() const noexcept { + return text_based_res; +} + +void MetricStat::setTextBasedRes(float textBasedRes) noexcept { + text_based_res = textBasedRes; +} + +float MetricStat::getTokenBasedRes() const noexcept { + return token_based_res; +} + +void MetricStat::setTokenBasedRes(float tokenBasedRes) noexcept { + token_based_res = tokenBasedRes; +} + +float MetricStat::getTreeBasedRes() const noexcept { + return tree_based_res; +} + +void MetricStat::setTreeBasedRes(float treeBasedRes) noexcept { + tree_based_res = treeBasedRes; +} + +bool MetricStat::isVerdict() const noexcept { + return verdict; +} + +void MetricStat::setVerdict(bool verdict_) noexcept { + verdict = verdict_; +} + +float MetricStat::getMeanRes() const noexcept { + return mean_res; +} + +void MetricStat::setMeanRes(float meanRes) noexcept { + mean_res = meanRes; +} + +bool MetricStat::operator==(const MetricStat &rhs) const noexcept { + return id == rhs.id; +} + +bool MetricStat::operator!=(const MetricStat &rhs) const noexcept { + return !(rhs == *this); +} diff --git a/server/internal/entities/src/Solution.cpp b/server/internal/entities/src/Solution.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0603c00cbb0eb713e7665ed5bfb4cce49dfca37c --- /dev/null +++ b/server/internal/entities/src/Solution.cpp @@ -0,0 +1,95 @@ + +#include +#include +#include "Solution.hpp" + +Solution::Solution(size_t id, std::string sendDate, unsigned long senderId, + std::string source, std::string tokens, + std::string astTree, unsigned long taskId, + std::string result) noexcept : id(id), send_date(std::move(sendDate)), sender_id(senderId), + source(std::move(source)), tokens(std::move(tokens)), + astTree(std::move(astTree)), + task_id(taskId), result(std::move(result)) {} + +Solution::Solution(std::string sendDate, unsigned long senderId, + std::string source, std::string tokens, + std::string astTree, unsigned long taskId, + std::string result) noexcept : id(0), send_date(std::move(sendDate)), sender_id(senderId), + source(std::move(source)), tokens(std::move(tokens)), + astTree(std::move(astTree)), + task_id(taskId), result(std::move(result)) {} + +Solution::Solution() noexcept : id(0), sender_id(0), task_id(0) {} + +size_t Solution::getId() const noexcept { + return id; +} + +void Solution::setId(size_t id_) noexcept { + id = id_; +} + +const std::string &Solution::getSendDate() const noexcept { + return send_date; +} + +void Solution::setSendDate(const std::string &sendDate) noexcept { + send_date = sendDate; +} + +size_t Solution::getSenderId() const noexcept { + return sender_id; +} + +void Solution::setSenderId(size_t senderId) noexcept { + sender_id = senderId; +} + +const std::string &Solution::getSource() const noexcept { + return source; +} + +void Solution::setSource(const std::string &source_) noexcept { + Solution::source = source_; +} + +const std::string &Solution::getTokens() const noexcept { + return tokens; +} + +void Solution::setTokens(const std::string &tokens_) noexcept { + Solution::tokens = tokens_; +} + +const std::string &Solution::getAstTree() const noexcept { + return astTree; +} + +void Solution::setAstTree(const std::string &astTree_) noexcept { + Solution::astTree = astTree_; +} + +size_t Solution::getTaskId() const noexcept { + return task_id; +} + +void Solution::setTaskId(size_t taskId) noexcept { + task_id = taskId; +} + +const std::string &Solution::getResult() const noexcept { + return result; +} + +void Solution::setResult(const std::string &result_) noexcept { + Solution::result = result_; +} + +bool Solution::operator==(const Solution &rhs) const noexcept { + return id == rhs.id; +} + +bool Solution::operator!=(const Solution &rhs) const noexcept { + return !(rhs == *this); +} + diff --git a/server/internal/entities/src/Task.cpp b/server/internal/entities/src/Task.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0fc10733fc4a2ab85888c8b2893c81bd51faded --- /dev/null +++ b/server/internal/entities/src/Task.cpp @@ -0,0 +1,43 @@ +#include "Task.hpp" +#include + +Task::Task(std::string description_, float treshold_) noexcept : id(0), description(std::move(description_)), + treshhold(treshold_) {} + +Task::Task(size_t id, std::string description_, float treshold_) noexcept : id(id), description(std::move(description_)), + treshhold(treshold_) {} +Task::Task() noexcept:id(0), treshhold(0) { +} + +unsigned long Task::getId() const noexcept { + return id; +} + +const std::string &Task::getDescription() const noexcept { + return description; +} + +void Task::setId(size_t id_) noexcept { + id = id_; +} + +void Task::setDescription(const std::string &description_) noexcept { + Task::description = description_; +} + +bool Task::operator==(const Task &rhs) const noexcept { + return id == rhs.id; +} + +bool Task::operator!=(const Task &rhs) const noexcept { + return !(rhs == *this); +} + +float Task::getTreshhold() const noexcept { + return treshhold; +} + +void Task::setTreshhold(float treshhold_) noexcept { + Task::treshhold = treshhold_; +} + diff --git a/server/internal/entities/src/User.cpp b/server/internal/entities/src/User.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67f2620dc4a925944d4fd349532eee764af4f57b --- /dev/null +++ b/server/internal/entities/src/User.cpp @@ -0,0 +1,59 @@ +#include +#include "../include/User.hpp" + +User::User(size_t id_, std::string login_, std::string password_, std::string username_) noexcept : + id(id_), login(std::move(login_)), password(std::move(password_)), username(std::move(username_)) { +} + +User::User(std::string login_, std::string password_, std::string username_) noexcept : + id(0), login(std::move(login_)), password(std::move(password_)), username(std::move(username_)) { +} + +User::User() noexcept : id(0) { +} + +const std::string &User::getLogin() const noexcept { + return login; +} + +void User::setId(size_t id_) noexcept { + id = id_; +} + +void User::setLogin(const std::string &login_) noexcept { + User::login = login_; +} + +const std::string &User::getPassword() const noexcept { + return password; +} + +void User::setPassword(const std::string &password_) noexcept { + User::password = password_; +} + +const std::string &User::getUsername() const noexcept { + return username; +} + +void User::setUsername(const std::string &username_) noexcept { + User::username = username_; +} + +size_t User::getId() const noexcept { + return id; +} + +std::ostream &operator<<(std::ostream &os, const User &user) noexcept { + os << "id: " << user.id << " login: " << user.login << " password: " << user.password << " username: " + << user.username; + return os; +} + +bool User::operator==(const User &rhs) const noexcept { + return id == rhs.id; +} + +bool User::operator!=(const User &rhs) const noexcept { + return !(rhs == *this); +} diff --git a/server/internal/entities/tests/CMakeLists.txt b/server/internal/entities/tests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/server/internal/metrics/CMakeLists.txt b/server/internal/metrics/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..531f6f6bfdc5a9bc7564cc06c844806cc402cc43 --- /dev/null +++ b/server/internal/metrics/CMakeLists.txt @@ -0,0 +1,28 @@ +project("MetricsLib") + +file(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) +file(GLOB INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include) + + +include_directories(${INCLUDE_DIRS}) +add_library(${PROJECT_NAME} ${SOURCES}) + +message("ANTLR4_LIB = ${ANTLR4_LIB}") +message("ANTLR4_LIB_INCLUDE_DIRS = ${ANTLR4_LIB_INCLUDE_DIRS}") + +target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIRS}) +target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES}) + + +set(METRICS_LIBRARY ${PROJECT_NAME}) +set(METRICS_LIBRARY ${METRICS_LIBRARY} PARENT_SCOPE) + + +set(METRICS_lib_INCLUDE_DIRS ${INCLUDE_DIRS}) +set(METRICS_lib_INCLUDE_DIRS ${METRICS_lib_INCLUDE_DIRS} PARENT_SCOPE) + + +enable_testing() +#if(BUILD_TESTS) +add_subdirectory(tests) +#endif() \ No newline at end of file diff --git a/server/internal/metrics/include/DiffLib.h b/server/internal/metrics/include/DiffLib.h new file mode 100644 index 0000000000000000000000000000000000000000..b24d9739977c4ad28d0376e63c807fb3521f7cee --- /dev/null +++ b/server/internal/metrics/include/DiffLib.h @@ -0,0 +1,38 @@ +// +// Created by march on 22.05.2023. +// + +#ifndef SOURCEDOUT_DIFFLIB_H +#define SOURCEDOUT_DIFFLIB_H + +#include +#include +#include +#include +#include +#include +#include + +class FoundSame { +public: + void setData(std::vector > > _tokens1, + std::vector > > _tokens2); + [[maybe_unused]] std::pair getTexts(); + +private: + struct Elem2 { + std::string op; // 1 - Insert, 2 - Delete, 3 - Copy, 4 - Replace + std::pair > token1; + std::pair > token2; + }; + + std::vector > > str_int_tokens1; + std::vector > > str_int_tokens2; + std::vector res_alignment; + + std::pair tokens2text(); + std::pair tokens2html(); + static void outOps (std::vector ops, std::string& str); +}; + +#endif //SOURCEDOUT_DIFFLIB_H diff --git a/server/internal/metrics/include/TextMetricsLib.h b/server/internal/metrics/include/TextMetricsLib.h new file mode 100644 index 0000000000000000000000000000000000000000..4db863f2a574c304d8717383634e2d9629ce59c9 --- /dev/null +++ b/server/internal/metrics/include/TextMetricsLib.h @@ -0,0 +1,45 @@ +// +// Created by march on 02.05.2023. +// + +#ifndef SOURCEDOUT_DECLARATION_H +#define SOURCEDOUT_DECLARATION_H + +#include +#include +#include +#include +#include +#include + +class ITextMetric { + public: + virtual ~ITextMetric() = default; + virtual void setData(std::string text1, std::string text2) = 0; + virtual double getMetric() = 0; +}; + +class PrepareDataTextMetric : public ITextMetric { + public: + void setData(std::string text1, std::string text2) override; + + protected: + std::vector tokens1; + std::vector tokens2; + + private: + static std::string deleteComments(const std::string& text); + static std::vector tbmTokenizer(const std::string& text); +}; + +class LevDistTextMetric : public PrepareDataTextMetric { + public: + double getMetric() override; +}; + +class JaccardTextMetric : public PrepareDataTextMetric { + public: + double getMetric() override; +}; + +#endif // SOURCEDOUT_DECLARATION_H diff --git a/server/internal/metrics/include/TokenMetricLib.h b/server/internal/metrics/include/TokenMetricLib.h new file mode 100644 index 0000000000000000000000000000000000000000..c333fe2abbb5c5b06801d4a19d77f5757dbb21f9 --- /dev/null +++ b/server/internal/metrics/include/TokenMetricLib.h @@ -0,0 +1,42 @@ +// +// Created by march on 04.05.2023. +// + +#ifndef SOURCEDOUT_TOKENMETRICLIB_H +#define SOURCEDOUT_TOKENMETRICLIB_H + +#include +#include +#include +#include +#include + +#include + + +class ITokenMetric{ + public: + virtual ~ITokenMetric() = default; + virtual void setData(std::vector tokens1, std::vector tokens2) = 0; + virtual double getMetric() = 0; +}; + +class PrepareDataTokenMetric : public ITokenMetric{ +public: + void setData(std::vector _tokens1, std::vector _tokens2) override; +protected: + std::vector tokens1; + std::vector tokens2; +}; + +class LevDistTokenMetric : public PrepareDataTokenMetric{ +public: + double getMetric() override; +}; + +class WShinglingTokenMetric : public PrepareDataTokenMetric{ +public: + double getMetric() override; +}; + +#endif //SOURCEDOUT_TOKENMETRICLIB_H diff --git a/server/internal/metrics/src/DiffLibImpl.cpp b/server/internal/metrics/src/DiffLibImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c9d55b7fe8e46cf27ae4cb5d1e388530f56d9c2 --- /dev/null +++ b/server/internal/metrics/src/DiffLibImpl.cpp @@ -0,0 +1,253 @@ +// +// Created by march on 22.05.2023. +// +#include + +#include "DiffLib.h" + +void FoundSame::setData(std::vector > > _tokens1, + std::vector > > _tokens2) { + str_int_tokens1 = std::move(_tokens2); + str_int_tokens2 = std::move(_tokens1); +} + +std::pair FoundSame::getTexts() { + unsigned long n = str_int_tokens1.size(); + unsigned long m = str_int_tokens2.size(); + + std::vector > dist (n + 1, std::vector (m + 1, 0)); + + for (size_t i = 0; i < n + 1; i++){ + dist[i][0] = static_cast (i); + } + + for (size_t i = 0; i < m + 1; i++){ + dist[0][i] = static_cast (i); + } + + std::vector > cache (n + 1, std::vector (m + 1)); + + for (size_t i = 1; i <= n; i++){ + cache[i][0] = {"I", {"%", str_int_tokens1[i-1].second}, str_int_tokens1[i-1]}; // str_int_tokens1[i-1].second мб кал + } + for (size_t i = 1; i <= m; i++){ + cache[0][i] = {"D", str_int_tokens2[i-1], {"#", str_int_tokens2[i-1].second}}; //аналогично + } + + std::pair > r, h; + for (size_t i = 1; i <= n; i++){ + for (size_t j = 1; j <= m; j++){ + h = str_int_tokens1[i-1], r = str_int_tokens2[j-1]; + std::vector > cases; + + if (r.first == h.first) + cases.push_back( {dist[i - 1][j - 1], {"C", r, h} } ); + else + cases.push_back({dist[i - 1][j - 1] + 1, {"R", r, h}}); + cases.push_back( { dist[i][j-1] + 1, {"D", r, {"#", r.second} } } ); + cases.push_back( { dist[i-1][j] + 1, {"I", {"%", h.second}, h} } ); + + dist[i][j] = cases[0].first; + cache[i][j] = cases[0].second; + + for (size_t k = 1; k < cases.size(); k++){ + if (dist[i][j] > cases[k].first){ + dist[i][j] = cases[k].first; + cache[i][j] = cases[k].second; + } + } + } + } + + std::vector alignment; + size_t i = n, j = m; + while (i != 0 || j != 0){ + std::string op = cache[i][j].op; + auto temp = cache[i][j]; +// if (temp.token1.second > temp.token2.second) { +// temp.token2.second = temp.token1.second; +// } +// else{ +// temp.token1.second = temp.token2.second; +// } + cache[i][j] = temp; + alignment.push_back(cache[i][j]); + if (op == "C" || op == "R"){ + i--, j--; + } else if (op == "I"){ + i--; + } else{ + j--; + } + } + std::reverse(alignment.begin(), alignment.end()); + + res_alignment = alignment; + + return tokens2html(); +} + +std::pair FoundSame::tokens2text() { + std::string res1, res2; + std::vector ops; + + int line = res_alignment[0].token1.second.first; + + for (auto & i : res_alignment){ + if (i.token1.second.first > line){ + while(line != i.token1.second.first){ + res1 += '\n'; + line++; + } + } + res1 += i.token1.first, res1 += " "; + } + + line = res_alignment[0].token2.second.first; + for (auto & i : res_alignment){ + if (i.token2.second.first > line){ + res2 += '\t'; + //outOps(ops, res2); + ops.clear(); + while(line < i.token2.second.first){ + res2+= '\n'; + line++; + } + } + ops.push_back(i.op); + res2 += i.token2.first, res2 += " "; + } + + res1.pop_back(), res2.pop_back(); + + return {res1, res2}; +} + +void FoundSame::outOps(std::vector ops, std::string& str) { + if (ops.empty()) return; + std::string o = ops[0]; + int f = 0; + for (auto & op : ops){ + if (op != o){ + f = 1; + break; + } + } + if (f == 0) + str += "[" + o + "]"; + else + for (auto & op : ops){ + str += op, str += " "; + } +} + +std::pair FoundSame::tokens2html() { + + std::string teg_I = ""; + std::string teg_D = ""; + std::string teg_C = ""; + std::string teg_R = ""; + std::string close_teg = ""; + + for (auto & i : res_alignment){ + + size_t pos; + while ((pos = i.token1.first.find("<")) != std::string::npos) { + i.token1.first.replace(pos, 1, "<"); + } + while ((pos = i.token1.first.find(">")) != std::string::npos) { + i.token1.first.replace(pos, 1, ">"); + } + + while ((pos = i.token2.first.find("<")) != std::string::npos) { + i.token2.first.replace(pos, 1, "<"); + } + while ((pos = i.token2.first.find(">")) != std::string::npos) { + i.token2.first.replace(pos, 1, ">"); + } + + if (i.token1.first == "%") { + i.token1.first = ""; + i.token1.second.first = -1; + } + + if (i.token2.first == "#") { + i.token2.first = ""; + i.token2.second.first = -1; + } + } + + std::string res1 = "\n" + "\n" + "
"; + std::string res2 = res1; + std::vector ops; + + int line = res_alignment[0].token1.second.first; + + int f = 0; + + for (auto & i : res_alignment){ + if (i.token1.second.first > line){ + while(line < i.token1.second.first){ + res1 += "
"; + res1 += '\n'; + line++; + } + f = 1; + } + if (f == 1){ + res1 += ""; + for (int k = 0; k < i.token1.second.second; k++){ + res1 += " "; + } + res1 += ""; + f = 0; + } + if (i.op == "I") res1 += teg_I; + if (i.op == "D") res1 += teg_D; + if (i.op == "C") res1 += teg_C; + if (i.op == "R") res1 += teg_R; + + res1 += i.token1.first; + if (!i.token1.first.empty()) res1 += " "; + res1 += close_teg; + } + + line = res_alignment[0].token2.second.first; + for (auto & i : res_alignment){ + if (i.token2.second.first > line){ + while(line < i.token2.second.first){ + res2 += "
"; + res2+= '\n'; + line++; + } + f = 1; + } + if (f == 1){ + res2 += ""; + for (int k = 0; k < i.token2.second.second; k++){ + res2 += " "; + } + res2 += ""; + f = 0; + } + if (i.op == "I") res2 += teg_I; + if (i.op == "D") res2 += teg_D; + if (i.op == "C") res2 += teg_C; + if (i.op == "R") res2 += teg_R; + + res2 += i.token2.first; + if (!i.token2.first.empty()) res2 += " "; + res2 += close_teg; + } + + res1 += "
\n" + ""; + res2 += "\n" + ""; + + return {res1, res2}; +} + + diff --git a/server/internal/metrics/src/TextMetricImpl.cpp b/server/internal/metrics/src/TextMetricImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..848c36bf6cfc1da24518fc279cb22275b9c89a26 --- /dev/null +++ b/server/internal/metrics/src/TextMetricImpl.cpp @@ -0,0 +1,117 @@ +// +// Created by march on 02.05.2023. +// + +#include "TextMetricsLib.h" + + +void PrepareDataTextMetric::setData(std::string text1, std::string text2) { + std::string non_comm_text1 = deleteComments(text1); + std::string non_comm_text2 = deleteComments(text2); + + tokens1 = tbmTokenizer(non_comm_text1); + tokens2 = tbmTokenizer(non_comm_text2); +} + +std::string PrepareDataTextMetric::deleteComments(const std::string& text) { + std::string modif; + std::string res; + + std::stringstream ss; + std::string line; + + ss << text; + + while(getline(ss, line)){ + line.push_back('\0'); + modif += line; + } + + bool s_comm = false; + bool m_comm = false; + + for (size_t i = 0; i < modif.size(); i++){ + if (s_comm && modif[i] == '\0') + s_comm = false; + else if (m_comm && modif[i] == '*' && modif[i + 1] == '/') + m_comm = false, i++; + else if (s_comm || m_comm) + continue; + else if (modif[i] == '/' && modif[i+1] == '/') + s_comm = true, i++; + else if (modif[i] == '/' && modif[i+1] == '*') + m_comm = true, i++; + + else if (modif[i] != '\0') + res += modif[i]; + else if (!res.empty() && res[res.size() - 1] != '\n') + res += '\n'; + } + return res; +} + +std::vector PrepareDataTextMetric::tbmTokenizer(const std::string &text) { + boost::char_separator sep(" {}();,\"\0\'"); + std::vector res; + boost::tokenizer < boost::char_separator > tokens(text, sep); + + for (const std::string &s: tokens) { + if (!s.empty() && s[0] != '\n' && s[0] != '\0'){ + res.push_back(s); + } + } + return res; +} + +double LevDistTextMetric::getMetric(){ + unsigned long n = tokens1.size(); + unsigned long m = tokens2.size(); + int x, y, z; + + std::vector > lev (n, std::vector (m, 0)); + + for (size_t i = 0; i < n; i++){ + for (size_t j = 0; j < m; j++){ + if (std::min(i, j) == 0){ + lev[i][j] = static_cast (std::max(i, j)); + } + else{ + x = lev[i-1][j]; + y = lev[i][j-1]; + z = lev[i-1][j-1]; + lev[i][j] = std::min(x, std::min(y, z)); + if (tokens1[i] != tokens2[j]){ + lev[i][j]++; + } + } + } + } + + if (n == 0 || m == 0) + return 0; + double res = 1.0 - static_cast (lev[n-1][m-1]) / static_cast (std::max(n ,m)); + return res; +} + + +double JaccardTextMetric::getMetric() { + std::set s1; + std::set s2; + + for (auto &i : tokens1) s1.insert(i); + for (auto &i : tokens2) s2.insert(i); + + + std::set intersect_sets; + set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), + std::inserter(intersect_sets, intersect_sets.begin())); + + std::set union_sets; + set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), + std::inserter(union_sets, union_sets.begin())); + + if (union_sets.empty()) + return 0; + else + return static_cast (intersect_sets.size()) / static_cast (union_sets.size()); +} diff --git a/server/internal/metrics/src/TokenMetricImpl.cpp b/server/internal/metrics/src/TokenMetricImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42e0d441ad9fc7260365c620ae3c6337512cd111 --- /dev/null +++ b/server/internal/metrics/src/TokenMetricImpl.cpp @@ -0,0 +1,79 @@ +// +// Created by march on 04.05.2023. +// + +#include "TokenMetricLib.h" + +double LevDistTokenMetric::getMetric() { + unsigned long n = tokens1.size(); + unsigned long m = tokens2.size(); + int x, y, z; + + std::vector > lev (n, std::vector (m, 0)); + + for (size_t i = 0; i < n; i++){ + for (size_t j = 0; j < m; j++){ + if (std::min(i, j) == 0){ + lev[i][j] = static_cast (std::max(i, j)); + } + else{ + x = lev[i-1][j]; + y = lev[i][j-1]; + z = lev[i-1][j-1]; + lev[i][j] = std::min(x, std::min(y, z)); + if (tokens1[i] != tokens2[j]){ + lev[i][j]++; + } + } + } + } + + if (n == 0 || m == 0) + return 0; + double res = 1.0 - static_cast (lev[n-1][m-1]) / static_cast (std::max(n ,m)); + return res; +} + +double WShinglingTokenMetric::getMetric() { + unsigned long n = tokens1.size(); + unsigned long m = tokens2.size(); + + if (n < 3 || m < 3) + return 0; + + std::vector > sh1; + std::vector > sh2; + + for (size_t i = 0; i < n - 2; i++){ + sh1.emplace_back(tokens1[i], tokens1[i+1], tokens1[i+2]); + } + for (size_t i = 0; i < m - 2; i++){ + sh2.emplace_back(tokens2[i], tokens2[i+1], tokens2[i+2]); + } + + std::set > s1; + std::set > s2; + + for (auto &i : sh1) s1.insert(i); + for (auto &i : sh2) s2.insert(i); + + + std::set> intersect_sets; + set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), + std::inserter(intersect_sets, intersect_sets.begin())); + + std::set> union_sets; + set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), + std::inserter(union_sets, union_sets.begin())); + + if (union_sets.empty()) + return 0; + else + return static_cast (intersect_sets.size()) / static_cast (union_sets.size()); + +} + +void PrepareDataTokenMetric::setData(std::vector _tokens1, std::vector _tokens2) { + tokens1 = std::move(_tokens1); + tokens2 = std::move(_tokens2); +} diff --git a/server/internal/metrics/testProgs/cpp/code1.txt b/server/internal/metrics/testProgs/cpp/code1.txt new file mode 100644 index 0000000000000000000000000000000000000000..24c4633827a7ec57212398549bbf91a6fe29f258 --- /dev/null +++ b/server/internal/metrics/testProgs/cpp/code1.txt @@ -0,0 +1,41 @@ +#include +#include + +using namespace std; + +bool check(vector s, int i, int j){ + for (int k = 0; k < s.size(); k++){ + if (s[k] != i && s[k] != j && s[k] % i == 0 && j % s[k] == 0){ + return 0; + } + } + return 1; +} + +int main(){ + long long n; + cin >> n; + vector s; + for (int i = 1; i <= n; i++){ + if (n % i == 0){ + s.push_back(i); + } + } + vector > ans; + for (int i = 0; i < s.size(); i++){ + for (int j = i + 1; j < s.size(); j++){ + if (s[j] % s[i] == 0 && check(s, s[i], s[j])){ + ans.push_back({s[i], s[j]}); + } + } + } + cout << "graph {" << endl; + for (int i = 0; i < s.size(); i++){ + cout << s[i] << endl; + } + + for (int i = 0; i < ans.size(); i++){ + cout << ans[i].first << "--" << ans[i].second << endl; + } + cout << "}"; +} \ No newline at end of file diff --git a/server/internal/metrics/testProgs/cpp/code2.txt b/server/internal/metrics/testProgs/cpp/code2.txt new file mode 100644 index 0000000000000000000000000000000000000000..d387566a40f5000bb4e62421384ebe0b43c63afb --- /dev/null +++ b/server/internal/metrics/testProgs/cpp/code2.txt @@ -0,0 +1,49 @@ +#include +#include + +using namespace std; + +bool check1(vector s, int i, int j){ + for (int k = 0; k < s.size(); k++){ + if (s[k] != i && s[k] != j && s[k] % i == 0 && j % s[k] == 0){ + return 0; + } + } + return 1; +} + +int main(){ + long long n1; + cin >> n1; + vector s2; + for (int k = 1; k <= n1; k++){ + if (n1 % k == 0){ + s2.push_back(k); + } + } + + if (n % 2 == 0) { + n+=1; + n-=1; + } + + vector > ans; + for (int i = 0; i < s2.size(); i++){ + for (int j = i + 1; j < s2.size(); j++){ + if (s2[j] % s2[i] == 0 && check1(s2, s2[i], s2[j])){ + ans.push_back({s[i], s[j]}); + } + } + } + cout << "graph {"; + cout << '\n'; + for (int k = 0; k < s2.size(); k++){ + cout << s[k] << endl; + } + + for (int i = 0; i < ans.size(); i++){ + cout << ans[i].first << "--" << ans[i].second << endl; + } + cout << "}"; + cout << '\n'; +} \ No newline at end of file diff --git a/server/internal/metrics/testProgs/cpp/code3.txt b/server/internal/metrics/testProgs/cpp/code3.txt new file mode 100644 index 0000000000000000000000000000000000000000..81966bf7c252c4505f1f71989bb27c16b1c44f5c --- /dev/null +++ b/server/internal/metrics/testProgs/cpp/code3.txt @@ -0,0 +1,12 @@ +#include + +using namespace std; + +int main() { + int a = 0, n; + cin >> n; + for (int i = 0; i < n; i++){ + a++; + cout << a; + } +} \ No newline at end of file diff --git a/server/internal/metrics/testProgs/cpp/code4.txt b/server/internal/metrics/testProgs/cpp/code4.txt new file mode 100644 index 0000000000000000000000000000000000000000..844d2cdfe00935ac33f54e74b027b59984009e65 --- /dev/null +++ b/server/internal/metrics/testProgs/cpp/code4.txt @@ -0,0 +1,45 @@ +#include +#include +#include +#include +using namespace std; +const int inf = 1e9; + + +int main() { + int n, s, f; + cin >> n >> s >> f; + s--; f--; + vector d(n, inf), p(n); + vector u(n); + vector < vector > > g(n); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + int q; + scanf("%d", &q); + if (i > 0) { + + } + } + } + d[s] = 0; + for (int i = 0; i < n; ++i) { + int v = -1; + for (int j = 0; j < n; ++j) + if (!u[j] && (v == -1 || d[j] < d[v])) + v = j; + if (d[v] == inf) break; + u[v] = true; + for (auto j : g[v]) { + int to = j.first; + int len = j.second; + if (d[v] + len < d[to]) { + d[to] = d[v] + len; + p[to] = v; + } + } + + } + cout << (d[f] == inf ? -1 : d[f]) << endl; + return 0; +} \ No newline at end of file diff --git a/server/internal/metrics/testProgs/output/out1.txt b/server/internal/metrics/testProgs/output/out1.txt new file mode 100644 index 0000000000000000000000000000000000000000..87281aa97c959e355d21968b55fc7b792a444270 --- /dev/null +++ b/server/internal/metrics/testProgs/output/out1.txt @@ -0,0 +1,41 @@ + + +
n , m = map ( int , input ( ) ) . split ( ) +
+arr = [ [ 0 for _ in range ( m ) ] for _ in range ( n ) ] +
+current_element = 1 +
+
+for diag_id in range ( n + m ) : +
+    if diag_id 2 == 0 : +
+        for x in range ( n ) : +
+            if 0 <= diag_id - x < m : +
+                arr [ x ] [ diag_id - x ] = current_element +
+                current_element += 1 +
+    else : +
+        for x in reversed ( range ( n ) ) : +
+            if 0 <= diag_id - x < m : +
+                arr [ x ] [ diag_id - x ] = current_element +
+                current_element += 1 + + + + +
+
+for line in arr : +
+    print ( * line ) + ) <EOF>
+ \ No newline at end of file diff --git a/server/internal/metrics/testProgs/output/out2.txt b/server/internal/metrics/testProgs/output/out2.txt new file mode 100644 index 0000000000000000000000000000000000000000..c33d11c863ee032a2202077ae53a8c86cb4b027e --- /dev/null +++ b/server/internal/metrics/testProgs/output/out2.txt @@ -0,0 +1,55 @@ + + +
n , m = map ( int , input ( ) ) . split ( ) +
+arr = [ [ 0 for _ in range ( m ) ] for _ in range ( n ) ] +
+current_element1 = 1 +
+
+for i in range ( n ) : +
+    print ( i ) + +
+
+for diag_id in range ( n + m ) : +
+    if diag_id % 2 == 0 : +
+        for x in range ( n ) : +
+            if 0 <= diag_id - x < m : +
+                arr [ x ] [ diag_id - x ] = current_element +
+                current_element += 1 +
+    else : +
+        for x in reversed ( range ( n ) ) : +
+            if 0 <= diag_id - x < m : +
+                arr [ x ] [ diag_id - x ] = current_element +
+                current_element += 1 +
+            if 0 <= diag_id - x < m : +
+                arr [ x ] [ diag_id - x ] = current_element +
+                current_element += 0 + + + + +
+
+
+
+for line in arr : +
+    print ( * line ) + ) <EOF>
+ \ No newline at end of file diff --git a/server/internal/metrics/testProgs/output/test1.html b/server/internal/metrics/testProgs/output/test1.html new file mode 100644 index 0000000000000000000000000000000000000000..878d452cfe7e23e79299b21837ce98b0e9659c2f --- /dev/null +++ b/server/internal/metrics/testProgs/output/test1.html @@ -0,0 +1,41 @@ + + +
n , m = map ( int , input ( ) ) . split ( ) +
+ arr = [ [ 0 for _ in range ( m ) ] for _ in range ( n ) ] +
+ current_element = 1 +
+
+ for diag_id in range ( n + m ) : +
+     if diag_id 2 == 0 : +
+         for x in range ( n ) : +
+             if 0 <= diag_id - x < m : +
+                 arr [ x ] [ diag_id - x ] = current_element +
+                 current_element += 1 +
+     else : +
+         for x in reversed ( range ( n ) ) : +
+             if 0 <= diag_id - x < m : +
+                 arr [ x ] [ diag_id - x ] = current_element +
+                 current_element += 1 + + + + +
+
+ for line in arr : +
+     print ( * line ) + ) <EOF>
+ \ No newline at end of file diff --git a/server/internal/metrics/testProgs/output/test2.html b/server/internal/metrics/testProgs/output/test2.html new file mode 100644 index 0000000000000000000000000000000000000000..7022d2f94c364f706124de4cc9dc8745212ad2bd --- /dev/null +++ b/server/internal/metrics/testProgs/output/test2.html @@ -0,0 +1,55 @@ + + +
n , m = map ( int , input ( ) ) . split ( ) +
+ arr = [ [ 0 for _ in range ( m ) ] for _ in range ( n ) ] +
+ current_element1 = 1 +
+
+ for i in range ( n ) : +
+     print ( i ) + +
+
+ for diag_id in range ( n + m ) : +
+     if diag_id % 2 == 0 : +
+         for x in range ( n ) : +
+             if 0 <= diag_id - x < m : +
+                 arr [ x ] [ diag_id - x ] = current_element +
+                 current_element += 1 +
+     else : +
+         for x in reversed ( range ( n ) ) : +
+             if 0 <= diag_id - x < m : +
+                 arr [ x ] [ diag_id - x ] = current_element +
+                 current_element += 1 +
+             if 0 <= diag_id - x < m : +
+                 arr [ x ] [ diag_id - x ] = current_element +
+                 current_element += 0 + + + + +
+
+
+
+ for line in arr : +
+     print ( * line ) + ) <EOF>
+ \ No newline at end of file diff --git a/server/internal/metrics/testProgs/python/pycode1.txt b/server/internal/metrics/testProgs/python/pycode1.txt new file mode 100644 index 0000000000000000000000000000000000000000..987fe46ae1fa9b045a7b26d0182b6f41493f3529 --- /dev/null +++ b/server/internal/metrics/testProgs/python/pycode1.txt @@ -0,0 +1,18 @@ +n, m = map(int, input()).split() +arr = [[0 for _ in range(m)] for _ in range(n)] +current_element = 1 + +for diag_id in range(n + m): + if diag_id % 2 == 0: + for x in range(n): + if 0 <= diag_id - x < m: + arr[x][diag_id - x] = current_element + current_element += 1 + else: + for x in reversed(range(n)): + if 0 <= diag_id - x < m: + arr[x][diag_id - x] = current_element + current_element += 1 + +for line in arr: + print(*line) \ No newline at end of file diff --git a/server/internal/metrics/testProgs/python/pycode2.txt b/server/internal/metrics/testProgs/python/pycode2.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6058de90278c32d93bbcec39a66d98c40a5ef4b --- /dev/null +++ b/server/internal/metrics/testProgs/python/pycode2.txt @@ -0,0 +1,26 @@ +n, m = map(int, input()).split() +arr = [[0 for _ in range(m)] for _ in range(n)] +current_element1 = 1 + +for i in range(n): + print(i) + +for diag_id in range(n + m): + if diag_id % 2 == 0: + for x in range(n): + if 0 <= diag_id - x < m: + arr[x][diag_id - x] = current_element + current_element += 1 + else: + for x in reversed(range(n)): + if 0 <= diag_id - x < m: + arr[x][diag_id - x] = current_element + current_element += 1 + if 0 <= diag_id - x < m: + arr[x][diag_id - x] = current_element + current_element += 0 + + + +for line in arr: + print(*line) \ No newline at end of file diff --git a/server/internal/metrics/testProgs/python/pycode3.txt b/server/internal/metrics/testProgs/python/pycode3.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b49d05c703b22f73b2b15a7090dbfa2d8e8e6ff --- /dev/null +++ b/server/internal/metrics/testProgs/python/pycode3.txt @@ -0,0 +1,19 @@ +n2, m2 = map(int, input()).split() +arr = [[0 for _ in range(m2)] for _ in range(n2)] +current_element = 1 + +for diag_id1 in range(n2 + m2): + if diag_id1 % 2 == 0: + for x in range(n): + if 0 <= diag_id1 - x < m2: + arr[x][diag_id1 - x] = current_element + current_element += 1 + else: + for x1 in reversed(range(n2)): + if 0 <= diag_id1 - x < m2: + arr[x][diag_id1 - x1] = current_element + current_element += 2 + current_element -= 1 + +for line1 in arr: + print(*line1) \ No newline at end of file diff --git a/server/internal/metrics/testProgs/python/pycode4.txt b/server/internal/metrics/testProgs/python/pycode4.txt new file mode 100644 index 0000000000000000000000000000000000000000..a7f014525b9f8416dd7d3d7306178f37b5281dc8 --- /dev/null +++ b/server/internal/metrics/testProgs/python/pycode4.txt @@ -0,0 +1,22 @@ +table = '' + + +def reverse_table(n): + global table + if n != 0: + str = input() + reverse_table(n - 1) + table += str[::-1] + '\n' + + + +n, m = map(int, input().split()) +reverse_table(n) +table = list(table) + +for i in range(len(table) - 1, 0, -1): + if table[i] == '\\' or table[i] == '/': + table[i + m + 1] = table[i] + table[i] = table[i - m - 1] + +print(''.join(table)) \ No newline at end of file diff --git a/server/internal/metrics/tests/CMakeLists.txt b/server/internal/metrics/tests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b5a55d4c1cf6aeaa1d772a77018a75d11bd41c3 --- /dev/null +++ b/server/internal/metrics/tests/CMakeLists.txt @@ -0,0 +1,7 @@ +file(GLOB SOURCES src/*.cpp) + +add_executable(metrics_test ${SOURCES}) + +target_link_libraries(metrics_test MetricsLib GTest::gtest_main GTest::gmock) + +add_test(metrics_test metrics_test) \ No newline at end of file diff --git a/server/internal/metrics/tests/src/main.cpp b/server/internal/metrics/tests/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..70cfa61104ff822a57412778fd4a5de924e2d23c --- /dev/null +++ b/server/internal/metrics/tests/src/main.cpp @@ -0,0 +1,13 @@ +// +// Created by march on 16.05.2023. +// + +#include +#include + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/text-basic-metrics/code1.txt b/server/internal/metrics/tests/src/test-codes/code1.txt similarity index 100% rename from text-basic-metrics/code1.txt rename to server/internal/metrics/tests/src/test-codes/code1.txt diff --git a/server/internal/metrics/tests/src/text_metrics_tests.cpp b/server/internal/metrics/tests/src/text_metrics_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2e79320b4a023bcc17a3f555d271b7ff144d346c --- /dev/null +++ b/server/internal/metrics/tests/src/text_metrics_tests.cpp @@ -0,0 +1,71 @@ +// +// Created by march on 04.05.2023. +// + +#include +#include + +#include "TextMetricsLib.h" + +class LevDistTextMetricTest : public ::testing::Test { +protected: + std::unique_ptr levDistTextMetric; + void SetUp(){ + levDistTextMetric = std::make_unique (); + } + void TearDown(){} +}; + +class JaccardTextMetricTest : public ::testing::Test { +protected: + std::unique_ptr jaccardTextMetric; + void SetUp(){ + jaccardTextMetric = std::make_unique (); + } + void TearDown(){} +}; + +TEST_F(LevDistTextMetricTest, check_eq_progs) { + + levDistTextMetric->setData("a b c d e f", "a b c d e f"); + + EXPECT_EQ(levDistTextMetric->getMetric(), 1); +} + +TEST_F(LevDistTextMetricTest, check_absolutely_not_eq_progs) { + + levDistTextMetric->setData("a b c", "d e f g"); + + EXPECT_EQ(levDistTextMetric->getMetric() < 0.5, true); +} + +TEST_F(LevDistTextMetricTest, test_with_empty_prog) { + + levDistTextMetric->setData("a b c", ""); + + EXPECT_EQ(levDistTextMetric->getMetric(), 0); +} + +TEST_F(JaccardTextMetricTest, check_eq_progs){ + + jaccardTextMetric->setData("a b c d e f", "d e a b c f"); + + EXPECT_EQ(jaccardTextMetric->getMetric(), 1); +} + +TEST_F(JaccardTextMetricTest, check_absolutely_not_eq_progs) { + + jaccardTextMetric->setData("a b c", "d e f g"); + + EXPECT_EQ(jaccardTextMetric->getMetric(), 0); +} + +TEST_F(JaccardTextMetricTest, test_with_empty_prog) { + + jaccardTextMetric->setData("a b c", ""); + + EXPECT_EQ(jaccardTextMetric->getMetric(), 0); +} + + + diff --git a/server/internal/metrics/tests/src/token_metrics_tests.cpp b/server/internal/metrics/tests/src/token_metrics_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e023d6b327ae6c9491b35a34a4a8fc3bc154428d --- /dev/null +++ b/server/internal/metrics/tests/src/token_metrics_tests.cpp @@ -0,0 +1,128 @@ +// +// Created by march on 16.05.2023. +// + +#include +#include + +#include + +#include "TokenMetricLib.h" + +class LevDistTokenMetricTest : public ::testing::Test { +protected: + std::unique_ptr levDistTokenMetric; + void SetUp(){ + levDistTokenMetric = std::make_unique (); + } + void TearDown(){} +}; + +class WShinglingTokenMetricTest : public ::testing::Test { +protected: + std::unique_ptr wShinglingTokenMetric; + void SetUp(){ + wShinglingTokenMetric = std::make_unique (); + } + void TearDown(){} +}; + +TEST_F(LevDistTokenMetricTest, check_eq_progs) { + + std::vector tokens1 = {1, 2, 3}; + + levDistTokenMetric->setData(tokens1, tokens1); + + EXPECT_EQ(levDistTokenMetric->getMetric(), 1); +} + +TEST_F(LevDistTokenMetricTest, check_absolutely_not_eq_progs) { + + std::vector tokens1 = {1, 2, 3}; + std::vector tokens2 = {3, 4, 5, 6}; + + levDistTokenMetric->setData(tokens1, tokens2); + + EXPECT_EQ(levDistTokenMetric->getMetric() < 0.5, true); +} + +TEST_F(LevDistTokenMetricTest, test_with_empty_prog) { + + std::vector tokens1 = {1, 2, 3}; + std::vector tokens2 = {}; + + levDistTokenMetric->setData(tokens1, tokens2); + + EXPECT_EQ(levDistTokenMetric->getMetric(), 0); +} + +TEST_F(WShinglingTokenMetricTest, check_eq_progs){ + + std::vector tokens1 = {1, 2, 3, 4, 5, 6}; + std::vector tokens2 = {1, 2, 3, 4, 5, 6}; + + wShinglingTokenMetric->setData(tokens1, tokens1); + + EXPECT_EQ(wShinglingTokenMetric->getMetric(), 1); +} + +TEST_F(WShinglingTokenMetricTest, check_absolutely_not_eq_progs) { + + std::vector tokens1 = {1, 2, 3}; + std::vector tokens2 = {4, 5, 6}; + + wShinglingTokenMetric->setData(tokens1, tokens2); + + EXPECT_EQ(wShinglingTokenMetric->getMetric(), 0); +} + +TEST_F(WShinglingTokenMetricTest, test_with_empty_prog) { + + std::vector tokens1 = {1, 2, 3}; + std::vector tokens2 = {}; + + wShinglingTokenMetric->setData(tokens1, tokens2); + + EXPECT_EQ(wShinglingTokenMetric->getMetric(), 0); +} + +TEST_F(WShinglingTokenMetricTest, test_with_empty_progs) { + + std::vector tokens1 = {}; + std::vector tokens2 = {}; + + wShinglingTokenMetric->setData(tokens1, tokens2); + + EXPECT_EQ(wShinglingTokenMetric->getMetric(), 0); +} + +TEST_F(WShinglingTokenMetricTest, test_with_small_size) { + + std::vector tokens1 = {1}; + std::vector tokens2 = {2, 3}; + + wShinglingTokenMetric->setData(tokens1, tokens2); + + double res = wShinglingTokenMetric->getMetric(); + EXPECT_EQ(res, 0); +} + +TEST_F(WShinglingTokenMetricTest, test_with_big_size) { + + std::vector tokens = {9, 45, 132, 85, 86, 89, 78, 45, 132, 128, 45, 132, 101, 1, + 128, 132, 127, 132, 103, 103, 132, 128, 84, 85, 132, 115, 1, 86, + 89, 43, 85, 132, 97, 1, 86, 132, 120, 128, 132, 113, 1, 128, 90, + 132, 127, 132, 102, 102, 132, 128, 59, 1, 128, 90, -1}; + + wShinglingTokenMetric->setData(tokens, tokens); + + double res = wShinglingTokenMetric->getMetric(); + EXPECT_EQ(res, 1); +} + + + + + + + diff --git a/server/internal/repository/CMakeLists.txt b/server/internal/repository/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..bee149e70d973e2da173369a75bb490c61d2ece7 --- /dev/null +++ b/server/internal/repository/CMakeLists.txt @@ -0,0 +1,32 @@ +project("RepositoryLib") + +set(LIB_NAME libRepository) + +file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) +file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h ${CMAKE_CURRENT_SOURCE_DIR}/virtual/*.hpp) + +message("SOURCES = ${SOURCES}") +message("HEADERS = ${HEADERS}") + + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wextra -O2 -pedantic -Wformat=2 -Wfloat-equal -Wconversion \ +-Wlogical-op -Wshift-overflow=2 -Wduplicated-cond -Wcast-qual -Wcast-align") + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lboost_filesystem") + + +add_library(${LIB_NAME} ${SOURCES} ${HEADERS}) +target_include_directories(${LIB_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/virtual) +target_link_libraries(${LIB_NAME} ${Boost_LIBRARIES} ${libpqxx_LIBRARIES} ${libEntities_LIB} ${libDbManager_LIB}) + +set(libRepository_LIB ${LIB_NAME}) +set(libRepository_LIB ${libRepository_LIB} PARENT_SCOPE) + +set(libRepository_INCLUDE_DIRS ${LIB_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/virtual) +set(libRepository_INCLUDE_DIRS ${libRepository_INCLUDE_DIRS} PARENT_SCOPE) + + +message(Entities_LIB = "${libEntities_LIB}") +message(dbManager = "${libDbManager_LIB}") +message("libRepository_LIB = ${libRepository_LIB}") +message("libRepository_INCLUDE_DIRS = ${libRepository_INCLUDE_DIRS}") diff --git a/server/internal/repository/virtual/IMetricRepository.hpp b/server/internal/repository/virtual/IMetricRepository.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fcd92fe7e4acf5f413a3937bc09cdb2117c25485 --- /dev/null +++ b/server/internal/repository/virtual/IMetricRepository.hpp @@ -0,0 +1,22 @@ +#ifndef SOURCEDOUT_IMETRICREPOSITORY_HPP +#define SOURCEDOUT_IMETRICREPOSITORY_HPP + + +#include +#include +#include "MetricStat.hpp" + +class IMetricRepository { +public: + virtual std::optional getById(size_t id) = 0; + + virtual size_t storeMetric(MetricStat metric) = 0; + + virtual void updateMetric(MetricStat metric) = 0; + + virtual void deleteMetric(MetricStat metric) = 0; + + virtual void deleteMetricById(size_t id) = 0; +}; + +#endif //SOURCEDOUT_IMETRICREPOSITORY_HPP diff --git a/server/internal/repository/virtual/ISolutionRepository.hpp b/server/internal/repository/virtual/ISolutionRepository.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3dfd3d9ce3c587e8c1402959210ff9c1a193d20c --- /dev/null +++ b/server/internal/repository/virtual/ISolutionRepository.hpp @@ -0,0 +1,30 @@ +#ifndef SOURCEDOUT_ISOLUTIONREPOSITORY_HPP +#define SOURCEDOUT_ISOLUTIONREPOSITORY_HPP + +#include +#include +#include "../../entities/include/Solution.hpp" + +class ISolutionRepository { + public: + virtual ~ISolutionRepository() = default; + virtual Solution getSolutionById(size_t id) = 0; + + virtual std::vector getSolutionsBySenderId(size_t sender_id) = 0; + virtual std::vector getSolutions(size_t sender_id, size_t task_id) = 0; + + + virtual std::vector getSolutionsByTaskId(size_t task_id) = 0; + + virtual size_t storeSolution(Solution solution) = 0; + + virtual void updateSolution(Solution solution) = 0; + + virtual void deleteSolutionById(size_t id) = 0; + + virtual void deleteSolution(Solution solution) = 0; + + +}; + +#endif //SOURCEDOUT_ISOLUTIONREPOSITORY_HPP diff --git a/server/internal/repository/virtual/ITaskRepository.hpp b/server/internal/repository/virtual/ITaskRepository.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c8a3588bf07d11f84c3c37573d9cd267ad539e96 --- /dev/null +++ b/server/internal/repository/virtual/ITaskRepository.hpp @@ -0,0 +1,24 @@ +#ifndef SOURCEDOUT_ITASKREPOSITORY_HPP +#define SOURCEDOUT_ITASKREPOSITORY_HPP + +#include +#include +#include "../../entities/include/Task.hpp" + +class ITaskRepository { + public: + virtual ~ITaskRepository() = default; + virtual Task getTaskById(size_t id) = 0; + + virtual std::vector getAllTasks() = 0; + + virtual void updateTask(Task task) = 0; + + virtual int storeTask(Task task) = 0; + + virtual void deleteTask(Task task) = 0; + + virtual void deleteTaskById(size_t task_id) = 0; +}; + +#endif //SOURCEDOUT_ITASKREPOSITORY_HPP diff --git a/server/internal/repository/virtual/IUserRepository.hpp b/server/internal/repository/virtual/IUserRepository.hpp new file mode 100644 index 0000000000000000000000000000000000000000..14d7a50ee86692f3768460ce520b78a50cf82f94 --- /dev/null +++ b/server/internal/repository/virtual/IUserRepository.hpp @@ -0,0 +1,23 @@ +#ifndef SOURCEDOUT_IUSERREPOSITORY_HPP +#define SOURCEDOUT_IUSERREPOSITORY_HPP + +#include +#include "../../entities/include/User.hpp" +class IUserRepository { +public: + virtual ~IUserRepository() = default; + virtual User getUserById(size_t id) = 0; + + virtual User getUserByLogin(std::string login) = 0; + + virtual size_t makeUser(User user) = 0; + + virtual void deleteUser(User user) = 0; + + virtual void deleteByUserId(size_t user_id) = 0; + + virtual std::vector getAllUsers() = 0; + +}; + +#endif //SOURCEDOUT_IUSERREPOSITORY_HPP diff --git a/server/internal/service/CMakeLists.txt b/server/internal/service/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..05699f792e677d21ad0105a50de58c431e6bc4f7 --- /dev/null +++ b/server/internal/service/CMakeLists.txt @@ -0,0 +1,26 @@ +project("ServiceLib") + +file(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) +file(GLOB INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/virtual) + + +include_directories(${INCLUDE_DIRS}) +add_library(${PROJECT_NAME} ${SOURCES}) + +message("ANTLR4_LIB = ${ANTLR4_LIB}") +message("ANTLR4_LIB_INCLUDE_DIRS = ${ANTLR4_LIB_INCLUDE_DIRS}") + +message("METRICS_lib_INCLUDE_DIRS=${METRICS_lib_INCLUDE_DIRS}") +message("METRICS_LIBRARY=${METRICS_LIBRARY}") + +target_include_directories(${PROJECT_NAME} PUBLIC ${INCLUDE_DIRS} ${libEntities_INCLUDE_DIRS} ${libRepository_INCLUDE_DIRS} ${ANTLR4_LIB_INCLUDE_DIRS} ${METRICS_lib_INCLUDE_DIRS}) +target_link_libraries(${PROJECT_NAME} ${libRepository_LIB} ${libEntities_LIB} ${ANTLR4_LIB} ${METRICS_LIBRARY}) + +set(SERVICE_lib_LIBRARY ${PROJECT_NAME}) +set(SERVICE_lib_LIBRARY ${SERVICE_lib_LIBRARY} PARENT_SCOPE) + +set(SERVICE_lib_INCLUDE_DIRS ${INCLUDE_DIRS}) +set(SERVICE_lib_INCLUDE_DIRS ${SERVICE_lib_INCLUDE_DIRS} PARENT_SCOPE) + +enable_testing() +add_subdirectory(tests) \ No newline at end of file diff --git a/server/internal/service/include/Exceptions.h b/server/internal/service/include/Exceptions.h new file mode 100644 index 0000000000000000000000000000000000000000..b15d6328066e1b96e994abe41ee5c7f848127281 --- /dev/null +++ b/server/internal/service/include/Exceptions.h @@ -0,0 +1,26 @@ +#pragma once + +class ValidateException : public std::exception { + std::string _msg; + + public: + ValidateException(const std::string& msg) : _msg(msg) {} + virtual const char* what() const noexcept override { return _msg.c_str(); } +}; + + +class LoginException : public std::exception { + std::string _msg; + + public: + LoginException(const std::string& msg) : _msg(msg) {} + virtual const char* what() const noexcept override { return _msg.c_str(); } +}; + +class FileExtensionException : public std::exception { + std::string _msg; + + public: + FileExtensionException(const std::string& msg) : _msg(msg) {} + virtual const char* what() const noexcept override { return _msg.c_str(); } +}; \ No newline at end of file diff --git a/server/internal/service/include/FileMethods.h b/server/internal/service/include/FileMethods.h new file mode 100644 index 0000000000000000000000000000000000000000..0ff8df34002475ed77baf828ac437f90eaee5010 --- /dev/null +++ b/server/internal/service/include/FileMethods.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +inline const std::string CPP_EXTENSION = "cpp"; +inline const std::string PYTHON_EXTENSION = "py"; +inline const std::string UNKNOWN_EXTENSION = ""; + +class FileMethods { + public: + static std::pair checkFileExtension( + const std::string& filename); +}; \ No newline at end of file diff --git a/server/internal/service/include/SolutionService.h b/server/internal/service/include/SolutionService.h new file mode 100644 index 0000000000000000000000000000000000000000..af7b811341fa63c1f34db299330da9b0034eae2a --- /dev/null +++ b/server/internal/service/include/SolutionService.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +#include "IAntlrWrapper.h" +#include "IMockMetrics.h" +#include "ISolutionRepository.hpp" +#include "ISolutionService.h" +#include "ITaskRepository.hpp" +#include "TextMetricsLib.h" +#include "TokenMetricLib.h" + +class SolutionService : ISolutionService { + private: + std::unique_ptr solutionRepo; + std::unique_ptr taskRepo; + std::unique_ptr antlr; + std::unique_ptr textMetric; + std::unique_ptr tokenMetric; + void setAntlrWrapper(const std::string& fileExtension, + const std::string& filedata); + std::string setResultVerdict(float textBasedRes, float tokenBasedRes, + float treshold); + std::pair getMaxTextResMetric(std::vector& solutions, + const std::string& filedata, + float treshold); + + std::pair getMaxTokenResMetric( + std::vector& solutions, std::vector& tokens, + float treshold); + + public: + explicit SolutionService(std::unique_ptr solutionRepo, + std::unique_ptr taskRepo); + SolutionService(); + void setMetrics(std::unique_ptr metrics_); + Solution createSolution(size_t userId, size_t taskId, + const std::string& filename, + const std::string& filedata) override; + std::vector getSolutionsByUserAndTaskId(size_t userId, + size_t taskId) override; + void deleteSolutionById(size_t solId) override; + std::pair getMetrics(size_t solId) override; +}; diff --git a/server/internal/service/include/TaskService.h b/server/internal/service/include/TaskService.h new file mode 100644 index 0000000000000000000000000000000000000000..d826e9ab4f8bf513f2965bea482b1590870d8016 --- /dev/null +++ b/server/internal/service/include/TaskService.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include "ITaskRepository.hpp" +#include "ITaskService.h" + +class TaskService : public ITaskService { + private: + std::unique_ptr taskRepo; + + public: + TaskService(std::unique_ptr taskRepo); + TaskService(); + Task createTask(const std::string& desc, float treshold = 0.5f) override; + Task getTask(size_t id) override; + std::vector getAllTasks() override; + void deleteTask(size_t id) override; +}; diff --git a/server/internal/service/include/UserService.h b/server/internal/service/include/UserService.h new file mode 100644 index 0000000000000000000000000000000000000000..9a266170227e795d21afc03e2247d70755cedfb7 --- /dev/null +++ b/server/internal/service/include/UserService.h @@ -0,0 +1,19 @@ +#pragma once +#include + +#include "IUserRepository.hpp" +#include "IUserService.h" +#include "UserValidator.h" + +class UserService : IUserService { + private: + std::unique_ptr userRepo; + + public: + explicit UserService(std::unique_ptr userRepo); + UserService(); + User createUser(const std::string& login, const std::string& username, + const std::string& password) override; + User login(const std::string& login, const std::string& password) override; + void deleteUser(size_t id) override; +}; diff --git a/server/internal/service/include/UserValidator.h b/server/internal/service/include/UserValidator.h new file mode 100644 index 0000000000000000000000000000000000000000..34459b6e355ce0e6437fca36c283a22ce351c0f8 --- /dev/null +++ b/server/internal/service/include/UserValidator.h @@ -0,0 +1,13 @@ +#pragma once + +#include "User.hpp" + +class UserValidator { + private: + static bool validateLogin(const std::string& login); + static bool validatePassword(const std::string& password); + static bool validateUsername(const std::string& username); + + public: + static bool validate(const User& user); +}; diff --git a/server/internal/service/include/Utils.h b/server/internal/service/include/Utils.h new file mode 100644 index 0000000000000000000000000000000000000000..20c67c83044f26f691c807f16634836ec8485756 --- /dev/null +++ b/server/internal/service/include/Utils.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +class Utils { + public: + static std::string convertIntArrayIntoString(std::vector& arr); + static std::vector convertStringIntoIntArray(const std::string& str); +}; diff --git a/server/internal/service/src/FileMethods.cpp b/server/internal/service/src/FileMethods.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6304eea4c8d6cda398701cb6406626190c6f46c8 --- /dev/null +++ b/server/internal/service/src/FileMethods.cpp @@ -0,0 +1,15 @@ +#include "FileMethods.h" + +#include +#include + +std::pair FileMethods::checkFileExtension( + const std::string& filename) { + if (filename.substr(filename.find_last_of(".") + 1) == CPP_EXTENSION) { + return std::make_pair(CPP_EXTENSION, true); + } + if (filename.substr(filename.find_last_of(".") + 1) == PYTHON_EXTENSION) { + return std::make_pair(PYTHON_EXTENSION, true); + } + return std::make_pair(UNKNOWN_EXTENSION, false); +} \ No newline at end of file diff --git a/server/internal/service/src/SolutionService.cpp b/server/internal/service/src/SolutionService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8aa704bdd8c1f5dc608e2d58088601fb6514d6ea --- /dev/null +++ b/server/internal/service/src/SolutionService.cpp @@ -0,0 +1,182 @@ +#include "SolutionService.h" + +#include +#include +#include + +#include "FileMethods.h" +#include "MyCppAntlr.h" +#include "PythonAntlr.h" +#include "Utils.h" + +const std::string PLAGIAT_VERDICT = "Не, ну вы не палитесь. Плагиат."; +const std::string NOT_PLAGIAT_VERDICT = + "Красивое решение. А главное уникальное !"; + +SolutionService::SolutionService( + std::unique_ptr solutionRepo, + std::unique_ptr taskRepo) + : solutionRepo(std::move(solutionRepo)), taskRepo(std::move(taskRepo)) {} + +SolutionService::SolutionService() { + // solutionRepo=std::make_unique(); + // taskRepo = std::make_unique(); +} + +void SolutionService::setAntlrWrapper(const std::string& fileExtension, + const std::string& filedata) { + std::istringstream in(filedata); + if (fileExtension == CPP_EXTENSION) { + antlr = std::make_unique(in); + } else if (fileExtension == PYTHON_EXTENSION) { + antlr = std::make_unique(in); + } +} + +std::string SolutionService::setResultVerdict(float textBasedRes, + float tokenBasedRes, + float treshold = 0.5f) { + float meanRes = (tokenBasedRes + textBasedRes) / 2; + if (meanRes < treshold) { + return NOT_PLAGIAT_VERDICT; + } + return PLAGIAT_VERDICT; +} + +std::pair SolutionService::getMaxTextResMetric( + std::vector& solutions, const std::string& filedata, + float treshold) { + std::pair maxMatch = std::make_pair(0.0, 0ul); + for (auto sol : solutions) { + textMetric = std::make_unique(); + textMetric->setData(filedata, sol.getSource()); + float textBasedRes = float(textMetric->getMetric()); + + textMetric = std::make_unique(); + textMetric->setData(filedata, sol.getSource()); + textBasedRes = (textBasedRes + float(textMetric->getMetric())) / 2; + + if (maxMatch.first < textBasedRes) { + maxMatch.first = textBasedRes; + maxMatch.second = sol.getSenderId(); + } + + if (textBasedRes > treshold) { + break; + } + } + return maxMatch; +} + +std::pair SolutionService::getMaxTokenResMetric( + std::vector& solutions, std::vector& tokens, + float treshold) { + std::pair maxMatch = std::make_pair(0.0, 0ul); + for (auto sol : solutions) { + tokenMetric = std::make_unique(); + tokenMetric->setData(tokens, + Utils::convertStringIntoIntArray(sol.getTokens())); + float tokenBasedRes = float(tokenMetric->getMetric()); + std::cout << tokenBasedRes << std::endl; + + std::cout << "Tokens from tokens" << std::endl; + for (int t : tokens) { + std::cout << t << " "; + } + std::cout << std::endl; + + std::cout << "Tokens from BD" << std::endl; + for (int t : Utils::convertStringIntoIntArray(sol.getTokens())) { + std::cout << t << " "; + } + std::cout << std::endl; + + tokenMetric = std::make_unique(); + tokenMetric->setData(tokens, + Utils::convertStringIntoIntArray(sol.getTokens())); + tokenBasedRes = (tokenBasedRes + float(tokenMetric->getMetric())) / 2; + + std::cout << tokenBasedRes << std::endl; + + if (maxMatch.first < tokenBasedRes) { + maxMatch.first = tokenBasedRes; + maxMatch.second = sol.getSenderId(); + } + + if (tokenBasedRes > treshold) { + break; + } + } + return maxMatch; +} + +Solution SolutionService::createSolution(size_t userId, size_t taskId, + const std::string& filename, + const std::string& filedata) { + try { + std::pair fileExtension = + FileMethods::checkFileExtension(filename); + if (!fileExtension.second) { + throw FileExtensionException("unknown file extension"); + } + + setAntlrWrapper(fileExtension.first, filedata); + std::vector tokensTypes = antlr->getTokensTypes(); + std::string astTree = antlr->getTreeString(); + + std::time_t now = + std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + + float treshold = taskRepo->getTaskById(taskId).getTreshhold(); + + std::vector solutions = + solutionRepo->getSolutionsByTaskId(taskId); + + std::pair textBasedRes = + getMaxTextResMetric(solutions, filedata, treshold); + std::pair tokenBasedRes = + getMaxTokenResMetric(solutions, tokensTypes, treshold); + + std::cout << textBasedRes.first << " " << tokenBasedRes.first << std::endl; + + std::string result = + setResultVerdict(textBasedRes.first, tokenBasedRes.first, treshold); + + Solution sol = Solution(std::ctime(&now), userId, filedata, + Utils::convertIntArrayIntoString(tokensTypes), + astTree, taskId, result); + size_t id = solutionRepo->storeSolution(sol); + sol.setId(id); + return sol; + } catch (std::exception& e) { + throw e; + } +} + +std::vector SolutionService::getSolutionsByUserAndTaskId( + size_t userId, size_t taskId) { + try { + return solutionRepo->getSolutions(userId, taskId); + } catch (std::exception& e) { + throw e; + } +} + +void SolutionService::deleteSolutionById(size_t solId) { + try { + solutionRepo->deleteSolutionById(solId); + } catch (std::exception& e) { + throw e; + } +} + +std::pair SolutionService::getMetrics(size_t solId) { + try { + Solution sol = solutionRepo->getSolutionById(solId); + std::string tokens = sol.getTokens(); + std::string astTree = sol.getAstTree(); + return std::make_pair(tokens, astTree); + } catch (std::exception& e) { + throw e; + } +} diff --git a/server/internal/service/src/TaskService.cpp b/server/internal/service/src/TaskService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c7d1bbfce73a787e62e77bac64f9dfee47267d6b --- /dev/null +++ b/server/internal/service/src/TaskService.cpp @@ -0,0 +1,44 @@ +#include "TaskService.h" + +TaskService::TaskService(std::unique_ptr taskRepo) + : taskRepo(std::move(taskRepo)) {} + +TaskService::TaskService() { + // TODO: раскоментировать, когда будет реализация + // taskRepo = std::make_unique(); +} + +Task TaskService::createTask(const std::string& desc, float treshold) { + try { + Task task = Task(desc,treshold); + size_t id = taskRepo->storeTask(task); + task.setId(id); + return task; + } catch (std::exception& e) { + throw e; + } +} + +std::vector TaskService::getAllTasks() { + try { + return taskRepo->getAllTasks(); + } catch (std::exception& e) { + throw e; + } +} + +Task TaskService::getTask(size_t id) { + try { + return taskRepo->getTaskById(id); + } catch (std::exception& e) { + throw e; + } +} + +void TaskService::deleteTask(size_t id) { + try { + taskRepo->deleteTaskById(id); + } catch (std::exception& e) { + throw e; + } +} diff --git a/server/internal/service/src/UserService.cpp b/server/internal/service/src/UserService.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b6b1666d1d2d7cc2297756bb31041ba6863b67e9 --- /dev/null +++ b/server/internal/service/src/UserService.cpp @@ -0,0 +1,48 @@ +#include "UserService.h" + +#include "Exceptions.h" +#include "UserValidator.h" + +UserService::UserService(std::unique_ptr userRepo) + : userRepo(std::move(userRepo)) {} + +UserService::UserService() { + // TODO: раскоментировать, когда будет реализация + // userRepo = std::make_unique(); +} + +User UserService::createUser(const std::string& login, const std::string& username, + const std::string& password) { + User user = User(login, password, username); + if (!UserValidator::validate(user)) { + throw ValidateException("invalid user params"); + } + try { + size_t id = userRepo->makeUser(user); + user.setId(id); + return user; + } catch (std::exception& e) { + throw e; + } +} + +User UserService::login(const std::string& login, const std::string& password) { + try { + User u = userRepo->getUserByLogin(login); + if (u.getPassword() != password){ + throw LoginException("incorrect password"); + } + return u; + } catch (std::exception& e) { + throw e; + } +} + + +void UserService::deleteUser(size_t id) { + try { + userRepo->deleteByUserId(id); + } catch (std::exception& e) { + throw e; + } +} diff --git a/server/internal/service/src/UserValidator.cpp b/server/internal/service/src/UserValidator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b653fc9af4a504efb2ffe17e7080adc8496a6f95 --- /dev/null +++ b/server/internal/service/src/UserValidator.cpp @@ -0,0 +1,34 @@ +#include "UserValidator.h" + +#include +#include + +bool UserValidator::validate(const User& user) { + if (validateLogin(user.getLogin()) && validatePassword(user.getPassword()) && + validateUsername(user.getUsername())) { + return true; + } + return false; +} + +bool UserValidator::validateLogin(const std::string& login) { + if (login.length() < 3 || login.length() > 30) { + return false; + } + const std::regex pattern("(\\w+)@(\\w+)(\\.(\\w+))+"); + return std::regex_match(login, pattern); +} + +bool UserValidator::validatePassword(const std::string& password) { + if (password.length() < 8 || password.length() > 30) { + return false; + } + return true; +} + +bool UserValidator::validateUsername(const std::string& username) { + if (username.length() < 3 || username.length() > 20) { + return false; + } + return true; +} diff --git a/server/internal/service/src/Utils.cpp b/server/internal/service/src/Utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..005748f89f67e8ae423ac8019fe7d1d812415dc5 --- /dev/null +++ b/server/internal/service/src/Utils.cpp @@ -0,0 +1,23 @@ +#include "Utils.h" + +#include +#include +#include +#include +#include + +std::string Utils::convertIntArrayIntoString(std::vector& arr) { + std::string str; + for (size_t i = 0; i < arr.size(); i++) { + str += std::to_string(arr[i]) + " "; + } + return str; +} + +std::vector Utils::convertStringIntoIntArray(const std::string& str) { + std::stringstream ss(str); + std::vector v; + + std::copy(std::istream_iterator(ss), {}, back_inserter(v)); + return v; +} diff --git a/server/internal/service/tests/CMakeLists.txt b/server/internal/service/tests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5dc8740fa010b643d39406582be5b37b0e1a5c09 --- /dev/null +++ b/server/internal/service/tests/CMakeLists.txt @@ -0,0 +1,17 @@ +project(test_service) + +set(CMAKE_CXX_STANDARD 20) +add_compile_options(-coverage) + +file(GLOB SOURCES *.cpp) + +enable_testing() +find_package(GTest REQUIRED) + +add_executable(${PROJECT_NAME} ${SOURCES}) + +target_link_libraries(${PROJECT_NAME} ${SERVICE_lib_LIBRARY} GTest::GTest gmock) +target_include_directories(${PROJECT_NAME} PUBLIC ${SERVICE_lib_INCLUDE_DIRS}) + + +add_test(test_service test_service) \ No newline at end of file diff --git a/server/internal/service/tests/SolutionServiceTest.cpp b/server/internal/service/tests/SolutionServiceTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43701101617da971cd5aeabf7811506ba999a8f7 --- /dev/null +++ b/server/internal/service/tests/SolutionServiceTest.cpp @@ -0,0 +1,123 @@ +#include +#include + +#include "SolutionService.h" + +class Exception : public std::exception { + std::string _msg; + + public: + Exception(const std::string& msg) : _msg(msg) {} + virtual const char* what() const noexcept override { return _msg.c_str(); } +}; + +class SolutionRepositoryMock : public ISolutionRepository { + public: + ~SolutionRepositoryMock() override = default; + MOCK_METHOD(Solution, getSolutionById, (size_t id), (override)); + MOCK_METHOD(std::vector, getSolutionsBySenderId, (size_t sender_id), + (override)); + MOCK_METHOD(std::vector, getSolutionsByTaskId, (size_t task_id), + (override)); + MOCK_METHOD(std::vector, getSolutions, + (size_t sender_id, size_t task_id), (override)); + MOCK_METHOD(size_t, storeSolution, (Solution solution), (override)); + MOCK_METHOD(void, updateSolution, (Solution solution), (override)); + MOCK_METHOD(void, deleteSolutionById, (size_t id), (override)); + MOCK_METHOD(void, deleteSolution, (Solution solution), (override)); +}; + +class TaskRepositoryMock : public ITaskRepository { + public: + ~TaskRepositoryMock() override = default; + MOCK_METHOD(Task, getTaskById, (size_t id), (override)); + MOCK_METHOD(void, updateTask, (Task task), (override)); + MOCK_METHOD(int, storeTask, (Task task), (override)); + MOCK_METHOD(void, deleteTask, (Task task), (override)); + MOCK_METHOD(void, deleteTaskById, (size_t id), (override)); + MOCK_METHOD(std::vector, getAllTasks, (), (override)); +}; + +struct SolutionServiceTest : public testing::Test { + SolutionService* ss; + SolutionRepositoryMock* solutionMockPtr; + TaskRepositoryMock* taskMockPtr; + + void SetUp() { + auto sMock = std::make_unique(); + solutionMockPtr = sMock.get(); + auto tMock = std::make_unique(); + taskMockPtr = tMock.get(); + ss = new SolutionService(std::move(sMock), std::move(tMock)); + } + void TearDown() { delete ss; } +}; + +ACTION(NoSolutionException) { + throw Exception("no solution with this id in db"); +} + +TEST_F(SolutionServiceTest, getSolutionsByUserAndTaskId) { + std::vector solutions; + solutions.push_back(Solution(0, "", 1, "", "", "", 1, "")); + solutions.push_back(Solution(1, "", 1, "", "", "", 1, "")); + EXPECT_CALL(*solutionMockPtr, getSolutions(1, 1)) + .Times(1) + .WillOnce(::testing::Return(solutions)); + std::vector sols = ss->getSolutionsByUserAndTaskId(1, 1); + EXPECT_EQ(sols.size(), 2); +} + +TEST_F(SolutionServiceTest, deleteSolution) { + EXPECT_CALL(*solutionMockPtr, deleteSolutionById(1)).Times(1); + ss->deleteSolutionById(1); +} + +TEST_F(SolutionServiceTest, deleteSolutionException) { + EXPECT_CALL(*solutionMockPtr, deleteSolutionById(-1)) + .Times(1) + .WillRepeatedly(NoSolutionException()); + EXPECT_THROW(ss->deleteSolutionById(-1), std::exception); +} + +TEST_F(SolutionServiceTest, getMetrics) { + EXPECT_CALL(*solutionMockPtr, getSolutionById(1)) + .Times(1) + .WillOnce(::testing::Return( + Solution(1, "", 1, "", "tokens", "astTree", 1, ""))); + std::pair metrics = ss->getMetrics(1); + EXPECT_EQ(metrics.first, "tokens"); + EXPECT_EQ(metrics.second, "astTree"); +} + +TEST_F(SolutionServiceTest, getMetricsException) { + EXPECT_CALL(*solutionMockPtr, getSolutionById(-1)) + .Times(1) + .WillRepeatedly(NoSolutionException()); + EXPECT_THROW(ss->getMetrics(-1), std::exception); +} + +TEST_F(SolutionServiceTest, createSolution) { + EXPECT_CALL(*solutionMockPtr, + storeSolution(Solution(0, "", 2, "source", "", "", 1, ""))) + .Times(1) + .WillRepeatedly(::testing::Return(1)); + + std::vector solutions; + solutions.push_back( + Solution(0, "", 1, "int main(){return 0;}", "45 132 85 86 89 59 1 128 90 -1", "", 1, "")); + //solutions.push_back(Solution(1, "", 1, "", "", "", 1, "")); + EXPECT_CALL(*solutionMockPtr, getSolutionsByTaskId(1)) + .Times(1) + .WillOnce(::testing::Return(solutions)); + + EXPECT_CALL(*taskMockPtr, getTaskById(1)) + .Times(1) + .WillOnce(::testing::Return(Task(1, "desription", 0.5f))); + + Solution sol = ss->createSolution(2, 1, "main.cpp", "int main(){return 0;}"); + EXPECT_EQ(sol.getId(), 1); + EXPECT_EQ(sol.getSource(), "int main(){return 0;}"); + EXPECT_EQ(sol.getTokens(), "45 132 85 86 89 59 1 128 90 -1 "); + EXPECT_EQ(sol.getResult(), "Не, ну вы не палитесь. Плагиат."); +} \ No newline at end of file diff --git a/server/internal/service/tests/TaskServiceTest.cpp b/server/internal/service/tests/TaskServiceTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ccf2c3837d7ff9e32e6ad237450c49947c697d43 --- /dev/null +++ b/server/internal/service/tests/TaskServiceTest.cpp @@ -0,0 +1,82 @@ +#include +#include + +#include "TaskService.h" + + +class Exception : public std::exception { + std::string _msg; + + public: + Exception(const std::string& msg) : _msg(msg) {} + virtual const char* what() const noexcept override { return _msg.c_str(); } +}; + +class TaskRepositoryMock : public ITaskRepository { + public: + ~TaskRepositoryMock() override = default; + MOCK_METHOD(Task, getTaskById, (size_t id), (override)); + MOCK_METHOD(void, updateTask, (Task task), (override)); + MOCK_METHOD(int, storeTask, (Task task), (override)); + MOCK_METHOD(void, deleteTask, (Task task), (override)); + MOCK_METHOD(void, deleteTaskById, (size_t id), (override)); + MOCK_METHOD(std::vector, getAllTasks,(),(override)); +}; + +struct TaskServiceTest : public testing::Test { + TaskService* ts; + TaskRepositoryMock* mock_ptr; + + void SetUp() { + auto mock = std::make_unique(); + mock_ptr = mock.get(); + ts = new TaskService(std::move(mock)); + } + void TearDown() { delete ts; } +}; + +ACTION(NoTaskException) { throw Exception("no task with this id in db"); } + +TEST_F(TaskServiceTest, deleteTaskById) { + EXPECT_CALL(*mock_ptr, deleteTaskById(1)).Times(1); + ts->deleteTask(1); +} + +TEST_F(TaskServiceTest, deleteTasWithInvalidId) { + EXPECT_CALL(*mock_ptr, deleteTaskById(1)) + .Times(1) + .WillRepeatedly(NoTaskException()); + EXPECT_THROW(ts->deleteTask(1), std::exception); +} + +TEST_F(TaskServiceTest, GetTaskByIdOK) { + EXPECT_CALL(*mock_ptr, getTaskById(1)) + .Times(1) + .WillOnce(::testing::Return(Task(1, "desription",0.7f))); + Task t = ts->getTask(1); + EXPECT_EQ(t.getId(), 1); + EXPECT_EQ(t.getDescription(), "desription"); +} + +TEST_F(TaskServiceTest, GetTaskByIdEXEPTION) { + EXPECT_CALL(*mock_ptr, getTaskById(-1)) + .Times(1) + .WillRepeatedly(NoTaskException()); + EXPECT_THROW(ts->getTask(-1), std::exception); +} + +TEST_F(TaskServiceTest, CreateTask) { + EXPECT_CALL(*mock_ptr, storeTask(Task("desc",0.5f))) + .Times(1) + .WillOnce(::testing::Return(1)); + Task t = ts->createTask("desc",0.5f); + EXPECT_EQ(t.getId(), 1); + EXPECT_EQ(t.getDescription(), "desc"); + + EXPECT_CALL(*mock_ptr, storeTask(Task("desc2",0.8f))) + .Times(1) + .WillOnce(::testing::Return(2)); + t = ts->createTask("desc2",0.8f); + EXPECT_EQ(t.getId(), 2); + EXPECT_EQ(t.getDescription(), "desc2"); +} diff --git a/server/internal/service/tests/UserServiceTest.cpp b/server/internal/service/tests/UserServiceTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e576a99b1adc84af2749a8c6995c5e369aa229e2 --- /dev/null +++ b/server/internal/service/tests/UserServiceTest.cpp @@ -0,0 +1,91 @@ +#include +#include + +#include "Exceptions.h" +#include "UserService.h" + + +class Exception : public std::exception { + std::string _msg; + + public: + Exception(const std::string& msg) : _msg(msg) {} + virtual const char* what() const noexcept override { return _msg.c_str(); } +}; + +class UserRepositoryMock : public IUserRepository { + public: + ~UserRepositoryMock() override = default; + MOCK_METHOD(User, getUserById, (size_t id), (override)); + MOCK_METHOD(User, getUserByLogin, (std::string login), (override)); + MOCK_METHOD(size_t, makeUser, (User user), (override)); + MOCK_METHOD(void, deleteUser, (User user), (override)); + MOCK_METHOD(void, deleteByUserId, (size_t id), (override)); + MOCK_METHOD(std::vector, getAllUsers, (), (override)); +}; + +struct UserServiceTest : public testing::Test { + UserService* us; + UserRepositoryMock* mock_ptr; + + void SetUp() { + auto mock = std::make_unique(); + mock_ptr = mock.get(); + us = new UserService(std::move(mock)); + } + void TearDown() { delete us; } +}; + +ACTION(NoUserException) { throw Exception("no user with this id in db"); } + +TEST_F(UserServiceTest, deleteUser) { + EXPECT_CALL(*mock_ptr, deleteByUserId(1)).Times(1); + us->deleteUser(1); +} + +TEST_F(UserServiceTest, deleteUserWithInvalidId) { + EXPECT_CALL(*mock_ptr, deleteByUserId(1)) + .Times(1) + .WillRepeatedly(NoUserException()); + EXPECT_THROW(us->deleteUser(1), std::exception); +} + +TEST_F(UserServiceTest, loginOk) { + EXPECT_CALL(*mock_ptr, getUserByLogin("login")) + .Times(1) + .WillOnce(::testing::Return(User(1, "login", "password", "username"))); + User u = us->login("login","password"); + EXPECT_EQ(u.getLogin(), "login"); + EXPECT_EQ(u.getId(), 1); + EXPECT_EQ(u.getPassword(), "password"); + EXPECT_EQ(u.getUsername(), "username"); +} + +TEST_F(UserServiceTest, loginInvalidLogin) { + EXPECT_CALL(*mock_ptr, getUserByLogin("loginnn")).Times(1).WillOnce(NoUserException()); + EXPECT_THROW(us->login("loginnn","password"), std::exception); +} + +TEST_F(UserServiceTest, loginInvalidPass) { + EXPECT_CALL(*mock_ptr, getUserByLogin("login")) + .Times(1) + .WillOnce(::testing::Return(User(1, "login", "password", "username"))); + EXPECT_THROW(us->login("login","password1"), std::exception); +} + +TEST_F(UserServiceTest, makeUserOk) { + EXPECT_CALL(*mock_ptr, makeUser(User("login@gmail.com", "password", "username"))) + .Times(1) + .WillOnce(::testing::Return(1)); + User u = us->createUser("login@gmail.com", "username", "password"); + EXPECT_EQ(u.getLogin(), "login@gmail.com"); + EXPECT_EQ(u.getId(), 1); + EXPECT_EQ(u.getPassword(), "password"); + EXPECT_EQ(u.getUsername(), "username"); +} + +TEST_F(UserServiceTest, makeUserInvalidData) { + EXPECT_CALL(*mock_ptr, makeUser(User("login", "password", "username"))) + .Times(0); + EXPECT_THROW(us->createUser("", "", ""), ValidateException); +} \ No newline at end of file diff --git a/server/internal/service/tests/UserValidatorTest.cpp b/server/internal/service/tests/UserValidatorTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a77c9c14ced248b4d2c686b7f0559e7e3577b91 --- /dev/null +++ b/server/internal/service/tests/UserValidatorTest.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include "UserValidator.h" + +TEST(UserValidatorTest, validateOK) { + EXPECT_TRUE(UserValidator::validate(User("login@gmail.com", "password", "username"))); +} + +TEST(UserValidatorTest, invalidLogin) { + EXPECT_FALSE(UserValidator::validate(User("", "password", "username"))); +} + +TEST(UserValidatorTest, invalidPassword) { + EXPECT_FALSE(UserValidator::validate(User("login", "", "username"))); +} + +TEST(UserValidatorTest, invalidUsername) { + EXPECT_FALSE(UserValidator::validate(User("login", "password", ""))); +} + +TEST(UserValidatorTest, invalidUserFields) { + EXPECT_FALSE(UserValidator::validate(User("", "", ""))); +} \ No newline at end of file diff --git a/server/internal/service/tests/main.cpp b/server/internal/service/tests/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ccb03731487f11418e7471cd8342ac0e4f81ae8 --- /dev/null +++ b/server/internal/service/tests/main.cpp @@ -0,0 +1,8 @@ +#include +#include + +int main(int argc, char** argv) { + ::testing::InitGoogleMock(&argc, argv); + + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/server/internal/service/virtual/IMockMetrics.h b/server/internal/service/virtual/IMockMetrics.h new file mode 100644 index 0000000000000000000000000000000000000000..d86a0f69e045523966ac4c50d01073853147b7fe --- /dev/null +++ b/server/internal/service/virtual/IMockMetrics.h @@ -0,0 +1,6 @@ +#pragma once + +class IMockMetrics { + public: + virtual void countMetric(); +}; diff --git a/server/internal/service/virtual/ISolutionService.h b/server/internal/service/virtual/ISolutionService.h new file mode 100644 index 0000000000000000000000000000000000000000..7c39d9c5dfa96085b13edbf49b9382b7c3f827d5 --- /dev/null +++ b/server/internal/service/virtual/ISolutionService.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "Solution.hpp" + +class ISolutionService { + public: + virtual ~ISolutionService() = default; + virtual Solution createSolution(size_t userId, size_t taskId, + const std::string& filename, + const std::string& filedata) = 0; + virtual std::vector getSolutionsByUserAndTaskId(size_t userId, + size_t taskId) = 0; + virtual void deleteSolutionById(size_t solId) = 0; + + virtual std::pair getMetrics(size_t solId) = 0; +}; diff --git a/server/internal/service/virtual/ITaskService.h b/server/internal/service/virtual/ITaskService.h new file mode 100644 index 0000000000000000000000000000000000000000..41501245fea6c102a6457e9377d591b065797957 --- /dev/null +++ b/server/internal/service/virtual/ITaskService.h @@ -0,0 +1,13 @@ +#pragma once +#include + +#include "Task.hpp" + +class ITaskService { + public: + virtual ~ITaskService() = default; + virtual Task createTask(const std::string& desc,float treshold) = 0; + virtual Task getTask(size_t id) = 0; + virtual std::vector getAllTasks() = 0; + virtual void deleteTask(size_t id) = 0; +}; diff --git a/server/internal/service/virtual/IUserService.h b/server/internal/service/virtual/IUserService.h new file mode 100644 index 0000000000000000000000000000000000000000..b3a0ab5d6a34923b0527f16aacbbf822b23c4b7a --- /dev/null +++ b/server/internal/service/virtual/IUserService.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include "User.hpp" + +class IUserService { + public: + virtual ~IUserService() = default; + virtual User createUser(const std::string& login, const std::string& username, + const std::string& password) = 0; + virtual User login(const std::string& login, const std::string& password) = 0; + virtual void deleteUser(size_t id) = 0; +}; diff --git a/server/pkg/CMakeLists.txt b/server/pkg/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f105ad52f9f205c401c2e5f15904b60fcc0bed87 --- /dev/null +++ b/server/pkg/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(antlr) + +set(ANTLR4_LIB ${ANTLR4_LIB} PARENT_SCOPE) +set(ANTLR4_LIB_INCLUDE_DIRS ${ANTLR4_LIB_INCLUDE_DIRS} PARENT_SCOPE) diff --git a/server/pkg/antlr/CMakeLists.txt b/server/pkg/antlr/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c69be37d7d52cc9ecccdb2dfe49abfdb91b3b2d --- /dev/null +++ b/server/pkg/antlr/CMakeLists.txt @@ -0,0 +1,27 @@ +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +set(CMAKE_CXX_STANDARD 20) + + +# set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-lpthread") +set(THREADS_PREFER_PTHREAD_FLAG ON) + + +include(ExternalAntlr4Cpp) +include_directories(${ANTLR4_INCLUDE_DIRS}) + + +set(ANTLR_EXECUTABLE /usr/local/lib/antlr-4.12.0-complete.jar) +find_package(ANTLR REQUIRED) + +add_subdirectory(cpp14) +add_subdirectory(python3) + +message("CPP_ANTLR_LIBRARY=${CPP_ANTLR_LIBRARY}") +message("PYTHON3_ANTLR_LIBRARY=${PYTHON3_ANTLR_LIBRARY}") + +set(ANTLR4_LIB ${CPP_ANTLR_LIBRARY} ${PYTHON3_ANTLR_LIBRARY}) +set(ANTLR4_LIB ${ANTLR4_LIB} PARENT_SCOPE) +set(ANTLR4_LIB_INCLUDE_DIRS ${CPP_ANTLR_INCLUDE_DIRS} ${PYTHON3_ANTLR_INCLUDE_DIRS}) +set(ANTLR4_LIB_INCLUDE_DIRS ${ANTLR4_LIB_INCLUDE_DIRS} PARENT_SCOPE) + diff --git a/server/pkg/antlr/cmake/ExternalAntlr4Cpp.cmake b/server/pkg/antlr/cmake/ExternalAntlr4Cpp.cmake new file mode 100644 index 0000000000000000000000000000000000000000..54f874b86be4fe787a640d9e9b560dac0fb0417a --- /dev/null +++ b/server/pkg/antlr/cmake/ExternalAntlr4Cpp.cmake @@ -0,0 +1,177 @@ +cmake_minimum_required(VERSION 3.7) + +if(POLICY CMP0114) + cmake_policy(SET CMP0114 NEW) +endif() + +include(ExternalProject) + +set(ANTLR4_ROOT ${CMAKE_CURRENT_BINARY_DIR}/antlr4_runtime/src/antlr4_runtime) +set(ANTLR4_INCLUDE_DIRS ${ANTLR4_ROOT}/runtime/Cpp/runtime/src) +set(ANTLR4_GIT_REPOSITORY https://github.com/antlr/antlr4.git) +if(NOT DEFINED ANTLR4_TAG) + # Set to branch name to keep library updated at the cost of needing to rebuild after 'clean' + # Set to commit hash to keep the build stable and does not need to rebuild after 'clean' + set(ANTLR4_TAG master) +endif() + +# Ensure that the include dir already exists at configure time (to avoid cmake erroring +# on non-existent include dirs) +file(MAKE_DIRECTORY "${ANTLR4_INCLUDE_DIRS}") + +if(${CMAKE_GENERATOR} MATCHES "Visual Studio.*") + set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/dist/$(Configuration)) +elseif(${CMAKE_GENERATOR} MATCHES "Xcode.*") + set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/dist/$(CONFIGURATION)) +else() + set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/dist) +endif() + +if(MSVC) + set(ANTLR4_STATIC_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/antlr4-runtime-static.lib) + set(ANTLR4_SHARED_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/antlr4-runtime.lib) + set(ANTLR4_RUNTIME_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/antlr4-runtime.dll) +else() + set(ANTLR4_STATIC_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.a) + if(MINGW) + set(ANTLR4_SHARED_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll.a) + set(ANTLR4_RUNTIME_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll) + elseif(CYGWIN) + set(ANTLR4_SHARED_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll.a) + set(ANTLR4_RUNTIME_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/cygantlr4-runtime-4.12.0.dll) + elseif(APPLE) + set(ANTLR4_RUNTIME_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dylib) + else() + set(ANTLR4_RUNTIME_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.so) + endif() +endif() + +if(${CMAKE_GENERATOR} MATCHES ".* Makefiles") + # This avoids + # 'warning: jobserver unavailable: using -j1. Add '+' to parent make rule.' + set(ANTLR4_BUILD_COMMAND $(MAKE)) +elseif(${CMAKE_GENERATOR} MATCHES "Visual Studio.*") + set(ANTLR4_BUILD_COMMAND + ${CMAKE_COMMAND} + --build . + --config $(Configuration) + --target) +elseif(${CMAKE_GENERATOR} MATCHES "Xcode.*") + set(ANTLR4_BUILD_COMMAND + ${CMAKE_COMMAND} + --build . + --config $(CONFIGURATION) + --target) +else() + set(ANTLR4_BUILD_COMMAND + ${CMAKE_COMMAND} + --build . + --target) +endif() + +if(NOT DEFINED ANTLR4_WITH_STATIC_CRT) + set(ANTLR4_WITH_STATIC_CRT ON) +endif() + +if(ANTLR4_ZIP_REPOSITORY) + ExternalProject_Add( + antlr4_runtime + PREFIX antlr4_runtime + URL ${ANTLR4_ZIP_REPOSITORY} + DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR} + BUILD_COMMAND "" + BUILD_IN_SOURCE 1 + SOURCE_DIR ${ANTLR4_ROOT} + SOURCE_SUBDIR runtime/Cpp + CMAKE_CACHE_ARGS + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DWITH_STATIC_CRT:BOOL=${ANTLR4_WITH_STATIC_CRT} + -DDISABLE_WARNINGS:BOOL=ON + # -DCMAKE_CXX_STANDARD:STRING=17 # if desired, compile the runtime with a different C++ standard + # -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} # alternatively, compile the runtime with the same C++ standard as the outer project + INSTALL_COMMAND "" + EXCLUDE_FROM_ALL 1) +else() + ExternalProject_Add( + antlr4_runtime + PREFIX antlr4_runtime + GIT_REPOSITORY ${ANTLR4_GIT_REPOSITORY} + GIT_TAG ${ANTLR4_TAG} + DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR} + BUILD_COMMAND "" + BUILD_IN_SOURCE 1 + SOURCE_DIR ${ANTLR4_ROOT} + SOURCE_SUBDIR runtime/Cpp + CMAKE_CACHE_ARGS + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DWITH_STATIC_CRT:BOOL=${ANTLR4_WITH_STATIC_CRT} + -DDISABLE_WARNINGS:BOOL=ON + # -DCMAKE_CXX_STANDARD:STRING=17 # if desired, compile the runtime with a different C++ standard + # -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} # alternatively, compile the runtime with the same C++ standard as the outer project + INSTALL_COMMAND "" + EXCLUDE_FROM_ALL 1) +endif() + +# Separate build step as rarely people want both +set(ANTLR4_BUILD_DIR ${ANTLR4_ROOT}) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0") + # CMake 3.14 builds in above's SOURCE_SUBDIR when BUILD_IN_SOURCE is true + set(ANTLR4_BUILD_DIR ${ANTLR4_ROOT}/runtime/Cpp) +endif() + +ExternalProject_Add_Step( + antlr4_runtime + build_static + COMMAND ${ANTLR4_BUILD_COMMAND} antlr4_static + # Depend on target instead of step (a custom command) + # to avoid running dependent steps concurrently + DEPENDS antlr4_runtime + BYPRODUCTS ${ANTLR4_STATIC_LIBRARIES} + EXCLUDE_FROM_MAIN 1 + WORKING_DIRECTORY ${ANTLR4_BUILD_DIR}) +ExternalProject_Add_StepTargets(antlr4_runtime build_static) + +add_library(antlr4_static STATIC IMPORTED) +add_dependencies(antlr4_static antlr4_runtime-build_static) +set_target_properties(antlr4_static PROPERTIES + IMPORTED_LOCATION ${ANTLR4_STATIC_LIBRARIES}) +target_include_directories(antlr4_static + INTERFACE + ${ANTLR4_INCLUDE_DIRS} +) + +ExternalProject_Add_Step( + antlr4_runtime + build_shared + COMMAND ${ANTLR4_BUILD_COMMAND} antlr4_shared + # Depend on target instead of step (a custom command) + # to avoid running dependent steps concurrently + DEPENDS antlr4_runtime + BYPRODUCTS ${ANTLR4_SHARED_LIBRARIES} ${ANTLR4_RUNTIME_LIBRARIES} + EXCLUDE_FROM_MAIN 1 + WORKING_DIRECTORY ${ANTLR4_BUILD_DIR}) +ExternalProject_Add_StepTargets(antlr4_runtime build_shared) + +add_library(antlr4_shared SHARED IMPORTED) +add_dependencies(antlr4_shared antlr4_runtime-build_shared) +set_target_properties(antlr4_shared PROPERTIES + IMPORTED_LOCATION ${ANTLR4_RUNTIME_LIBRARIES}) +target_include_directories(antlr4_shared + INTERFACE + ${ANTLR4_INCLUDE_DIRS} +) + +if(ANTLR4_SHARED_LIBRARIES) + set_target_properties(antlr4_shared PROPERTIES + IMPORTED_IMPLIB ${ANTLR4_SHARED_LIBRARIES}) +endif() diff --git a/server/pkg/antlr/cmake/FindANTLR.cmake b/server/pkg/antlr/cmake/FindANTLR.cmake new file mode 100644 index 0000000000000000000000000000000000000000..0ac8f8c79f939621c3a9405e51e0fa0648109107 --- /dev/null +++ b/server/pkg/antlr/cmake/FindANTLR.cmake @@ -0,0 +1,124 @@ +find_package(Java QUIET COMPONENTS Runtime) + +if(NOT ANTLR_EXECUTABLE) + find_program(ANTLR_EXECUTABLE + NAMES antlr.jar antlr4.jar antlr-4.jar antlr-4.12.0-complete.jar) +endif() + +if(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE) + execute_process( + COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE} + OUTPUT_VARIABLE ANTLR_COMMAND_OUTPUT + ERROR_VARIABLE ANTLR_COMMAND_ERROR + RESULT_VARIABLE ANTLR_COMMAND_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(ANTLR_COMMAND_RESULT EQUAL 0) + string(REGEX MATCH "Version [0-9]+(\\.[0-9]+)*" ANTLR_VERSION ${ANTLR_COMMAND_OUTPUT}) + string(REPLACE "Version " "" ANTLR_VERSION ${ANTLR_VERSION}) + else() + message( + SEND_ERROR + "Command '${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE}' " + "failed with the output '${ANTLR_COMMAND_ERROR}'") + endif() + + macro(ANTLR_TARGET Name InputFile) + set(ANTLR_OPTIONS LEXER PARSER LISTENER VISITOR) + set(ANTLR_ONE_VALUE_ARGS PACKAGE OUTPUT_DIRECTORY DEPENDS_ANTLR) + set(ANTLR_MULTI_VALUE_ARGS COMPILE_FLAGS DEPENDS) + cmake_parse_arguments(ANTLR_TARGET + "${ANTLR_OPTIONS}" + "${ANTLR_ONE_VALUE_ARGS}" + "${ANTLR_MULTI_VALUE_ARGS}" + ${ARGN}) + + set(ANTLR_${Name}_INPUT ${InputFile}) + + get_filename_component(ANTLR_INPUT ${InputFile} NAME_WE) + + if(ANTLR_TARGET_OUTPUT_DIRECTORY) + set(ANTLR_${Name}_OUTPUT_DIR ${ANTLR_TARGET_OUTPUT_DIRECTORY}) + else() + set(ANTLR_${Name}_OUTPUT_DIR + ${CMAKE_CURRENT_BINARY_DIR}/antlr4cpp_generated_src/${ANTLR_INPUT}) + endif() + + unset(ANTLR_${Name}_CXX_OUTPUTS) + + if((ANTLR_TARGET_LEXER AND NOT ANTLR_TARGET_PARSER) OR + (ANTLR_TARGET_PARSER AND NOT ANTLR_TARGET_LEXER)) + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.cpp) + set(ANTLR_${Name}_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.interp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.tokens) + else() + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.cpp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.cpp) + list(APPEND ANTLR_${Name}_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.interp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.tokens) + endif() + + if(ANTLR_TARGET_LISTENER) + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.cpp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.cpp) + list(APPEND ANTLR_TARGET_COMPILE_FLAGS -listener) + endif() + + if(ANTLR_TARGET_VISITOR) + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.cpp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.cpp) + list(APPEND ANTLR_TARGET_COMPILE_FLAGS -visitor) + endif() + + if(ANTLR_TARGET_PACKAGE) + list(APPEND ANTLR_TARGET_COMPILE_FLAGS -package ${ANTLR_TARGET_PACKAGE}) + endif() + + list(APPEND ANTLR_${Name}_OUTPUTS ${ANTLR_${Name}_CXX_OUTPUTS}) + + if(ANTLR_TARGET_DEPENDS_ANTLR) + if(ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT) + list(APPEND ANTLR_TARGET_DEPENDS + ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT}) + list(APPEND ANTLR_TARGET_DEPENDS + ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_OUTPUTS}) + else() + message(SEND_ERROR + "ANTLR target '${ANTLR_TARGET_DEPENDS_ANTLR}' not found") + endif() + endif() + + add_custom_command( + OUTPUT ${ANTLR_${Name}_OUTPUTS} + COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE} + ${InputFile} + -o ${ANTLR_${Name}_OUTPUT_DIR} + -no-listener + -Dlanguage=Cpp + ${ANTLR_TARGET_COMPILE_FLAGS} + DEPENDS ${InputFile} + ${ANTLR_TARGET_DEPENDS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Building ${Name} with ANTLR ${ANTLR_VERSION}") + endmacro(ANTLR_TARGET) + +endif(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + ANTLR + REQUIRED_VARS ANTLR_EXECUTABLE Java_JAVA_EXECUTABLE + VERSION_VAR ANTLR_VERSION) diff --git a/server/pkg/antlr/cmake/antlr4-generator.cmake.in b/server/pkg/antlr/cmake/antlr4-generator.cmake.in new file mode 100644 index 0000000000000000000000000000000000000000..63996514b0de9d619946f11b90585f8e0ecf7d95 --- /dev/null +++ b/server/pkg/antlr/cmake/antlr4-generator.cmake.in @@ -0,0 +1,181 @@ +set(ANTLR_VERSION @ANTLR_VERSION@) + +@PACKAGE_INIT@ + +if (NOT ANTLR4_CPP_GENERATED_SRC_DIR) + set(ANTLR4_GENERATED_SRC_DIR ${CMAKE_BINARY_DIR}/antlr4_generated_src) +endif() + +FIND_PACKAGE(Java COMPONENTS Runtime REQUIRED) + +# +# The ANTLR generator will output the following files given the input file f.g4 +# +# Input -> f.g4 +# Output -> f.h +# -> f.cpp +# +# the following files will only be produced if there is a parser contained +# Flag -visitor active +# Output -> BaseVisitor.h +# -> BaseVisitor.cpp +# -> Visitor.h +# -> Visitor.cpp +# +# Flag -listener active +# Output -> BaseListener.h +# -> BaseListener.cpp +# -> Listener.h +# -> Listener.cpp +# +# See documentation in markup +# +function(antlr4_generate + Antlr4_ProjectTarget + Antlr4_InputFile + Antlr4_GeneratorType + ) + + set( Antlr4_GeneratedSrcDir ${ANTLR4_GENERATED_SRC_DIR}/${Antlr4_ProjectTarget} ) + + get_filename_component(Antlr4_InputFileBaseName ${Antlr4_InputFile} NAME_WE ) + + list( APPEND Antlr4_GeneratorStatusMessage "Common Include-, Source- and Tokenfiles" ) + + if ( ${Antlr4_GeneratorType} STREQUAL "LEXER") + set(Antlr4_LexerBaseName "${Antlr4_InputFileBaseName}") + set(Antlr4_ParserBaseName "") + else() + if ( ${Antlr4_GeneratorType} STREQUAL "PARSER") + set(Antlr4_LexerBaseName "") + set(Antlr4_ParserBaseName "${Antlr4_InputFileBaseName}") + else() + if ( ${Antlr4_GeneratorType} STREQUAL "BOTH") + set(Antlr4_LexerBaseName "${Antlr4_InputFileBaseName}Lexer") + set(Antlr4_ParserBaseName "${Antlr4_InputFileBaseName}Parser") + else() + message(FATAL_ERROR "The third parameter must be LEXER, PARSER or BOTH") + endif () + endif () + endif () + + # Prepare list of generated targets + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}.tokens" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}.interp" ) + list( APPEND DependentTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}.tokens" ) + + if ( NOT ${Antlr4_LexerBaseName} STREQUAL "" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_LexerBaseName}.h" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_LexerBaseName}.cpp" ) + endif () + + if ( NOT ${Antlr4_ParserBaseName} STREQUAL "" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_ParserBaseName}.h" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_ParserBaseName}.cpp" ) + endif () + + # process optional arguments ... + + if ( ( ARGC GREATER_EQUAL 4 ) AND ARGV3 ) + set(Antlr4_BuildListenerOption "-listener") + + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}BaseListener.h" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}BaseListener.cpp" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}Listener.h" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}Listener.cpp" ) + + list( APPEND Antlr4_GeneratorStatusMessage ", Listener Include- and Sourcefiles" ) + else() + set(Antlr4_BuildListenerOption "-no-listener") + endif () + + if ( ( ARGC GREATER_EQUAL 5 ) AND ARGV4 ) + set(Antlr4_BuildVisitorOption "-visitor") + + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}BaseVisitor.h" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}BaseVisitor.cpp" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}Visitor.h" ) + list( APPEND Antlr4_GeneratedTargets "${Antlr4_GeneratedSrcDir}/${Antlr4_InputFileBaseName}Visitor.cpp" ) + + list( APPEND Antlr4_GeneratorStatusMessage ", Visitor Include- and Sourcefiles" ) + else() + set(Antlr4_BuildVisitorOption "-no-visitor") + endif () + + if ( (ARGC GREATER_EQUAL 6 ) AND (NOT ${ARGV5} STREQUAL "") ) + set(Antlr4_NamespaceOption "-package;${ARGV5}") + + list( APPEND Antlr4_GeneratorStatusMessage " in Namespace ${ARGV5}" ) + else() + set(Antlr4_NamespaceOption "") + endif () + + if ( (ARGC GREATER_EQUAL 7 ) AND (NOT ${ARGV6} STREQUAL "") ) + set(Antlr4_AdditionalDependencies ${ARGV6}) + else() + set(Antlr4_AdditionalDependencies "") + endif () + + if ( (ARGC GREATER_EQUAL 8 ) AND (NOT ${ARGV7} STREQUAL "") ) + set(Antlr4_LibOption "-lib;${ARGV7}") + + list( APPEND Antlr4_GeneratorStatusMessage " using Library ${ARGV7}" ) + else() + set(Antlr4_LibOption "") + endif () + + if(NOT Java_FOUND) + message(FATAL_ERROR "Java is required to process grammar or lexer files! - Use 'FIND_PACKAGE(Java COMPONENTS Runtime REQUIRED)'") + endif() + + if(NOT EXISTS "${ANTLR4_JAR_LOCATION}") + message(FATAL_ERROR "Unable to find antlr tool. ANTLR4_JAR_LOCATION:${ANTLR4_JAR_LOCATION}") + endif() + + # The call to generate the files + add_custom_command( + OUTPUT ${Antlr4_GeneratedTargets} + # Remove target directory + COMMAND + ${CMAKE_COMMAND} -E remove_directory ${Antlr4_GeneratedSrcDir} + # Create target directory + COMMAND + ${CMAKE_COMMAND} -E make_directory ${Antlr4_GeneratedSrcDir} + COMMAND + # Generate files + "${Java_JAVA_EXECUTABLE}" -jar "${ANTLR4_JAR_LOCATION}" -Werror -Dlanguage=Cpp ${Antlr4_BuildListenerOption} ${Antlr4_BuildVisitorOption} ${Antlr4_LibOption} ${ANTLR4_GENERATED_OPTIONS} -o "${Antlr4_GeneratedSrcDir}" ${Antlr4_NamespaceOption} "${Antlr4_InputFile}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + MAIN_DEPENDENCY "${Antlr4_InputFile}" + DEPENDS ${Antlr4_AdditionalDependencies} + ) + + # set output variables in parent scope + set( ANTLR4_INCLUDE_DIR_${Antlr4_ProjectTarget} ${Antlr4_GeneratedSrcDir} PARENT_SCOPE) + set( ANTLR4_SRC_FILES_${Antlr4_ProjectTarget} ${Antlr4_GeneratedTargets} PARENT_SCOPE) + set( ANTLR4_TOKEN_FILES_${Antlr4_ProjectTarget} ${DependentTargets} PARENT_SCOPE) + set( ANTLR4_TOKEN_DIRECTORY_${Antlr4_ProjectTarget} ${Antlr4_GeneratedSrcDir} PARENT_SCOPE) + + # export generated cpp files into list + foreach(generated_file ${Antlr4_GeneratedTargets}) + + if (NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + set_source_files_properties( + ${generated_file} + PROPERTIES + COMPILE_FLAGS -Wno-overloaded-virtual + ) + endif () + + if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + set_source_files_properties( + ${generated_file} + PROPERTIES + COMPILE_FLAGS -wd4251 + ) + endif () + + endforeach(generated_file) + +message(STATUS "Antlr4 ${Antlr4_ProjectTarget} - Building " ${Antlr4_GeneratorStatusMessage} ) + +endfunction() diff --git a/server/pkg/antlr/cmake/antlr4-runtime.cmake.in b/server/pkg/antlr/cmake/antlr4-runtime.cmake.in new file mode 100644 index 0000000000000000000000000000000000000000..697b36c628172d5439476c4e28b67ea1fa64ca26 --- /dev/null +++ b/server/pkg/antlr/cmake/antlr4-runtime.cmake.in @@ -0,0 +1,13 @@ +set(ANTLR_VERSION @ANTLR_VERSION@) + +@PACKAGE_INIT@ + +set_and_check(ANTLR4_INCLUDE_DIR "@PACKAGE_ANTLR4_INCLUDE_DIR@") +set_and_check(ANTLR4_LIB_DIR "@PACKAGE_ANTLR4_LIB_DIR@") + +include(CMakeFindDependencyMacro) +find_dependency(Threads) + +include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake) + +check_required_components(antlr) diff --git a/server/pkg/antlr/cpp14/CMakeLists.txt b/server/pkg/antlr/cpp14/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c3100fcaf43d34bc7ecb64894a5f0dc735585b5 --- /dev/null +++ b/server/pkg/antlr/cpp14/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.7) +project(cpp_antlr_lib) + +file(GLOB SOURCES ./src/*.cpp) +file(GLOB INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/../virtual) + + +antlr_target(CPP14GrammarLexer CPP14Lexer.g4 LEXER + PACKAGE antlrcpptest) +antlr_target(CPP14GrammarParser CPP14Parser.g4 PARSER + PACKAGE antlrcpptest + DEPENDS_ANTLR CPP14GrammarLexer + COMPILE_FLAGS -lib ${ANTLR_CPP14GrammarLexer_OUTPUT_DIR}) + +include_directories(${ANTLR_CPP14GrammarLexer_OUTPUT_DIR}) +include_directories(${ANTLR_CPP14GrammarParser_OUTPUT_DIR}) + + +message("ANTLR_CPP14GrammarParser_OUTPUT_DIR=${ANTLR_CPP14GrammarParser_OUTPUT_DIR}") + +include_directories(${INCLUDE_DIRS}) +add_library(${PROJECT_NAME} ${SOURCES} ${ANTLR_CPP14GrammarLexer_CXX_OUTPUTS} ${ANTLR_CPP14GrammarParser_CXX_OUTPUTS}) + + +target_link_libraries(${PROJECT_NAME} antlr4_static Threads::Threads) + +set(CPP_ANTLR_LIBRARY ${PROJECT_NAME}) +set(CPP_ANTLR_LIBRARY ${CPP_ANTLR_LIBRARY} PARENT_SCOPE) + +set(CPP_ANTLR_INCLUDE_DIRS ${INCLUDE_DIRS} ${ANTLR_CPP14GrammarLexer_OUTPUT_DIR} ${ANTLR_CPP14GrammarParser_OUTPUT_DIR}) +set(CPP_ANTLR_INCLUDE_DIRS ${CPP_ANTLR_INCLUDE_DIRS} PARENT_SCOPE) + +message("CPP_ANTLR = ${CPP_ANTLR_INCLUDE_DIRS} ") \ No newline at end of file diff --git a/server/pkg/antlr/cpp14/CPP14Lexer.g4 b/server/pkg/antlr/cpp14/CPP14Lexer.g4 new file mode 100644 index 0000000000000000000000000000000000000000..860e6d20c0c0d7774707bd9d10ad1cb8d53fa5b7 --- /dev/null +++ b/server/pkg/antlr/cpp14/CPP14Lexer.g4 @@ -0,0 +1,409 @@ +lexer grammar CPP14Lexer; + +IntegerLiteral: + DecimalLiteral Integersuffix? + | OctalLiteral Integersuffix? + | HexadecimalLiteral Integersuffix? + | BinaryLiteral Integersuffix?; + +CharacterLiteral: + ('u' | 'U' | 'L')? '\'' Cchar+ '\''; + +FloatingLiteral: + Fractionalconstant Exponentpart? Floatingsuffix? + | Digitsequence Exponentpart Floatingsuffix?; + +StringLiteral: + Encodingprefix? + (Rawstring + |'"' Schar* '"'); + +BooleanLiteral: False_ | True_; + +PointerLiteral: Nullptr; + +UserDefinedLiteral: + UserDefinedIntegerLiteral + | UserDefinedFloatingLiteral + | UserDefinedStringLiteral + | UserDefinedCharacterLiteral; + +MultiLineMacro: + '#' (~[\n]*? '\\' '\r'? '\n')+ ~ [\n]+ -> channel (HIDDEN); + +Directive: '#' ~ [\n]* -> channel (HIDDEN); +/*Keywords*/ + +Alignas: 'alignas'; + +Alignof: 'alignof'; + +Asm: 'asm'; + +Auto: 'auto'; + +Bool: 'bool'; + +Break: 'break'; + +Case: 'case'; + +Catch: 'catch'; + +Char: 'char'; + +Char16: 'char16_t'; + +Char32: 'char32_t'; + +Class: 'class'; + +Const: 'const'; + +Constexpr: 'constexpr'; + +Const_cast: 'const_cast'; + +Continue: 'continue'; + +Decltype: 'decltype'; + +Default: 'default'; + +Delete: 'delete'; + +Do: 'do'; + +Double: 'double'; + +Dynamic_cast: 'dynamic_cast'; + +Else: 'else'; + +Enum: 'enum'; + +Explicit: 'explicit'; + +Export: 'export'; + +Extern: 'extern'; + +//DO NOT RENAME - PYTHON NEEDS True and False +False_: 'false'; + +Final: 'final'; + +Float: 'float'; + +For: 'for'; + +Friend: 'friend'; + +Goto: 'goto'; + +If: 'if'; + +Inline: 'inline'; + +Int: 'int'; + +Long: 'long'; + +Mutable: 'mutable'; + +Namespace: 'namespace'; + +New: 'new'; + +Noexcept: 'noexcept'; + +Nullptr: 'nullptr'; + +Operator: 'operator'; + +Override: 'override'; + +Private: 'private'; + +Protected: 'protected'; + +Public: 'public'; + +Register: 'register'; + +Reinterpret_cast: 'reinterpret_cast'; + +Return: 'return'; + +Short: 'short'; + +Signed: 'signed'; + +Sizeof: 'sizeof'; + +Static: 'static'; + +Static_assert: 'static_assert'; + +Static_cast: 'static_cast'; + +Struct: 'struct'; + +Switch: 'switch'; + +Template: 'template'; + +This: 'this'; + +Thread_local: 'thread_local'; + +Throw: 'throw'; + +//DO NOT RENAME - PYTHON NEEDS True and False +True_: 'true'; + +Try: 'try'; + +Typedef: 'typedef'; + +Typeid_: 'typeid'; + +Typename_: 'typename'; + +Union: 'union'; + +Unsigned: 'unsigned'; + +Using: 'using'; + +Virtual: 'virtual'; + +Void: 'void'; + +Volatile: 'volatile'; + +Wchar: 'wchar_t'; + +While: 'while'; +/*Operators*/ + +LeftParen: '('; + +RightParen: ')'; + +LeftBracket: '['; + +RightBracket: ']'; + +LeftBrace: '{'; + +RightBrace: '}'; + +Plus: '+'; + +Minus: '-'; + +Star: '*'; + +Div: '/'; + +Mod: '%'; + +Caret: '^'; + +And: '&'; + +Or: '|'; + +Tilde: '~'; + +Not: '!' | 'not'; + +Assign: '='; + +Less: '<'; + +Greater: '>'; + +PlusAssign: '+='; + +MinusAssign: '-='; + +StarAssign: '*='; + +DivAssign: '/='; + +ModAssign: '%='; + +XorAssign: '^='; + +AndAssign: '&='; + +OrAssign: '|='; + +LeftShiftAssign: '<<='; + +RightShiftAssign: '>>='; + +Equal: '=='; + +NotEqual: '!='; + +LessEqual: '<='; + +GreaterEqual: '>='; + +AndAnd: '&&' | 'and'; + +OrOr: '||' | 'or'; + +PlusPlus: '++'; + +MinusMinus: '--'; + +Comma: ','; + +ArrowStar: '->*'; + +Arrow: '->'; + +Question: '?'; + +Colon: ':'; + +Doublecolon: '::'; + +Semi: ';'; + +Dot: '.'; + +DotStar: '.*'; + +Ellipsis: '...'; + +fragment Hexquad: + HEXADECIMALDIGIT HEXADECIMALDIGIT HEXADECIMALDIGIT HEXADECIMALDIGIT; + +fragment Universalcharactername: + '\\u' Hexquad + | '\\U' Hexquad Hexquad; + +Identifier: + /* + Identifiernondigit | Identifier Identifiernondigit | Identifier DIGIT + */ + Identifiernondigit (Identifiernondigit | DIGIT)*; + +fragment Identifiernondigit: NONDIGIT | Universalcharactername; + +fragment NONDIGIT: [a-zA-Z_]; + +fragment DIGIT: [0-9]; + +DecimalLiteral: NONZERODIGIT ('\''? DIGIT)*; + +OctalLiteral: '0' ('\''? OCTALDIGIT)*; + +HexadecimalLiteral: ('0x' | '0X') HEXADECIMALDIGIT ( + '\''? HEXADECIMALDIGIT + )*; + +BinaryLiteral: ('0b' | '0B') BINARYDIGIT ('\''? BINARYDIGIT)*; + +fragment NONZERODIGIT: [1-9]; + +fragment OCTALDIGIT: [0-7]; + +fragment HEXADECIMALDIGIT: [0-9a-fA-F]; + +fragment BINARYDIGIT: [01]; + +Integersuffix: + Unsignedsuffix Longsuffix? + | Unsignedsuffix Longlongsuffix? + | Longsuffix Unsignedsuffix? + | Longlongsuffix Unsignedsuffix?; + +fragment Unsignedsuffix: [uU]; + +fragment Longsuffix: [lL]; + +fragment Longlongsuffix: 'll' | 'LL'; + +fragment Cchar: + ~ ['\\\r\n] + | Escapesequence + | Universalcharactername; + +fragment Escapesequence: + Simpleescapesequence + | Octalescapesequence + | Hexadecimalescapesequence; + +fragment Simpleescapesequence: + '\\\'' + | '\\"' + | '\\?' + | '\\\\' + | '\\a' + | '\\b' + | '\\f' + | '\\n' + | '\\r' + | ('\\' ('\r' '\n'? | '\n')) + | '\\t' + | '\\v'; + +fragment Octalescapesequence: + '\\' OCTALDIGIT + | '\\' OCTALDIGIT OCTALDIGIT + | '\\' OCTALDIGIT OCTALDIGIT OCTALDIGIT; + +fragment Hexadecimalescapesequence: '\\x' HEXADECIMALDIGIT+; + +fragment Fractionalconstant: + Digitsequence? '.' Digitsequence + | Digitsequence '.'; + +fragment Exponentpart: + 'e' SIGN? Digitsequence + | 'E' SIGN? Digitsequence; + +fragment SIGN: [+-]; + +fragment Digitsequence: DIGIT ('\''? DIGIT)*; + +fragment Floatingsuffix: [flFL]; + +fragment Encodingprefix: 'u8' | 'u' | 'U' | 'L'; + +fragment Schar: + ~ ["\\\r\n] + | Escapesequence + | Universalcharactername; + +fragment Rawstring: 'R"' (( '\\' ["()] )|~[\r\n (])*? '(' ~[)]*? ')' (( '\\' ["()]) | ~[\r\n "])*? '"'; + +UserDefinedIntegerLiteral: + DecimalLiteral Udsuffix + | OctalLiteral Udsuffix + | HexadecimalLiteral Udsuffix + | BinaryLiteral Udsuffix; + +UserDefinedFloatingLiteral: + Fractionalconstant Exponentpart? Udsuffix + | Digitsequence Exponentpart Udsuffix; + +UserDefinedStringLiteral: StringLiteral Udsuffix; + +UserDefinedCharacterLiteral: CharacterLiteral Udsuffix; + +fragment Udsuffix: Identifier; + +Whitespace: [ \t]+ -> skip; + +Newline: ('\r' '\n'? | '\n') -> skip; + +BlockComment: '/*' .*? '*/' -> skip; + +LineComment: '//' ~ [\r\n]* -> skip; diff --git a/server/pkg/antlr/cpp14/CPP14Parser.g4 b/server/pkg/antlr/cpp14/CPP14Parser.g4 new file mode 100644 index 0000000000000000000000000000000000000000..19c9aa5518ab77db29e555d76f7d910f4b87fc74 --- /dev/null +++ b/server/pkg/antlr/cpp14/CPP14Parser.g4 @@ -0,0 +1,823 @@ +/******************************************************************************* + * The MIT License (MIT) + * + * Copyright (c) 2015 Camilo Sanchez (Camiloasc1) 2020 Martin Mirchev (Marti2203) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * **************************************************************************** + */ +parser grammar CPP14Parser; +options { + tokenVocab = CPP14Lexer; +} +/*Basic concepts*/ + +translationUnit: declarationseq? EOF; +/*Expressions*/ + +primaryExpression: + literal+ + | This + | LeftParen expression RightParen + | idExpression + | lambdaExpression; + +idExpression: unqualifiedId | qualifiedId; + +unqualifiedId: + Identifier + | operatorFunctionId + | conversionFunctionId + | literalOperatorId + | Tilde (className | decltypeSpecifier) + | templateId; + +qualifiedId: nestedNameSpecifier Template? unqualifiedId; + +nestedNameSpecifier: + (theTypeName | namespaceName | decltypeSpecifier)? Doublecolon + | nestedNameSpecifier ( + Identifier + | Template? simpleTemplateId + ) Doublecolon; +lambdaExpression: + lambdaIntroducer lambdaDeclarator? compoundStatement; + +lambdaIntroducer: LeftBracket lambdaCapture? RightBracket; + +lambdaCapture: + captureList + | captureDefault (Comma captureList)?; + +captureDefault: And | Assign; + +captureList: capture (Comma capture)* Ellipsis?; + +capture: simpleCapture | initcapture; + +simpleCapture: And? Identifier | This; + +initcapture: And? Identifier initializer; + +lambdaDeclarator: + LeftParen parameterDeclarationClause? RightParen Mutable? exceptionSpecification? + attributeSpecifierSeq? trailingReturnType?; + +postfixExpression: + primaryExpression + | postfixExpression LeftBracket (expression | bracedInitList) RightBracket + | postfixExpression LeftParen expressionList? RightParen + | (simpleTypeSpecifier | typeNameSpecifier) ( + LeftParen expressionList? RightParen + | bracedInitList + ) + | postfixExpression (Dot | Arrow) ( + Template? idExpression + | pseudoDestructorName + ) + | postfixExpression (PlusPlus | MinusMinus) + | ( + Dynamic_cast + | Static_cast + | Reinterpret_cast + | Const_cast + ) Less theTypeId Greater LeftParen expression RightParen + | typeIdOfTheTypeId LeftParen (expression | theTypeId) RightParen; +/* + add a middle layer to eliminate duplicated function declarations + */ + +typeIdOfTheTypeId: Typeid_; + +expressionList: initializerList; + +pseudoDestructorName: + nestedNameSpecifier? (theTypeName Doublecolon)? Tilde theTypeName + | nestedNameSpecifier Template simpleTemplateId Doublecolon Tilde theTypeName + | Tilde decltypeSpecifier; + +unaryExpression: + postfixExpression + | (PlusPlus | MinusMinus | unaryOperator | Sizeof) unaryExpression + | Sizeof ( + LeftParen theTypeId RightParen + | Ellipsis LeftParen Identifier RightParen + ) + | Alignof LeftParen theTypeId RightParen + | noExceptExpression + | newExpression + | deleteExpression; + +unaryOperator: Or | Star | And | Plus | Tilde | Minus | Not; + +newExpression: + Doublecolon? New newPlacement? ( + newTypeId + | (LeftParen theTypeId RightParen) + ) newInitializer?; + +newPlacement: LeftParen expressionList RightParen; + +newTypeId: typeSpecifierSeq newDeclarator?; + +newDeclarator: + pointerOperator newDeclarator? + | noPointerNewDeclarator; + +noPointerNewDeclarator: + LeftBracket expression RightBracket attributeSpecifierSeq? + | noPointerNewDeclarator LeftBracket constantExpression RightBracket attributeSpecifierSeq?; + +newInitializer: + LeftParen expressionList? RightParen + | bracedInitList; + +deleteExpression: + Doublecolon? Delete (LeftBracket RightBracket)? castExpression; + +noExceptExpression: Noexcept LeftParen expression RightParen; + +castExpression: + unaryExpression + | LeftParen theTypeId RightParen castExpression; + +pointerMemberExpression: + castExpression ((DotStar | ArrowStar) castExpression)*; + +multiplicativeExpression: + pointerMemberExpression ( + (Star | Div | Mod) pointerMemberExpression + )*; + +additiveExpression: + multiplicativeExpression ( + (Plus | Minus) multiplicativeExpression + )*; + +shiftExpression: + additiveExpression (shiftOperator additiveExpression)*; + +shiftOperator: Greater Greater | Less Less; + +relationalExpression: + shiftExpression ( + (Less | Greater | LessEqual | GreaterEqual) shiftExpression + )*; + +equalityExpression: + relationalExpression ( + (Equal | NotEqual) relationalExpression + )*; + +andExpression: equalityExpression (And equalityExpression)*; + +exclusiveOrExpression: andExpression (Caret andExpression)*; + +inclusiveOrExpression: + exclusiveOrExpression (Or exclusiveOrExpression)*; + +logicalAndExpression: + inclusiveOrExpression (AndAnd inclusiveOrExpression)*; + +logicalOrExpression: + logicalAndExpression (OrOr logicalAndExpression)*; + +conditionalExpression: + logicalOrExpression ( + Question expression Colon assignmentExpression + )?; + +assignmentExpression: + conditionalExpression + | logicalOrExpression assignmentOperator initializerClause + | throwExpression; + +assignmentOperator: + Assign + | StarAssign + | DivAssign + | ModAssign + | PlusAssign + | MinusAssign + | RightShiftAssign + | LeftShiftAssign + | AndAssign + | XorAssign + | OrAssign; + +expression: assignmentExpression (Comma assignmentExpression)*; + +constantExpression: conditionalExpression; +/*Statements*/ + +statement: + labeledStatement + | declarationStatement + | attributeSpecifierSeq? ( + expressionStatement + | compoundStatement + | selectionStatement + | iterationStatement + | jumpStatement + | tryBlock + ); + +labeledStatement: + attributeSpecifierSeq? ( + Identifier + | Case constantExpression + | Default + ) Colon statement; + +expressionStatement: expression? Semi; + +compoundStatement: LeftBrace statementSeq? RightBrace; + +statementSeq: statement+; + +selectionStatement: + If LeftParen condition RightParen statement (Else statement)? + | Switch LeftParen condition RightParen statement; + +condition: + expression + | attributeSpecifierSeq? declSpecifierSeq declarator ( + Assign initializerClause + | bracedInitList + ); + +iterationStatement: + While LeftParen condition RightParen statement + | Do statement While LeftParen expression RightParen Semi + | For LeftParen ( + forInitStatement condition? Semi expression? + | forRangeDeclaration Colon forRangeInitializer + ) RightParen statement; + +forInitStatement: expressionStatement | simpleDeclaration; + +forRangeDeclaration: + attributeSpecifierSeq? declSpecifierSeq declarator; + +forRangeInitializer: expression | bracedInitList; + +jumpStatement: + ( + Break + | Continue + | Return (expression | bracedInitList)? + | Goto Identifier + ) Semi; + +declarationStatement: blockDeclaration; +/*Declarations*/ + +declarationseq: declaration+; + +declaration: + blockDeclaration + | functionDefinition + | templateDeclaration + | explicitInstantiation + | explicitSpecialization + | linkageSpecification + | namespaceDefinition + | emptyDeclaration + | attributeDeclaration; + +blockDeclaration: + simpleDeclaration + | asmDefinition + | namespaceAliasDefinition + | usingDeclaration + | usingDirective + | staticAssertDeclaration + | aliasDeclaration + | opaqueEnumDeclaration; + +aliasDeclaration: + Using Identifier attributeSpecifierSeq? Assign theTypeId Semi; + +simpleDeclaration: + declSpecifierSeq? initDeclaratorList? Semi + | attributeSpecifierSeq declSpecifierSeq? initDeclaratorList Semi; + +staticAssertDeclaration: + Static_assert LeftParen constantExpression Comma StringLiteral RightParen Semi; + +emptyDeclaration: Semi; + +attributeDeclaration: attributeSpecifierSeq Semi; + +declSpecifier: + storageClassSpecifier + | typeSpecifier + | functionSpecifier + | Friend + | Typedef + | Constexpr; + +declSpecifierSeq: declSpecifier+? attributeSpecifierSeq?; + +storageClassSpecifier: + Register + | Static + | Thread_local + | Extern + | Mutable; + +functionSpecifier: Inline | Virtual | Explicit; + +typedefName: Identifier; + +typeSpecifier: + trailingTypeSpecifier + | classSpecifier + | enumSpecifier; + +trailingTypeSpecifier: + simpleTypeSpecifier + | elaboratedTypeSpecifier + | typeNameSpecifier + | cvQualifier; + +typeSpecifierSeq: typeSpecifier+ attributeSpecifierSeq?; + +trailingTypeSpecifierSeq: + trailingTypeSpecifier+ attributeSpecifierSeq?; + +simpleTypeLengthModifier: + Short + | Long; + +simpleTypeSignednessModifier: + Unsigned + | Signed; + +simpleTypeSpecifier: + nestedNameSpecifier? theTypeName + | nestedNameSpecifier Template simpleTemplateId + | simpleTypeSignednessModifier + | simpleTypeSignednessModifier? simpleTypeLengthModifier+ + | simpleTypeSignednessModifier? Char + | simpleTypeSignednessModifier? Char16 + | simpleTypeSignednessModifier? Char32 + | simpleTypeSignednessModifier? Wchar + | Bool + | simpleTypeSignednessModifier? simpleTypeLengthModifier* Int + | Float + | simpleTypeLengthModifier? Double + | Void + | Auto + | decltypeSpecifier; + +theTypeName: + className + | enumName + | typedefName + | simpleTemplateId; + +decltypeSpecifier: + Decltype LeftParen (expression | Auto) RightParen; + +elaboratedTypeSpecifier: + classKey ( + attributeSpecifierSeq? nestedNameSpecifier? Identifier + | simpleTemplateId + | nestedNameSpecifier Template? simpleTemplateId + ) + | Enum nestedNameSpecifier? Identifier; + +enumName: Identifier; + +enumSpecifier: + enumHead LeftBrace (enumeratorList Comma?)? RightBrace; + +enumHead: + enumkey attributeSpecifierSeq? ( + nestedNameSpecifier? Identifier + )? enumbase?; + +opaqueEnumDeclaration: + enumkey attributeSpecifierSeq? Identifier enumbase? Semi; + +enumkey: Enum (Class | Struct)?; + +enumbase: Colon typeSpecifierSeq; + +enumeratorList: + enumeratorDefinition (Comma enumeratorDefinition)*; + +enumeratorDefinition: enumerator (Assign constantExpression)?; + +enumerator: Identifier; + +namespaceName: originalNamespaceName | namespaceAlias; + +originalNamespaceName: Identifier; + +namespaceDefinition: + Inline? Namespace (Identifier | originalNamespaceName)? LeftBrace namespaceBody = declarationseq + ? RightBrace; + +namespaceAlias: Identifier; + +namespaceAliasDefinition: + Namespace Identifier Assign qualifiednamespacespecifier Semi; + +qualifiednamespacespecifier: nestedNameSpecifier? namespaceName; + +usingDeclaration: + Using ((Typename_? nestedNameSpecifier) | Doublecolon) unqualifiedId Semi; + +usingDirective: + attributeSpecifierSeq? Using Namespace nestedNameSpecifier? namespaceName Semi; + +asmDefinition: Asm LeftParen StringLiteral RightParen Semi; + +linkageSpecification: + Extern StringLiteral ( + LeftBrace declarationseq? RightBrace + | declaration + ); + +attributeSpecifierSeq: attributeSpecifier+; + +attributeSpecifier: + LeftBracket LeftBracket attributeList? RightBracket RightBracket + | alignmentspecifier; + +alignmentspecifier: + Alignas LeftParen (theTypeId | constantExpression) Ellipsis? RightParen; + +attributeList: attribute (Comma attribute)* Ellipsis?; + +attribute: (attributeNamespace Doublecolon)? Identifier attributeArgumentClause?; + +attributeNamespace: Identifier; + +attributeArgumentClause: LeftParen balancedTokenSeq? RightParen; + +balancedTokenSeq: balancedtoken+; + +balancedtoken: + LeftParen balancedTokenSeq RightParen + | LeftBracket balancedTokenSeq RightBracket + | LeftBrace balancedTokenSeq RightBrace + | ~( + LeftParen + | RightParen + | LeftBrace + | RightBrace + | LeftBracket + | RightBracket + )+; +/*Declarators*/ + +initDeclaratorList: initDeclarator (Comma initDeclarator)*; + +initDeclarator: declarator initializer?; + +declarator: + pointerDeclarator + | noPointerDeclarator parametersAndQualifiers trailingReturnType; + +pointerDeclarator: (pointerOperator Const?)* noPointerDeclarator; + +noPointerDeclarator: + declaratorid attributeSpecifierSeq? + | noPointerDeclarator ( + parametersAndQualifiers + | LeftBracket constantExpression? RightBracket attributeSpecifierSeq? + ) + | LeftParen pointerDeclarator RightParen; + +parametersAndQualifiers: + LeftParen parameterDeclarationClause? RightParen cvqualifierseq? refqualifier? + exceptionSpecification? attributeSpecifierSeq?; + +trailingReturnType: + Arrow trailingTypeSpecifierSeq abstractDeclarator?; + +pointerOperator: + (And | AndAnd) attributeSpecifierSeq? + | nestedNameSpecifier? Star attributeSpecifierSeq? cvqualifierseq?; + +cvqualifierseq: cvQualifier+; + +cvQualifier: Const | Volatile; + +refqualifier: And | AndAnd; + +declaratorid: Ellipsis? idExpression; + +theTypeId: typeSpecifierSeq abstractDeclarator?; + +abstractDeclarator: + pointerAbstractDeclarator + | noPointerAbstractDeclarator? parametersAndQualifiers trailingReturnType + | abstractPackDeclarator; + +pointerAbstractDeclarator: + noPointerAbstractDeclarator + | pointerOperator+ noPointerAbstractDeclarator?; + +noPointerAbstractDeclarator: + noPointerAbstractDeclarator ( + parametersAndQualifiers + | noPointerAbstractDeclarator LeftBracket constantExpression? RightBracket + attributeSpecifierSeq? + ) + | parametersAndQualifiers + | LeftBracket constantExpression? RightBracket attributeSpecifierSeq? + | LeftParen pointerAbstractDeclarator RightParen; + +abstractPackDeclarator: + pointerOperator* noPointerAbstractPackDeclarator; + +noPointerAbstractPackDeclarator: + noPointerAbstractPackDeclarator ( + parametersAndQualifiers + | LeftBracket constantExpression? RightBracket attributeSpecifierSeq? + ) + | Ellipsis; + +parameterDeclarationClause: + parameterDeclarationList (Comma? Ellipsis)?; + +parameterDeclarationList: + parameterDeclaration (Comma parameterDeclaration)*; + +parameterDeclaration: + attributeSpecifierSeq? declSpecifierSeq ( + (declarator | abstractDeclarator?) ( + Assign initializerClause + )? + ); + +functionDefinition: + attributeSpecifierSeq? declSpecifierSeq? declarator virtualSpecifierSeq? functionBody; + +functionBody: + constructorInitializer? compoundStatement + | functionTryBlock + | Assign (Default | Delete) Semi; + +initializer: + braceOrEqualInitializer + | LeftParen expressionList RightParen; + +braceOrEqualInitializer: + Assign initializerClause + | bracedInitList; + +initializerClause: assignmentExpression | bracedInitList; + +initializerList: + initializerClause Ellipsis? ( + Comma initializerClause Ellipsis? + )*; + +bracedInitList: LeftBrace (initializerList Comma?)? RightBrace; +/*Classes*/ + +className: Identifier | simpleTemplateId; + +classSpecifier: + classHead LeftBrace memberSpecification? RightBrace; + +classHead: + classKey attributeSpecifierSeq? ( + classHeadName classVirtSpecifier? + )? baseClause? + | Union attributeSpecifierSeq? ( + classHeadName classVirtSpecifier? + )?; + +classHeadName: nestedNameSpecifier? className; + +classVirtSpecifier: Final; + +classKey: Class | Struct; + +memberSpecification: + (memberdeclaration | accessSpecifier Colon)+; + +memberdeclaration: + attributeSpecifierSeq? declSpecifierSeq? memberDeclaratorList? Semi + | functionDefinition + | usingDeclaration + | staticAssertDeclaration + | templateDeclaration + | aliasDeclaration + | emptyDeclaration; + +memberDeclaratorList: + memberDeclarator (Comma memberDeclarator)*; + +memberDeclarator: + declarator ( + virtualSpecifierSeq? pureSpecifier? + | braceOrEqualInitializer? + ) + | Identifier? attributeSpecifierSeq? Colon constantExpression; + +virtualSpecifierSeq: virtualSpecifier+; + +virtualSpecifier: Override | Final; +/* + purespecifier: Assign '0'//Conflicts with the lexer ; + */ + +pureSpecifier: + Assign val = OctalLiteral {if($val.text.compare("0")!=0) throw new InputMismatchException(this); + }; +/*Derived classes*/ + +baseClause: Colon baseSpecifierList; + +baseSpecifierList: + baseSpecifier Ellipsis? (Comma baseSpecifier Ellipsis?)*; + +baseSpecifier: + attributeSpecifierSeq? ( + baseTypeSpecifier + | Virtual accessSpecifier? baseTypeSpecifier + | accessSpecifier Virtual? baseTypeSpecifier + ); + +classOrDeclType: + nestedNameSpecifier? className + | decltypeSpecifier; + +baseTypeSpecifier: classOrDeclType; + +accessSpecifier: Private | Protected | Public; +/*Special member functions*/ + +conversionFunctionId: Operator conversionTypeId; + +conversionTypeId: typeSpecifierSeq conversionDeclarator?; + +conversionDeclarator: pointerOperator conversionDeclarator?; + +constructorInitializer: Colon memInitializerList; + +memInitializerList: + memInitializer Ellipsis? (Comma memInitializer Ellipsis?)*; + +memInitializer: + meminitializerid ( + LeftParen expressionList? RightParen + | bracedInitList + ); + +meminitializerid: classOrDeclType | Identifier; +/*Overloading*/ + +operatorFunctionId: Operator theOperator; + +literalOperatorId: + Operator ( + StringLiteral Identifier + | UserDefinedStringLiteral + ); +/*Templates*/ + +templateDeclaration: + Template Less templateparameterList Greater declaration; + +templateparameterList: + templateParameter (Comma templateParameter)*; + +templateParameter: typeParameter | parameterDeclaration; + +typeParameter: + ( + (Template Less templateparameterList Greater)? Class + | Typename_ + ) ((Ellipsis? Identifier?) | (Identifier? Assign theTypeId)); + +simpleTemplateId: + templateName Less templateArgumentList? Greater; + +templateId: + simpleTemplateId + | (operatorFunctionId | literalOperatorId) Less templateArgumentList? Greater; + +templateName: Identifier; + +templateArgumentList: + templateArgument Ellipsis? (Comma templateArgument Ellipsis?)*; + +templateArgument: theTypeId | constantExpression | idExpression; + +typeNameSpecifier: + Typename_ nestedNameSpecifier ( + Identifier + | Template? simpleTemplateId + ); + +explicitInstantiation: Extern? Template declaration; + +explicitSpecialization: Template Less Greater declaration; +/*Exception handling*/ + +tryBlock: Try compoundStatement handlerSeq; + +functionTryBlock: + Try constructorInitializer? compoundStatement handlerSeq; + +handlerSeq: handler+; + +handler: + Catch LeftParen exceptionDeclaration RightParen compoundStatement; + +exceptionDeclaration: + attributeSpecifierSeq? typeSpecifierSeq ( + declarator + | abstractDeclarator + )? + | Ellipsis; + +throwExpression: Throw assignmentExpression?; + +exceptionSpecification: + dynamicExceptionSpecification + | noeExceptSpecification; + +dynamicExceptionSpecification: + Throw LeftParen typeIdList? RightParen; + +typeIdList: theTypeId Ellipsis? (Comma theTypeId Ellipsis?)*; + +noeExceptSpecification: + Noexcept LeftParen constantExpression RightParen + | Noexcept; +/*Preprocessing directives*/ + +/*Lexer*/ + +theOperator: + New (LeftBracket RightBracket)? + | Delete (LeftBracket RightBracket)? + | Plus + | Minus + | Star + | Div + | Mod + | Caret + | And + | Or + | Tilde + | Not + | Assign + | Greater + | Less + | GreaterEqual + | PlusAssign + | MinusAssign + | StarAssign + | ModAssign + | XorAssign + | AndAssign + | OrAssign + | Less Less + | Greater Greater + | RightShiftAssign + | LeftShiftAssign + | Equal + | NotEqual + | LessEqual + | AndAnd + | OrOr + | PlusPlus + | MinusMinus + | Comma + | ArrowStar + | Arrow + | LeftParen RightParen + | LeftBracket RightBracket; + +literal: + IntegerLiteral + | CharacterLiteral + | FloatingLiteral + | StringLiteral + | BooleanLiteral + | PointerLiteral + | UserDefinedLiteral; + diff --git a/server/pkg/antlr/cpp14/include/MyCppAntlr.h b/server/pkg/antlr/cpp14/include/MyCppAntlr.h new file mode 100644 index 0000000000000000000000000000000000000000..1794eb0a04b88a7f7564281a5bc54896cfff7d58 --- /dev/null +++ b/server/pkg/antlr/cpp14/include/MyCppAntlr.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +#include "CPP14Lexer.h" +#include "CPP14Parser.h" +#include "IAntlrWrapper.h" + +class MyCppAntlr:public IAntlrWrapper { + private: + std::unique_ptr lexer_ptr; + std::unique_ptr parser_ptr; + std::unique_ptr input_ptr; + std::unique_ptr tokenStream_ptr; + + public: + MyCppAntlr(std::istream &in); + ~MyCppAntlr() override = default; + std::vector getTokens() override; + std::vector getTokensTypes() override; + std::vector getTokensNames() override; + std::vector> getTokensNamesWithPosition() override; + std::vector > > getTokensNamesWithFullPosition() override; + std::pair getTokensAndTree() override; + std::string getTokensString() override; + std::string getTreeString() override; +}; diff --git a/server/pkg/antlr/cpp14/src/MyCppAntlr.cpp b/server/pkg/antlr/cpp14/src/MyCppAntlr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1dd13e6f0e04f6dac6e7025b021df40c4d17ac8d --- /dev/null +++ b/server/pkg/antlr/cpp14/src/MyCppAntlr.cpp @@ -0,0 +1,102 @@ +#include "MyCppAntlr.h" + +#include + +MyCppAntlr::MyCppAntlr(std::istream& in) { + input_ptr = std::make_unique(in); + lexer_ptr = std::make_unique(&(*input_ptr)); + tokenStream_ptr = std::make_unique(&(*lexer_ptr)); + parser_ptr = std::make_unique(&(*tokenStream_ptr)); +} + +std::vector MyCppAntlr::getTokens() { + tokenStream_ptr->fill(); + std::vector ans(tokenStream_ptr->size()); + + int i = 0; + for (antlr4::Token* token : tokenStream_ptr->getTokens()) { + ans[i] = token; + i++; + } + + return ans; +} + +std::vector> MyCppAntlr::getTokensNamesWithPosition(){ + tokenStream_ptr->fill(); + std::vector> ans(tokenStream_ptr->size()); + + int i = 0; + for (antlr4::Token *token : tokenStream_ptr->getTokens()) { + auto type = token->getText(); + int line = token->getLine(); + ans[i]=std::make_pair(type,line); + i++; + } + + return ans; +} + +std::vector > > MyCppAntlr::getTokensNamesWithFullPosition(){ + tokenStream_ptr->fill(); + std::vector > > ans(tokenStream_ptr->size()); + + size_t i = 0; + for (antlr4::Token *token : tokenStream_ptr->getTokens()) { + auto type = token->getText(); + int line = static_cast (token->getLine()); + int pos = static_cast (token->getCharPositionInLine()); + ans[i] = std::make_pair(type, std::make_pair(line, pos)); + i++; + } + + return ans; +} + +std::vector MyCppAntlr::getTokensTypes() { + tokenStream_ptr->fill(); + std::vector ans(tokenStream_ptr->size()); + + int i = 0; + for (antlr4::Token *token : tokenStream_ptr->getTokens()) { + ans[i] = token->getType(); + i++; + } + + return ans; +} + +std::vector MyCppAntlr::getTokensNames() { + tokenStream_ptr->fill(); + std::vector ans(tokenStream_ptr->size()); + + int i = 0; + for (antlr4::Token *token : tokenStream_ptr->getTokens()) { + ans[i] = token->getText(); + i++; + } + + return ans; +} + +std::string MyCppAntlr::getTokensString() { + tokenStream_ptr->fill(); + std::string res; + + for (antlr4::Token* token : tokenStream_ptr->getTokens()) { + res += token->toString() + " "; + } + + return res; +} + +std::string MyCppAntlr::getTreeString() { + auto tree = parser_ptr->translationUnit(); + return tree->toStringTree(&(*parser_ptr)); +} + +std::pair MyCppAntlr::getTokensAndTree() { + std::string tokens = getTokensString(); + std::string astTree = getTreeString(); + return std::make_pair(tokens, astTree); +} \ No newline at end of file diff --git a/server/pkg/antlr/python3/CMakeLists.txt b/server/pkg/antlr/python3/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e60ee233e7e1ee5c03da8d013259029e9ce25528 --- /dev/null +++ b/server/pkg/antlr/python3/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.7) +project(python_antlr_lib) + +file(GLOB SOURCES ./src/*.cpp) +file(GLOB INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/../virtual) + + +antlr_target(Python3Grammar Python3.g4 + PACKAGE antlrcpptest) + +include_directories(${ANTLR_Python3Grammar_OUTPUT_DIR}) + + +message("ANTLR_Python3Grammar_OUTPUT_DIR=${ANTLR_Python3Grammar_OUTPUT_DIR}") + +include_directories(${INCLUDE_DIRS}) +add_library(${PROJECT_NAME} ${SOURCES} ${ANTLR_Python3Grammar_CXX_OUTPUTS}) + + +target_link_libraries(${PROJECT_NAME} antlr4_static Threads::Threads) + +set(PYTHON3_ANTLR_LIBRARY ${PROJECT_NAME}) +set(PYTHON3_ANTLR_LIBRARY ${PYTHON3_ANTLR_LIBRARY} PARENT_SCOPE) + +set(PYTHON3_ANTLR_INCLUDE_DIRS ${INCLUDE_DIRS} ${ANTLR_Python3Grammar_OUTPUT_DIR}) +set(PYTHON3_ANTLR_INCLUDE_DIRS ${PYTHON3_ANTLR_INCLUDE_DIRS} PARENT_SCOPE) + +message("PYTHON3_ANTLR = ${PYTHON3_ANTLR_INCLUDE_DIRS} ") \ No newline at end of file diff --git a/server/pkg/antlr/python3/Python3.g4 b/server/pkg/antlr/python3/Python3.g4 new file mode 100644 index 0000000000000000000000000000000000000000..3f801e18042385ecd324faa3c156db9757796e73 --- /dev/null +++ b/server/pkg/antlr/python3/Python3.g4 @@ -0,0 +1,1182 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014 by Bart Kiers + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Project : python3-parser; an ANTLR4 grammar for Python 3 + * https://github.com/bkiers/python3-parser + * Developed by : Bart Kiers, bart@big-o.nl + */ +grammar Python3; + +// All comments that start with "///" are copy-pasted from +// The Python Language Reference + +tokens { INDENT, DEDENT } + +@lexer::header { + #include "Python3Parser.h" +} + + +@lexer::members { + private: + // A queue where extra tokens are pushed on (see the NEWLINE lexer rule). + std::vector> m_tokens; + // The stack that keeps track of the indentation level. + std::stack m_indents; + // The amount of opened braces, brackets and parenthesis. + int m_opened = 0; + // The most recently produced token. + std::unique_ptr m_pLastToken = nullptr; + + public: + virtual void emit(std::unique_ptr newToken) override { + m_tokens.push_back(cloneToken(newToken)); + setToken(std::move(newToken)); + } + + std::unique_ptr nextToken() override { + // Check if the end-of-file is ahead and there are still some DEDENTS expected. + if (_input->LA(1) == EOF && !m_indents.empty()) { + // Remove any trailing EOF tokens from our buffer. + for (int i = m_tokens.size() - 1; i >= 0; i--) { + if (m_tokens[i]->getType() == EOF) { + m_tokens.erase(m_tokens.begin() + i); + } + } + + // First emit an extra line break that serves as the end of the statement. + emit(commonToken(Python3Parser::NEWLINE, "\n")); + + // Now emit as much DEDENT tokens as needed. + while (!m_indents.empty()) { + emit(createDedent()); + m_indents.pop(); + } + + // Put the EOF back on the token stream. + emit(commonToken(EOF, "")); + } + + std::unique_ptr next = Lexer::nextToken(); + + if (next->getChannel() == antlr4::Token::DEFAULT_CHANNEL) { + // Keep track of the last token on the default channel. + m_pLastToken = cloneToken(next); + } + + if (!m_tokens.empty()) + { + next = std::move(*m_tokens.begin()); + m_tokens.erase(m_tokens.begin()); + } + + return next; + } + + private: + std::unique_ptr createDedent() { + std::unique_ptr dedent = commonToken(Python3Parser::DEDENT, ""); + return dedent; + } + + std::unique_ptr commonToken(size_t type, const std::string& text) { + int stop = getCharIndex() - 1; + int start = text.empty() ? stop : stop - text.size() + 1; + return _factory->create({ this, _input }, type, text, DEFAULT_TOKEN_CHANNEL, start, stop, m_pLastToken ? m_pLastToken->getLine() : 0, m_pLastToken ? m_pLastToken->getCharPositionInLine() : 0); + } + + std::unique_ptr cloneToken(const std::unique_ptr& source) { + return _factory->create({ this, _input }, source->getType(), source->getText(), source->getChannel(), source->getStartIndex(), source->getStopIndex(), source->getLine(), source->getCharPositionInLine()); + } + + + // Calculates the indentation of the provided spaces, taking the + // following rules into account: + // + // "Tabs are replaced (from left to right) by one to eight spaces + // such that the total number of characters up to and including + // the replacement is a multiple of eight [...]" + // + // -- https://docs.python.org/3.1/reference/lexical_analysis.html#indentation + static int getIndentationCount(const std::string& spaces) { + int count = 0; + for (char ch : spaces) { + switch (ch) { + case '\t': + count += 8 - (count % 8); + break; + default: + // A normal space char. + count++; + } + } + + return count; + } + + bool atStartOfInput() { + return getCharPositionInLine() == 0 && getLine() == 1; + } +} + +/* + * parser rules + */ + +single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE; +file_input: (NEWLINE | stmt)* EOF; +eval_input: testlist NEWLINE* EOF; + +decorator: '@' dotted_name ( '(' (arglist)? ')' )? NEWLINE; +decorators: decorator+; +decorated: decorators (classdef | funcdef | async_funcdef); + +async_funcdef: ASYNC funcdef; +funcdef: 'def' NAME parameters ('->' test)? ':' suite; + +parameters: '(' (typedargslist)? ')'; +typedargslist: (tfpdef ('=' test)? (',' tfpdef ('=' test)?)* (',' ( + '*' (tfpdef)? (',' tfpdef ('=' test)?)* (',' ('**' tfpdef (',')?)?)? + | '**' tfpdef (',')?)?)? + | '*' (tfpdef)? (',' tfpdef ('=' test)?)* (',' ('**' tfpdef (',')?)?)? + | '**' tfpdef (',')?); +tfpdef: NAME (':' test)?; +varargslist: (vfpdef ('=' test)? (',' vfpdef ('=' test)?)* (',' ( + '*' (vfpdef)? (',' vfpdef ('=' test)?)* (',' ('**' vfpdef (',')?)?)? + | '**' vfpdef (',')?)?)? + | '*' (vfpdef)? (',' vfpdef ('=' test)?)* (',' ('**' vfpdef (',')?)?)? + | '**' vfpdef (',')? +); +vfpdef: NAME; + +stmt: simple_stmt | compound_stmt; +simple_stmt: small_stmt (';' small_stmt)* (';')? NEWLINE; +small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | + import_stmt | global_stmt | nonlocal_stmt | assert_stmt); +expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | + ('=' (yield_expr|testlist_star_expr))*); +annassign: ':' test ('=' test)?; +testlist_star_expr: (test|star_expr) (',' (test|star_expr))* (',')?; +augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | + '<<=' | '>>=' | '**=' | '//='); +// For normal and annotated assignments, additional restrictions enforced by the interpreter +del_stmt: 'del' exprlist; +pass_stmt: 'pass'; +flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt; +break_stmt: 'break'; +continue_stmt: 'continue'; +return_stmt: 'return' (testlist)?; +yield_stmt: yield_expr; +raise_stmt: 'raise' (test ('from' test)?)?; +import_stmt: import_name | import_from; +import_name: 'import' dotted_as_names; +// note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS +import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+) + 'import' ('*' | '(' import_as_names ')' | import_as_names)); +import_as_name: NAME ('as' NAME)?; +dotted_as_name: dotted_name ('as' NAME)?; +import_as_names: import_as_name (',' import_as_name)* (',')?; +dotted_as_names: dotted_as_name (',' dotted_as_name)*; +dotted_name: NAME ('.' NAME)*; +global_stmt: 'global' NAME (',' NAME)*; +nonlocal_stmt: 'nonlocal' NAME (',' NAME)*; +assert_stmt: 'assert' test (',' test)?; + +compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt; +async_stmt: ASYNC (funcdef | with_stmt | for_stmt); +if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ('else' ':' suite)?; +while_stmt: 'while' test ':' suite ('else' ':' suite)?; +for_stmt: 'for' exprlist 'in' testlist ':' suite ('else' ':' suite)?; +try_stmt: ('try' ':' suite + ((except_clause ':' suite)+ + ('else' ':' suite)? + ('finally' ':' suite)? | + 'finally' ':' suite)); +with_stmt: 'with' with_item (',' with_item)* ':' suite; +with_item: test ('as' expr)?; +// NB compile.c makes sure that the default except clause is last +except_clause: 'except' (test ('as' NAME)?)?; +suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT; + +test: or_test ('if' or_test 'else' test)? | lambdef; +test_nocond: or_test | lambdef_nocond; +lambdef: 'lambda' (varargslist)? ':' test; +lambdef_nocond: 'lambda' (varargslist)? ':' test_nocond; +or_test: and_test ('or' and_test)*; +and_test: not_test ('and' not_test)*; +not_test: 'not' not_test | comparison; +comparison: expr (comp_op expr)*; +// <> isn't actually a valid comparison operator in Python. It's here for the +// sake of a __future__ import described in PEP 401 (which really works :-) +comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'; +star_expr: '*' expr; +expr: xor_expr ('|' xor_expr)*; +xor_expr: and_expr ('^' and_expr)*; +and_expr: shift_expr ('&' shift_expr)*; +shift_expr: arith_expr (('<<'|'>>') arith_expr)*; +arith_expr: term (('+'|'-') term)*; +term: factor (('*'|'@'|'/'|'%'|'//') factor)*; +factor: ('+'|'-'|'~') factor | power; +power: atom_expr ('**' factor)?; +atom_expr: (AWAIT)? atom trailer*; +atom: ('(' (yield_expr|testlist_comp)? ')' | + '[' (testlist_comp)? ']' | + '{' (dictorsetmaker)? '}' | + NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False'); +testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* (',')? ); +trailer: '(' (arglist)? ')' | '[' subscriptlist ']' | '.' NAME; +subscriptlist: subscript (',' subscript)* (',')?; +subscript: test | (test)? ':' (test)? (sliceop)?; +sliceop: ':' (test)?; +exprlist: (expr|star_expr) (',' (expr|star_expr))* (',')?; +testlist: test (',' test)* (',')?; +dictorsetmaker: ( ((test ':' test | '**' expr) + (comp_for | (',' (test ':' test | '**' expr))* (',')?)) | + ((test | star_expr) + (comp_for | (',' (test | star_expr))* (',')?)) ); + +classdef: 'class' NAME ('(' (arglist)? ')')? ':' suite; + +arglist: argument (',' argument)* (',')?; + +// The reason that keywords are test nodes instead of NAME is that using NAME +// results in an ambiguity. ast.c makes sure it's a NAME. +// "test '=' test" is really "keyword '=' test", but we have no such token. +// These need to be in a single rule to avoid grammar that is ambiguous +// to our LL(1) parser. Even though 'test' includes '*expr' in star_expr, +// we explicitly match '*' here, too, to give it proper precedence. +// Illegal combinations and orderings are blocked in ast.c: +// multiple (test comp_for) arguments are blocked; keyword unpackings +// that precede iterable unpackings are blocked; etc. +argument: ( test (comp_for)? | + test '=' test | + '**' test | + '*' test ); + +comp_iter: comp_for | comp_if; +comp_for: (ASYNC)? 'for' exprlist 'in' or_test (comp_iter)?; +comp_if: 'if' test_nocond (comp_iter)?; + +// not used in grammar, but may appear in "node" passed from Parser to Compiler +encoding_decl: NAME; + +yield_expr: 'yield' (yield_arg)?; +yield_arg: 'from' test | testlist; + +/* + * lexer rules + */ + +STRING + : STRING_LITERAL + | BYTES_LITERAL + ; + +NUMBER + : INTEGER + | FLOAT_NUMBER + | IMAG_NUMBER + ; + +INTEGER + : DECIMAL_INTEGER + | OCT_INTEGER + | HEX_INTEGER + | BIN_INTEGER + ; + +DEF : 'def'; +RETURN : 'return'; +RAISE : 'raise'; +FROM : 'from'; +IMPORT : 'import'; +AS : 'as'; +GLOBAL : 'global'; +NONLOCAL : 'nonlocal'; +ASSERT : 'assert'; +IF : 'if'; +ELIF : 'elif'; +ELSE : 'else'; +WHILE : 'while'; +FOR : 'for'; +IN : 'in'; +TRY : 'try'; +FINALLY : 'finally'; +WITH : 'with'; +EXCEPT : 'except'; +LAMBDA : 'lambda'; +OR : 'or'; +AND : 'and'; +NOT : 'not'; +IS : 'is'; +NONE : 'None'; +TRUE : 'True'; +FALSE : 'False'; +CLASS : 'class'; +YIELD : 'yield'; +DEL : 'del'; +PASS : 'pass'; +CONTINUE : 'continue'; +BREAK : 'break'; +ASYNC : 'async'; +AWAIT : 'await'; + +NEWLINE + : ( {atStartOfInput()}? SPACES + | ( '\r'? '\n' | '\r' | '\f' ) SPACES? + ) + { + { + std::string newLine, spaces; + std::string text = getText(); + for(char c : text) + { + if ((c == '\r') || (c == '\n') || (c == '\f')) + newLine.push_back(c); + else + spaces.push_back(c); + } + + + // Strip newlines inside open clauses except if we are near EOF. We keep NEWLINEs near EOF to + // satisfy the final newline needed by the single_put rule used by the REPL. + int next = _input->LA(1); + int nextnext = _input->LA(2); + if (m_opened > 0 || (nextnext != -1 && (next == '\r' || next == '\n' || next == '\f' || next == '#'))) { + // If we're inside a list or on a blank line, ignore all indents, + // dedents and line breaks. + skip(); + } + else { + emit(commonToken(NEWLINE, newLine)); + int indent = getIndentationCount(spaces); + int previous = m_indents.empty() ? 0 : m_indents.top(); + if (indent == previous) { + // skip indents of the same size as the present indent-size + skip(); + } + else if (indent > previous) { + m_indents.push(indent); + emit(commonToken(Python3Parser::INDENT, spaces)); + } + else { + // Possibly emit more than 1 DEDENT token. + while(!m_indents.empty() && m_indents.top() > indent) { + emit(createDedent()); + m_indents.pop(); + } + } + } + } + } + ; + +/// identifier ::= id_start id_continue* +NAME + : ID_START ID_CONTINUE* + ; + +/// stringliteral ::= [stringprefix](shortstring | longstring) +/// stringprefix ::= "r" | "u" | "R" | "U" | "f" | "F" +/// | "fr" | "Fr" | "fR" | "FR" | "rf" | "rF" | "Rf" | "RF" +STRING_LITERAL + : ( [rR] | [uU] | [fF] | ( [fF] [rR] ) | ( [rR] [fF] ) )? ( SHORT_STRING | LONG_STRING ) + ; + +/// bytesliteral ::= bytesprefix(shortbytes | longbytes) +/// bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR" | "rb" | "rB" | "Rb" | "RB" +BYTES_LITERAL + : ( [bB] | ( [bB] [rR] ) | ( [rR] [bB] ) ) ( SHORT_BYTES | LONG_BYTES ) + ; + +/// decimalinteger ::= nonzerodigit digit* | "0"+ +DECIMAL_INTEGER + : NON_ZERO_DIGIT DIGIT* + | '0'+ + ; + +/// octinteger ::= "0" ("o" | "O") octdigit+ +OCT_INTEGER + : '0' [oO] OCT_DIGIT+ + ; + +/// hexinteger ::= "0" ("x" | "X") hexdigit+ +HEX_INTEGER + : '0' [xX] HEX_DIGIT+ + ; + +/// bininteger ::= "0" ("b" | "B") bindigit+ +BIN_INTEGER + : '0' [bB] BIN_DIGIT+ + ; + +/// floatnumber ::= pointfloat | exponentfloat +FLOAT_NUMBER + : POINT_FLOAT + | EXPONENT_FLOAT + ; + +/// imagnumber ::= (floatnumber | intpart) ("j" | "J") +IMAG_NUMBER + : ( FLOAT_NUMBER | INT_PART ) [jJ] + ; + +DOT : '.'; +ELLIPSIS : '...'; +STAR : '*'; +OPEN_PAREN : '(' {m_opened++;}; +CLOSE_PAREN : ')' {m_opened--;}; +COMMA : ','; +COLON : ':'; +SEMI_COLON : ';'; +POWER : '**'; +ASSIGN : '='; +OPEN_BRACK : '[' {m_opened++;}; +CLOSE_BRACK : ']' {m_opened--;}; +OR_OP : '|'; +XOR : '^'; +AND_OP : '&'; +LEFT_SHIFT : '<<'; +RIGHT_SHIFT : '>>'; +ADD : '+'; +MINUS : '-'; +DIV : '/'; +MOD : '%'; +IDIV : '//'; +NOT_OP : '~'; +OPEN_BRACE : '{' {m_opened++;}; +CLOSE_BRACE : '}' {m_opened--;}; +LESS_THAN : '<'; +GREATER_THAN : '>'; +EQUALS : '=='; +GT_EQ : '>='; +LT_EQ : '<='; +NOT_EQ_1 : '<>'; +NOT_EQ_2 : '!='; +AT : '@'; +ARROW : '->'; +ADD_ASSIGN : '+='; +SUB_ASSIGN : '-='; +MULT_ASSIGN : '*='; +AT_ASSIGN : '@='; +DIV_ASSIGN : '/='; +MOD_ASSIGN : '%='; +AND_ASSIGN : '&='; +OR_ASSIGN : '|='; +XOR_ASSIGN : '^='; +LEFT_SHIFT_ASSIGN : '<<='; +RIGHT_SHIFT_ASSIGN : '>>='; +POWER_ASSIGN : '**='; +IDIV_ASSIGN : '//='; + +SKIP_ + : ( SPACES | COMMENT | LINE_JOINING ) -> skip + ; + +UNKNOWN_CHAR + : . + ; + +/* + * fragments + */ + +/// shortstring ::= "'" shortstringitem* "'" | '"' shortstringitem* '"' +/// shortstringitem ::= shortstringchar | stringescapeseq +/// shortstringchar ::= +fragment SHORT_STRING + : '\'' ( STRING_ESCAPE_SEQ | ~[\\\r\n\f'] )* '\'' + | '"' ( STRING_ESCAPE_SEQ | ~[\\\r\n\f"] )* '"' + ; +/// longstring ::= "'''" longstringitem* "'''" | '"""' longstringitem* '"""' +fragment LONG_STRING + : '\'\'\'' LONG_STRING_ITEM*? '\'\'\'' + | '"""' LONG_STRING_ITEM*? '"""' + ; + +/// longstringitem ::= longstringchar | stringescapeseq +fragment LONG_STRING_ITEM + : LONG_STRING_CHAR + | STRING_ESCAPE_SEQ + ; + +/// longstringchar ::= +fragment LONG_STRING_CHAR + : ~'\\' + ; + +/// stringescapeseq ::= "\" +fragment STRING_ESCAPE_SEQ + : '\\' . + | '\\' NEWLINE + ; + +/// nonzerodigit ::= "1"..."9" +fragment NON_ZERO_DIGIT + : [1-9] + ; + +/// digit ::= "0"..."9" +fragment DIGIT + : [0-9] + ; + +/// octdigit ::= "0"..."7" +fragment OCT_DIGIT + : [0-7] + ; + +/// hexdigit ::= digit | "a"..."f" | "A"..."F" +fragment HEX_DIGIT + : [0-9a-fA-F] + ; + +/// bindigit ::= "0" | "1" +fragment BIN_DIGIT + : [01] + ; + +/// pointfloat ::= [intpart] fraction | intpart "." +fragment POINT_FLOAT + : INT_PART? FRACTION + | INT_PART '.' + ; + +/// exponentfloat ::= (intpart | pointfloat) exponent +fragment EXPONENT_FLOAT + : ( INT_PART | POINT_FLOAT ) EXPONENT + ; + +/// intpart ::= digit+ +fragment INT_PART + : DIGIT+ + ; + +/// fraction ::= "." digit+ +fragment FRACTION + : '.' DIGIT+ + ; + +/// exponent ::= ("e" | "E") ["+" | "-"] digit+ +fragment EXPONENT + : [eE] [+-]? DIGIT+ + ; + +/// shortbytes ::= "'" shortbytesitem* "'" | '"' shortbytesitem* '"' +/// shortbytesitem ::= shortbyteschar | bytesescapeseq +fragment SHORT_BYTES + : '\'' ( SHORT_BYTES_CHAR_NO_SINGLE_QUOTE | BYTES_ESCAPE_SEQ )* '\'' + | '"' ( SHORT_BYTES_CHAR_NO_DOUBLE_QUOTE | BYTES_ESCAPE_SEQ )* '"' + ; + +/// longbytes ::= "'''" longbytesitem* "'''" | '"""' longbytesitem* '"""' +fragment LONG_BYTES + : '\'\'\'' LONG_BYTES_ITEM*? '\'\'\'' + | '"""' LONG_BYTES_ITEM*? '"""' + ; + +/// longbytesitem ::= longbyteschar | bytesescapeseq +fragment LONG_BYTES_ITEM + : LONG_BYTES_CHAR + | BYTES_ESCAPE_SEQ + ; + +/// shortbyteschar ::= +fragment SHORT_BYTES_CHAR_NO_SINGLE_QUOTE + : [\u0000-\u0009] + | [\u000B-\u000C] + | [\u000E-\u0026] + | [\u0028-\u005B] + | [\u005D-\u007F] + ; + +fragment SHORT_BYTES_CHAR_NO_DOUBLE_QUOTE + : [\u0000-\u0009] + | [\u000B-\u000C] + | [\u000E-\u0021] + | [\u0023-\u005B] + | [\u005D-\u007F] + ; + +/// longbyteschar ::= +fragment LONG_BYTES_CHAR + : [\u0000-\u005B] + | [\u005D-\u007F] + ; + +/// bytesescapeseq ::= "\" +fragment BYTES_ESCAPE_SEQ + : '\\' [\u0000-\u007F] + ; + +fragment SPACES + : [ \t]+ + ; + +fragment COMMENT + : '#' ~[\r\n\f]* + ; + +fragment LINE_JOINING + : '\\' SPACES? ( '\r'? '\n' | '\r' | '\f') + ; + +/// id_start ::= +fragment ID_START + : '_' + | [A-Z] + | [a-z] + | '\u00AA' + | '\u00B5' + | '\u00BA' + | [\u00C0-\u00D6] + | [\u00D8-\u00F6] + | [\u00F8-\u01BA] + | '\u01BB' + | [\u01BC-\u01BF] + | [\u01C0-\u01C3] + | [\u01C4-\u0241] + | [\u0250-\u02AF] + | [\u02B0-\u02C1] + | [\u02C6-\u02D1] + | [\u02E0-\u02E4] + | '\u02EE' + | '\u037A' + | '\u0386' + | [\u0388-\u038A] + | '\u038C' + | [\u038E-\u03A1] + | [\u03A3-\u03CE] + | [\u03D0-\u03F5] + | [\u03F7-\u0481] + | [\u048A-\u04CE] + | [\u04D0-\u04F9] + | [\u0500-\u050F] + | [\u0531-\u0556] + | '\u0559' + | [\u0561-\u0587] + | [\u05D0-\u05EA] + | [\u05F0-\u05F2] + | [\u0621-\u063A] + | '\u0640' + | [\u0641-\u064A] + | [\u066E-\u066F] + | [\u0671-\u06D3] + | '\u06D5' + | [\u06E5-\u06E6] + | [\u06EE-\u06EF] + | [\u06FA-\u06FC] + | '\u06FF' + | '\u0710' + | [\u0712-\u072F] + | [\u074D-\u076D] + | [\u0780-\u07A5] + | '\u07B1' + | [\u0904-\u0939] + | '\u093D' + | '\u0950' + | [\u0958-\u0961] + | '\u097D' + | [\u0985-\u098C] + | [\u098F-\u0990] + | [\u0993-\u09A8] + | [\u09AA-\u09B0] + | '\u09B2' + | [\u09B6-\u09B9] + | '\u09BD' + | '\u09CE' + | [\u09DC-\u09DD] + | [\u09DF-\u09E1] + | [\u09F0-\u09F1] + | [\u0A05-\u0A0A] + | [\u0A0F-\u0A10] + | [\u0A13-\u0A28] + | [\u0A2A-\u0A30] + | [\u0A32-\u0A33] + | [\u0A35-\u0A36] + | [\u0A38-\u0A39] + | [\u0A59-\u0A5C] + | '\u0A5E' + | [\u0A72-\u0A74] + | [\u0A85-\u0A8D] + | [\u0A8F-\u0A91] + | [\u0A93-\u0AA8] + | [\u0AAA-\u0AB0] + | [\u0AB2-\u0AB3] + | [\u0AB5-\u0AB9] + | '\u0ABD' + | '\u0AD0' + | [\u0AE0-\u0AE1] + | [\u0B05-\u0B0C] + | [\u0B0F-\u0B10] + | [\u0B13-\u0B28] + | [\u0B2A-\u0B30] + | [\u0B32-\u0B33] + | [\u0B35-\u0B39] + | '\u0B3D' + | [\u0B5C-\u0B5D] + | [\u0B5F-\u0B61] + | '\u0B71' + | '\u0B83' + | [\u0B85-\u0B8A] + | [\u0B8E-\u0B90] + | [\u0B92-\u0B95] + | [\u0B99-\u0B9A] + | '\u0B9C' + | [\u0B9E-\u0B9F] + | [\u0BA3-\u0BA4] + | [\u0BA8-\u0BAA] + | [\u0BAE-\u0BB9] + | [\u0C05-\u0C0C] + | [\u0C0E-\u0C10] + | [\u0C12-\u0C28] + | [\u0C2A-\u0C33] + | [\u0C35-\u0C39] + | [\u0C60-\u0C61] + | [\u0C85-\u0C8C] + | [\u0C8E-\u0C90] + | [\u0C92-\u0CA8] + | [\u0CAA-\u0CB3] + | [\u0CB5-\u0CB9] + | '\u0CBD' + | '\u0CDE' + | [\u0CE0-\u0CE1] + | [\u0D05-\u0D0C] + | [\u0D0E-\u0D10] + | [\u0D12-\u0D28] + | [\u0D2A-\u0D39] + | [\u0D60-\u0D61] + | [\u0D85-\u0D96] + | [\u0D9A-\u0DB1] + | [\u0DB3-\u0DBB] + | '\u0DBD' + | [\u0DC0-\u0DC6] + | [\u0E01-\u0E30] + | [\u0E32-\u0E33] + | [\u0E40-\u0E45] + | '\u0E46' + | [\u0E81-\u0E82] + | '\u0E84' + | [\u0E87-\u0E88] + | '\u0E8A' + | '\u0E8D' + | [\u0E94-\u0E97] + | [\u0E99-\u0E9F] + | [\u0EA1-\u0EA3] + | '\u0EA5' + | '\u0EA7' + | [\u0EAA-\u0EAB] + | [\u0EAD-\u0EB0] + | [\u0EB2-\u0EB3] + | '\u0EBD' + | [\u0EC0-\u0EC4] + | '\u0EC6' + | [\u0EDC-\u0EDD] + | '\u0F00' + | [\u0F40-\u0F47] + | [\u0F49-\u0F6A] + | [\u0F88-\u0F8B] + | [\u1000-\u1021] + | [\u1023-\u1027] + | [\u1029-\u102A] + | [\u1050-\u1055] + | [\u10A0-\u10C5] + | [\u10D0-\u10FA] + | '\u10FC' + | [\u1100-\u1159] + | [\u115F-\u11A2] + | [\u11A8-\u11F9] + | [\u1200-\u1248] + | [\u124A-\u124D] + | [\u1250-\u1256] + | '\u1258' + | [\u125A-\u125D] + | [\u1260-\u1288] + | [\u128A-\u128D] + | [\u1290-\u12B0] + | [\u12B2-\u12B5] + | [\u12B8-\u12BE] + | '\u12C0' + | [\u12C2-\u12C5] + | [\u12C8-\u12D6] + | [\u12D8-\u1310] + | [\u1312-\u1315] + | [\u1318-\u135A] + | [\u1380-\u138F] + | [\u13A0-\u13F4] + | [\u1401-\u166C] + | [\u166F-\u1676] + | [\u1681-\u169A] + | [\u16A0-\u16EA] + | [\u16EE-\u16F0] + | [\u1700-\u170C] + | [\u170E-\u1711] + | [\u1720-\u1731] + | [\u1740-\u1751] + | [\u1760-\u176C] + | [\u176E-\u1770] + | [\u1780-\u17B3] + | '\u17D7' + | '\u17DC' + | [\u1820-\u1842] + | '\u1843' + | [\u1844-\u1877] + | [\u1880-\u18A8] + | [\u1900-\u191C] + | [\u1950-\u196D] + | [\u1970-\u1974] + | [\u1980-\u19A9] + | [\u19C1-\u19C7] + | [\u1A00-\u1A16] + | [\u1D00-\u1D2B] + | [\u1D2C-\u1D61] + | [\u1D62-\u1D77] + | '\u1D78' + | [\u1D79-\u1D9A] + | [\u1D9B-\u1DBF] + | [\u1E00-\u1E9B] + | [\u1EA0-\u1EF9] + | [\u1F00-\u1F15] + | [\u1F18-\u1F1D] + | [\u1F20-\u1F45] + | [\u1F48-\u1F4D] + | [\u1F50-\u1F57] + | '\u1F59' + | '\u1F5B' + | '\u1F5D' + | [\u1F5F-\u1F7D] + | [\u1F80-\u1FB4] + | [\u1FB6-\u1FBC] + | '\u1FBE' + | [\u1FC2-\u1FC4] + | [\u1FC6-\u1FCC] + | [\u1FD0-\u1FD3] + | [\u1FD6-\u1FDB] + | [\u1FE0-\u1FEC] + | [\u1FF2-\u1FF4] + | [\u1FF6-\u1FFC] + | '\u2071' + | '\u207F' + | [\u2090-\u2094] + | '\u2102' + | '\u2107' + | [\u210A-\u2113] + | '\u2115' + | '\u2118' + | [\u2119-\u211D] + | '\u2124' + | '\u2126' + | '\u2128' + | [\u212A-\u212D] + | '\u212E' + | [\u212F-\u2131] + | [\u2133-\u2134] + | [\u2135-\u2138] + | '\u2139' + | [\u213C-\u213F] + | [\u2145-\u2149] + | [\u2160-\u2183] + | [\u2C00-\u2C2E] + | [\u2C30-\u2C5E] + | [\u2C80-\u2CE4] + | [\u2D00-\u2D25] + | [\u2D30-\u2D65] + | '\u2D6F' + | [\u2D80-\u2D96] + | [\u2DA0-\u2DA6] + | [\u2DA8-\u2DAE] + | [\u2DB0-\u2DB6] + | [\u2DB8-\u2DBE] + | [\u2DC0-\u2DC6] + | [\u2DC8-\u2DCE] + | [\u2DD0-\u2DD6] + | [\u2DD8-\u2DDE] + | '\u3005' + | '\u3006' + | '\u3007' + | [\u3021-\u3029] + | [\u3031-\u3035] + | [\u3038-\u303A] + | '\u303B' + | '\u303C' + | [\u3041-\u3096] + | [\u309B-\u309C] + | [\u309D-\u309E] + | '\u309F' + | [\u30A1-\u30FA] + | [\u30FC-\u30FE] + | '\u30FF' + | [\u3105-\u312C] + | [\u3131-\u318E] + | [\u31A0-\u31B7] + | [\u31F0-\u31FF] + | [\u3400-\u4DB5] + | [\u4E00-\u9FBB] + | [\uA000-\uA014] + | '\uA015' + | [\uA016-\uA48C] + | [\uA800-\uA801] + | [\uA803-\uA805] + | [\uA807-\uA80A] + | [\uA80C-\uA822] + | [\uAC00-\uD7A3] + | [\uF900-\uFA2D] + | [\uFA30-\uFA6A] + | [\uFA70-\uFAD9] + | [\uFB00-\uFB06] + | [\uFB13-\uFB17] + | '\uFB1D' + | [\uFB1F-\uFB28] + | [\uFB2A-\uFB36] + | [\uFB38-\uFB3C] + | '\uFB3E' + | [\uFB40-\uFB41] + | [\uFB43-\uFB44] + | [\uFB46-\uFBB1] + | [\uFBD3-\uFD3D] + | [\uFD50-\uFD8F] + | [\uFD92-\uFDC7] + | [\uFDF0-\uFDFB] + | [\uFE70-\uFE74] + | [\uFE76-\uFEFC] + | [\uFF21-\uFF3A] + | [\uFF41-\uFF5A] + | [\uFF66-\uFF6F] + | '\uFF70' + | [\uFF71-\uFF9D] + | [\uFF9E-\uFF9F] + | [\uFFA0-\uFFBE] + | [\uFFC2-\uFFC7] + | [\uFFCA-\uFFCF] + | [\uFFD2-\uFFD7] + | [\uFFDA-\uFFDC] + ; + +/// id_continue ::= +fragment ID_CONTINUE + : ID_START + | [0-9] + | [\u0300-\u036F] + | [\u0483-\u0486] + | [\u0591-\u05B9] + | [\u05BB-\u05BD] + | '\u05BF' + | [\u05C1-\u05C2] + | [\u05C4-\u05C5] + | '\u05C7' + | [\u0610-\u0615] + | [\u064B-\u065E] + | [\u0660-\u0669] + | '\u0670' + | [\u06D6-\u06DC] + | [\u06DF-\u06E4] + | [\u06E7-\u06E8] + | [\u06EA-\u06ED] + | [\u06F0-\u06F9] + | '\u0711' + | [\u0730-\u074A] + | [\u07A6-\u07B0] + | [\u0901-\u0902] + | '\u0903' + | '\u093C' + | [\u093E-\u0940] + | [\u0941-\u0948] + | [\u0949-\u094C] + | '\u094D' + | [\u0951-\u0954] + | [\u0962-\u0963] + | [\u0966-\u096F] + | '\u0981' + | [\u0982-\u0983] + | '\u09BC' + | [\u09BE-\u09C0] + | [\u09C1-\u09C4] + | [\u09C7-\u09C8] + | [\u09CB-\u09CC] + | '\u09CD' + | '\u09D7' + | [\u09E2-\u09E3] + | [\u09E6-\u09EF] + | [\u0A01-\u0A02] + | '\u0A03' + | '\u0A3C' + | [\u0A3E-\u0A40] + | [\u0A41-\u0A42] + | [\u0A47-\u0A48] + | [\u0A4B-\u0A4D] + | [\u0A66-\u0A6F] + | [\u0A70-\u0A71] + | [\u0A81-\u0A82] + | '\u0A83' + | '\u0ABC' + | [\u0ABE-\u0AC0] + | [\u0AC1-\u0AC5] + | [\u0AC7-\u0AC8] + | '\u0AC9' + | [\u0ACB-\u0ACC] + | '\u0ACD' + | [\u0AE2-\u0AE3] + | [\u0AE6-\u0AEF] + | '\u0B01' + | [\u0B02-\u0B03] + | '\u0B3C' + | '\u0B3E' + | '\u0B3F' + | '\u0B40' + | [\u0B41-\u0B43] + | [\u0B47-\u0B48] + | [\u0B4B-\u0B4C] + | '\u0B4D' + | '\u0B56' + | '\u0B57' + | [\u0B66-\u0B6F] + | '\u0B82' + | [\u0BBE-\u0BBF] + | '\u0BC0' + | [\u0BC1-\u0BC2] + | [\u0BC6-\u0BC8] + | [\u0BCA-\u0BCC] + | '\u0BCD' + | '\u0BD7' + | [\u0BE6-\u0BEF] + | [\u0C01-\u0C03] + | [\u0C3E-\u0C40] + | [\u0C41-\u0C44] + | [\u0C46-\u0C48] + | [\u0C4A-\u0C4D] + | [\u0C55-\u0C56] + | [\u0C66-\u0C6F] + | [\u0C82-\u0C83] + | '\u0CBC' + | '\u0CBE' + | '\u0CBF' + | [\u0CC0-\u0CC4] + | '\u0CC6' + | [\u0CC7-\u0CC8] + | [\u0CCA-\u0CCB] + | [\u0CCC-\u0CCD] + | [\u0CD5-\u0CD6] + | [\u0CE6-\u0CEF] + | [\u0D02-\u0D03] + | [\u0D3E-\u0D40] + | [\u0D41-\u0D43] + | [\u0D46-\u0D48] + | [\u0D4A-\u0D4C] + | '\u0D4D' + | '\u0D57' + | [\u0D66-\u0D6F] + | [\u0D82-\u0D83] + | '\u0DCA' + | [\u0DCF-\u0DD1] + | [\u0DD2-\u0DD4] + | '\u0DD6' + | [\u0DD8-\u0DDF] + | [\u0DF2-\u0DF3] + | '\u0E31' + | [\u0E34-\u0E3A] + | [\u0E47-\u0E4E] + | [\u0E50-\u0E59] + | '\u0EB1' + | [\u0EB4-\u0EB9] + | [\u0EBB-\u0EBC] + | [\u0EC8-\u0ECD] + | [\u0ED0-\u0ED9] + | [\u0F18-\u0F19] + | [\u0F20-\u0F29] + | '\u0F35' + | '\u0F37' + | '\u0F39' + | [\u0F3E-\u0F3F] + | [\u0F71-\u0F7E] + | '\u0F7F' + | [\u0F80-\u0F84] + | [\u0F86-\u0F87] + | [\u0F90-\u0F97] + | [\u0F99-\u0FBC] + | '\u0FC6' + | '\u102C' + | [\u102D-\u1030] + | '\u1031' + | '\u1032' + | [\u1036-\u1037] + | '\u1038' + | '\u1039' + | [\u1040-\u1049] + | [\u1056-\u1057] + | [\u1058-\u1059] + | '\u135F' + | [\u1369-\u1371] + | [\u1712-\u1714] + | [\u1732-\u1734] + | [\u1752-\u1753] + | [\u1772-\u1773] + | '\u17B6' + | [\u17B7-\u17BD] + | [\u17BE-\u17C5] + | '\u17C6' + | [\u17C7-\u17C8] + | [\u17C9-\u17D3] + | '\u17DD' + | [\u17E0-\u17E9] + | [\u180B-\u180D] + | [\u1810-\u1819] + | '\u18A9' + | [\u1920-\u1922] + | [\u1923-\u1926] + | [\u1927-\u1928] + | [\u1929-\u192B] + | [\u1930-\u1931] + | '\u1932' + | [\u1933-\u1938] + | [\u1939-\u193B] + | [\u1946-\u194F] + | [\u19B0-\u19C0] + | [\u19C8-\u19C9] + | [\u19D0-\u19D9] + | [\u1A17-\u1A18] + | [\u1A19-\u1A1B] + | [\u1DC0-\u1DC3] + | [\u203F-\u2040] + | '\u2054' + | [\u20D0-\u20DC] + | '\u20E1' + | [\u20E5-\u20EB] + | [\u302A-\u302F] + | [\u3099-\u309A] + | '\uA802' + | '\uA806' + | '\uA80B' + | [\uA823-\uA824] + | [\uA825-\uA826] + | '\uA827' + | '\uFB1E' + | [\uFE00-\uFE0F] + | [\uFE20-\uFE23] + | [\uFE33-\uFE34] + | [\uFE4D-\uFE4F] + | [\uFF10-\uFF19] + | '\uFF3F' + ; diff --git a/server/pkg/antlr/python3/include/PythonAntlr.h b/server/pkg/antlr/python3/include/PythonAntlr.h new file mode 100644 index 0000000000000000000000000000000000000000..047f96ba2135fdcc22f661c5b5f4c44483864ec4 --- /dev/null +++ b/server/pkg/antlr/python3/include/PythonAntlr.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include + +#include "Python3Lexer.h" +#include "Python3Parser.h" +#include "IAntlrWrapper.h" +#include "antlr4-runtime.h" + +class PythonAntlr:public IAntlrWrapper { + private: + std::unique_ptr lexer_ptr; + std::unique_ptr parser_ptr; + std::unique_ptr input_ptr; + std::unique_ptr tokenStream_ptr; + + public: + PythonAntlr(std::istream &in); + ~PythonAntlr() override = default; + std::vector getTokens() override; + std::vector getTokensTypes() override; + std::vector getTokensNames() override; + std::vector> getTokensNamesWithPosition() override; + std::vector > > getTokensNamesWithFullPosition() override; + std::pair getTokensAndTree() override; + std::string getTokensString() override; + std::string getTreeString() override; +}; \ No newline at end of file diff --git a/server/pkg/antlr/python3/src/PythonAntlr.cpp b/server/pkg/antlr/python3/src/PythonAntlr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44aa199c26be97a0bbed6c5193b6afe9e540186d --- /dev/null +++ b/server/pkg/antlr/python3/src/PythonAntlr.cpp @@ -0,0 +1,102 @@ +#include "PythonAntlr.h" + +#include + +PythonAntlr::PythonAntlr(std::istream& in) { + input_ptr = std::make_unique(in); + lexer_ptr = std::make_unique(&(*input_ptr)); + tokenStream_ptr = std::make_unique(&(*lexer_ptr)); + parser_ptr = std::make_unique(&(*tokenStream_ptr)); +} + +std::vector PythonAntlr::getTokens() { + tokenStream_ptr->fill(); + std::vector ans(tokenStream_ptr->size()); + + int i = 0; + for (antlr4::Token *token : tokenStream_ptr->getTokens()) { + ans[i] = token; + i++; + } + + return ans; +} + +std::vector> PythonAntlr::getTokensNamesWithPosition(){ + tokenStream_ptr->fill(); + std::vector> ans(tokenStream_ptr->size()); + + int i = 0; + for (antlr4::Token *token : tokenStream_ptr->getTokens()) { + auto type = token->getText(); + int line = token->getLine(); + ans[i]=std::make_pair(type,line); + i++; + } + + return ans; +} + +std::vector > > PythonAntlr::getTokensNamesWithFullPosition(){ + tokenStream_ptr->fill(); + std::vector > > ans(tokenStream_ptr->size()); + + size_t i = 0; + for (antlr4::Token *token : tokenStream_ptr->getTokens()) { + auto type = token->getText(); + int line = token->getLine(); + int pos = token->getCharPositionInLine(); + ans[i] = std::make_pair(type, std::make_pair(line, pos)); + i++; + } + + return ans; +} + +std::vector PythonAntlr::getTokensTypes() { + tokenStream_ptr->fill(); + std::vector ans(tokenStream_ptr->size()); + + int i = 0; + for (antlr4::Token *token : tokenStream_ptr->getTokens()) { + ans[i] = token->getType(); + i++; + } + + return ans; +} + +std::string PythonAntlr::getTokensString() { + tokenStream_ptr->fill(); + std::string res; + + for (antlr4::Token* token : tokenStream_ptr->getTokens()) { + res += token->toString()+" "; + } + + return res; +} + +std::vector PythonAntlr::getTokensNames() { + tokenStream_ptr->fill(); + std::vector ans(tokenStream_ptr->size()); + + int i = 0; + for (antlr4::Token *token : tokenStream_ptr->getTokens()) { + ans[i] = token->getText(); + i++; + } + + return ans; +} + +std::string PythonAntlr::getTreeString() { + auto tree = parser_ptr->file_input(); + return tree->toStringTree(&(*parser_ptr)); +} + +std::pair PythonAntlr::getTokensAndTree() { + std::string tokens = getTokensString(); + std::string astTree = getTreeString(); + return std::make_pair(tokens, astTree); +} \ No newline at end of file diff --git a/server/pkg/antlr/testprogs/cpp/test.cpp b/server/pkg/antlr/testprogs/cpp/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..708f54faef6c2973eac82325711aac97dc313926 --- /dev/null +++ b/server/pkg/antlr/testprogs/cpp/test.cpp @@ -0,0 +1,13 @@ +#include + + +int main() +{ + std::string res; + int a; + if (true && true) { + std::cout << "Hello World!"; + } + return 0; +} + diff --git a/server/pkg/antlr/testprogs/python/test.py b/server/pkg/antlr/testprogs/python/test.py new file mode 100644 index 0000000000000000000000000000000000000000..327d9004f717869738016e24306e6757c3ed0b1f --- /dev/null +++ b/server/pkg/antlr/testprogs/python/test.py @@ -0,0 +1,7 @@ +var_1 = 1567 +reverse = 0 +while var_1 > 0: + rest = var_1 % 10 + reverse = reverse * 10 + rest + var_1 = var_1 // 10 +print("Число в обратном порядке:", reverse) \ No newline at end of file diff --git a/server/pkg/antlr/virtual/IAntlrWrapper.h b/server/pkg/antlr/virtual/IAntlrWrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..c4452fe1f531b3a89fc51a775a5ded7297cfa0bf --- /dev/null +++ b/server/pkg/antlr/virtual/IAntlrWrapper.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "antlr4-runtime.h" + +class IAntlrWrapper { + public: + virtual ~IAntlrWrapper() = default; + virtual std::vector getTokens() = 0; + virtual std::vector getTokensTypes() = 0; + virtual std::vector getTokensNames() = 0; + virtual std::vector> getTokensNamesWithPosition() = 0; + virtual std::vector > > getTokensNamesWithFullPosition() = 0; + virtual std::pair getTokensAndTree() = 0; + virtual std::string getTokensString() = 0; + virtual std::string getTreeString() = 0; +}; diff --git a/src/main.cpp b/src/main.cpp index cbd2bd5cf24d419d22f50b5d29560a8591df4ecf..2eade44ba266eebca7e330a2c219da206e1475b7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,264 +1,30 @@ - -#include -#include -#include -#include -#include -#include #include -#include -#include -#include - -namespace beast = boost::beast; // from -namespace http = beast::http; // from -namespace net = boost::asio; // from -using tcp = boost::asio::ip::tcp; // from - -//------------------------------------------------------------------------------ - -// Return a reasonable mime type based on the extension of a file. -beast::string_view mime_type(beast::string_view path) { - using beast::iequals; - auto const ext = [&path] { - auto const pos = path.rfind("."); - if (pos == beast::string_view::npos) return beast::string_view{}; - return path.substr(pos); - }(); - if (iequals(ext, ".htm")) return "text/html"; - if (iequals(ext, ".html")) return "text/html"; - if (iequals(ext, ".php")) return "text/html"; - if (iequals(ext, ".css")) return "text/css"; - if (iequals(ext, ".txt")) return "text/plain"; - if (iequals(ext, ".js")) return "application/javascript"; - if (iequals(ext, ".json")) return "application/json"; - if (iequals(ext, ".xml")) return "application/xml"; - if (iequals(ext, ".swf")) return "application/x-shockwave-flash"; - if (iequals(ext, ".flv")) return "video/x-flv"; - if (iequals(ext, ".png")) return "image/png"; - if (iequals(ext, ".jpe")) return "image/jpeg"; - if (iequals(ext, ".jpeg")) return "image/jpeg"; - if (iequals(ext, ".jpg")) return "image/jpeg"; - if (iequals(ext, ".gif")) return "image/gif"; - if (iequals(ext, ".bmp")) return "image/bmp"; - if (iequals(ext, ".ico")) return "image/vnd.microsoft.icon"; - if (iequals(ext, ".tiff")) return "image/tiff"; - if (iequals(ext, ".tif")) return "image/tiff"; - if (iequals(ext, ".svg")) return "image/svg+xml"; - if (iequals(ext, ".svgz")) return "image/svg+xml"; - return "application/text"; -} - -// Append an HTTP rel-path to a local filesystem path. -// The returned path is normalized for the platform. -std::string path_cat(beast::string_view base, beast::string_view path) { - if (base.empty()) return std::string(path); - std::string result(base); -#ifdef BOOST_MSVC - char constexpr path_separator = '\\'; - if (result.back() == path_separator) result.resize(result.size() - 1); - result.append(path.data(), path.size()); - for (auto& c : result) - if (c == '/') c = path_separator; -#else - char constexpr path_separator = '/'; - if (result.back() == path_separator) result.resize(result.size() - 1); - result.append(path.data(), path.size()); -#endif - return result; -} - -// This function produces an HTTP response for the given -// request. The type of the response object depends on the -// contents of the request, so the interface requires the -// caller to pass a generic lambda for receiving the response. -template -void handle_request(beast::string_view doc_root, - http::request>&& req, - Send&& send) { - // Returns a bad request response - auto const bad_request = [&req](beast::string_view why) { - http::response res{http::status::bad_request, - req.version()}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, "text/html"); - res.keep_alive(req.keep_alive()); - res.body() = std::string(why); - res.prepare_payload(); - return res; - }; - - // Returns a not found response - auto const not_found = [&req](beast::string_view target) { - http::response res{http::status::not_found, - req.version()}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, "text/html"); - res.keep_alive(req.keep_alive()); - res.body() = "The resource '" + std::string(target) + "' was not found."; - res.prepare_payload(); - return res; - }; - - // Returns a server error response - auto const server_error = [&req](beast::string_view what) { - http::response res{http::status::internal_server_error, - req.version()}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, "text/html"); - res.keep_alive(req.keep_alive()); - res.body() = "An error occurred: '" + std::string(what) + "'"; - res.prepare_payload(); - return res; - }; - - // Make sure we can handle the method - if (req.method() != http::verb::get && req.method() != http::verb::head) - return send(bad_request("Unknown HTTP-method")); - - // Request path must be absolute and not contain "..". - if (req.target().empty() || req.target()[0] != '/' || - req.target().find("..") != beast::string_view::npos) - return send(bad_request("Illegal request-target")); - - // Build the path to the requested file - std::string path = path_cat(doc_root, req.target()); - if (req.target().back() == '/') path.append("index.html"); - - // Attempt to open the file - beast::error_code ec; - http::file_body::value_type body; - body.open(path.c_str(), beast::file_mode::scan, ec); - - // Handle the case where the file doesn't exist - if (ec == beast::errc::no_such_file_or_directory) - return send(not_found(req.target())); - - // Handle an unknown error - if (ec) return send(server_error(ec.message())); - - // Cache the size since we need it after the move - auto const size = body.size(); - - // Respond to HEAD request - if (req.method() == http::verb::head) { - http::response res{http::status::ok, req.version()}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, mime_type(path)); - res.content_length(size); - res.keep_alive(req.keep_alive()); - return send(std::move(res)); - } - - // Respond to GET request - http::response res{ - std::piecewise_construct, std::make_tuple(std::move(body)), - std::make_tuple(http::status::ok, req.version())}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, mime_type(path)); - res.content_length(size); - res.keep_alive(req.keep_alive()); - return send(std::move(res)); -} - -//------------------------------------------------------------------------------ - -// Report a failure -void fail(beast::error_code ec, char const* what) { - std::cerr << what << ": " << ec.message() << "\n"; -} - -// This is the C++11 equivalent of a generic lambda. -// The function object is used to send an HTTP message. -template -struct send_lambda { - Stream& stream_; - bool& close_; - beast::error_code& ec_; - - explicit send_lambda(Stream& stream, bool& close, beast::error_code& ec) - : stream_(stream), close_(close), ec_(ec) {} - - template - void operator()(http::message&& msg) const { - // Determine if we should close the connection after - close_ = msg.need_eof(); - - // We need the serializer here because the serializer requires - // a non-const file_body, and the message oriented version of - // http::write only works with const messages. - http::serializer sr{msg}; - http::write(stream_, sr, ec_); - } -}; - -// Handles an HTTP server connection -void do_session(tcp::socket& socket, - std::shared_ptr const& doc_root) { - bool close = false; - beast::error_code ec; - - // This buffer is required to persist across reads - beast::flat_buffer buffer; - - // This lambda is used to send messages - send_lambda lambda{socket, close, ec}; - - for (;;) { - // Read a request - http::request req; - http::read(socket, buffer, req, ec); - if (ec == http::error::end_of_stream) break; - if (ec) return fail(ec, "read"); - - // Send the response - handle_request(*doc_root, std::move(req), lambda); - if (ec) return fail(ec, "write"); - if (close) { - // This means we should close the connection, usually because - // the response indicated the "Connection: close" semantic. - break; - } - } +#include - // Send a TCP shutdown - socket.shutdown(tcp::socket::shutdown_send, ec); +#include "TextMetricsLib.h" - // At this point the connection is closed gracefully -} +int main(){ + std::ifstream fin1; + fin1.open("metrics/testProgs/code1.txt"); + assert(fin1.is_open()); -//------------------------------------------------------------------------------ + std::ifstream fin2; + fin2.open("metrics/testProgs/code2.txt"); + assert(fin2.is_open()); -int main(int argc, char* argv[]) { - try { - // Check command line arguments. - if (argc != 4) { - std::cerr << "Usage: http-server-sync
\n" - << "Example:\n" - << " http-server-sync 0.0.0.0 8080 .\n"; - return EXIT_FAILURE; - } - auto const address = net::ip::make_address(argv[1]); - auto const port = static_cast(std::atoi(argv[2])); - auto const doc_root = std::make_shared(argv[3]); + std::string text1( (std::istreambuf_iterator(fin1) ), + (std::istreambuf_iterator() ) ); - // The io_context is required for all I/O - net::io_context ioc{1}; + std::string text2( (std::istreambuf_iterator(fin2) ), + (std::istreambuf_iterator() ) ); + fin1.close(); + fin2.close(); - // The acceptor receives incoming connections - tcp::acceptor acceptor{ioc, {address, port}}; - for (;;) { - // This will receive the new connection - tcp::socket socket{ioc}; + LevDistTextMetric livDistTextMetric; + JaccardTextMetric jaccardTextMetric; - // Block until we get a connection - acceptor.accept(socket); + livDistTextMetric.setData(text1, text2); + jaccardTextMetric.setData(text1, text2); - // Launch the session, transferring ownership of the socket - std::thread{std::bind(&do_session, std::move(socket), doc_root)}.detach(); - } - } catch (const std::exception& e) { - std::cerr << "Error: " << e.what() << std::endl; - return EXIT_FAILURE; - } -} + std::cout << livDistTextMetric.getMetric() << std::endl << jaccardTextMetric.getMetric(); +} \ No newline at end of file diff --git a/text-basic-metrics/code2.txt b/text-basic-metrics/code2.txt deleted file mode 100644 index 2115b76e6866f8af7e14dbd7de1ed6fe3a2c9ec2..0000000000000000000000000000000000000000 --- a/text-basic-metrics/code2.txt +++ /dev/null @@ -1,29 +0,0 @@ -// однострочный комментарий -// еще один -// вау еще один - -#include -#include -#include - -using namespace std; - -/* многострочный комм - * // внутри него однострочный - * - */ - - -int main() { - stringstream ss1; - string res1; - // ещё в код напихаю комментов - ss1 << "a bwfw ce "; - while(getline(ss, res1, ' ')){ //комментарий после строки с кодом - /* - * летс гоу - * худшее место для многострочного коммента - */ - cout << res1 << endl; /* многострочный однострочно */ - } -} \ No newline at end of file diff --git a/text-basic-metrics/tbm_main.cpp b/text-basic-metrics/tbm_main.cpp deleted file mode 100644 index fdd4253768b6369af5fe434526e26cbb9fc30bcd..0000000000000000000000000000000000000000 --- a/text-basic-metrics/tbm_main.cpp +++ /dev/null @@ -1,153 +0,0 @@ -// -// Created by march on 21.04.2023. -// - -#include -#include -#include -#include -#include -#include -#include - -#include - - -std::string deleteComms(const std::string& text){ - std::string modif; - std::string res; - - std::stringstream ss; - std::string line; - - ss << text; - - while(getline(ss, line)){ - line.pop_back(); - line.push_back('\0'); - modif += line; - } - - bool s_comm = false; - bool m_comm = false; - - for (int i = 0; i < modif.size(); i++){ - if (s_comm && modif[i] == '\0') - s_comm = false; - else if (m_comm && modif[i] == '*' && modif[i + 1] == '/') - m_comm = false, i++; - else if (s_comm || m_comm) - continue; - else if (modif[i] == '/' && modif[i+1] == '/') - s_comm = true, i++; - else if (modif[i] == '/' && modif[i+1] == '*') - m_comm = true, i++; - - else if (modif[i] != '\0') - res += modif[i]; - else{ - res += '\n'; - } - } - return res; -} - -std::vector tbm_tokenizer(const std::string &text){ - boost::char_separator sep(" {}();,\"\0\'"); - std::vector res; - boost::tokenizer < boost::char_separator > tokens(text, sep); - - for (const std::string &s: tokens) { - if (!s.empty() && s[0] != '\n' && s[0] != '\0'){ - res.push_back(s); - } - } - return res; -} - -// % = intersection(A, B) / union(A, B) -double Jaccard_metric(const std::vector & tokens1, const std::vector & tokens2){ - std::set s1; - std::set s2; - - for (auto &i : tokens1) s1.insert(i); - for (auto &i : tokens2) s2.insert(i); - - - std::set intersect_sets; - set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), - std::inserter(intersect_sets, intersect_sets.begin())); - - std::set union_sets; - set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), - std::inserter(union_sets, union_sets.begin())); - - std::cout << intersect_sets.size() << " " << union_sets.size() << std::endl; - - return static_cast (intersect_sets.size()) / static_cast (union_sets.size()); -} - -double Livenstain_dist(std::vector tokens1, std::vector tokens2){ - unsigned long n = tokens1.size(); - unsigned long m = tokens2.size(); - int x, y, z; - - std::vector > lev (n, std::vector (m, 0)); - - for (int i = 0; i < n; i++){ - for (int j = 0; j < m; j++){ - if (std::min(i, j) == 0){ - lev[i][j] = std::max(i, j); - } - else{ - x = lev[i-1][j]; - y = lev[i][j-1]; - z = lev[i-1][j-1]; - lev[i][j] = std::min(x, std::min(y, z)); - if (tokens1[i] != tokens2[j]){ - lev[i][j]++; - } - } - } - } - - return lev[n-1][m-1]; -} - -std::pair textCompare(std::istream& fin1, std::istream& fin2){ - std::string line; - - std::string text1( (std::istreambuf_iterator(fin1) ), - (std::istreambuf_iterator() ) ); - - std::string text2( (std::istreambuf_iterator(fin2) ), - (std::istreambuf_iterator() ) ); - - std::string non_comm_text1 = deleteComms(text1); - std::string non_comm_text2 = deleteComms(text2); - - std::vector tokens1 = tbm_tokenizer(non_comm_text1); - std::vector tokens2 = tbm_tokenizer(non_comm_text2); - - double res1 = Jaccard_metric(tokens1, tokens2); - double res2 = 1 - Livenstain_dist(tokens1, tokens2) / std::max(tokens1.size(), tokens2.size()); - - return {res1, res2}; -} - -int main(){ - - std::ifstream fin1; - fin1.open("text-basic-metrics/code1.txt"); - assert(fin1.is_open()); - - std::ifstream fin2; - fin2.open("text-basic-metrics/code2.txt"); - assert(fin2.is_open()); - - std::pair metrics_res = textCompare(fin1, fin2); - - std::cout << "Jaccard metric "<< metrics_res.first << "\nLivenstein distance: " << metrics_res.second; - fin1.close(); - fin2.close(); -} \ No newline at end of file