diff --git a/.clang-format b/.clang-format index 61dec384..46a0a466 100644 --- a/.clang-format +++ b/.clang-format @@ -139,3 +139,15 @@ KeepEmptyLines: AtEndOfFile: false AtStartOfBlock: false AtStartOfFile: false + +StatementMacros: + - DECO_CFG_START + - DECO_CFG + - DECO_CFG_END + - DecoKV + - DecoFlag + - DecoComma + - DecoInput + - DecoPack + - DecoKVStyled + - DecoMulti diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 05508108..9fe22401 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -72,10 +72,10 @@ jobs: uses: ./.github/workflows/deploy-docs.yml secrets: inherit - clice: - needs: changes - if: ${{ needs.changes.outputs.clice == 'true' }} - uses: ./.github/workflows/publish-clice.yml + # clice: + # needs: changes + # if: ${{ needs.changes.outputs.clice == 'true' }} + # uses: ./.github/workflows/publish-clice.yml vscode: needs: changes @@ -87,10 +87,10 @@ jobs: if: ${{ needs.changes.outputs.cmake == 'true' }} uses: ./.github/workflows/test-cmake.yml - xmake: - needs: changes - if: ${{ needs.changes.outputs.xmake == 'true' }} - uses: ./.github/workflows/test-xmake.yml + # xmake: + # needs: changes + # if: ${{ needs.changes.outputs.xmake == 'true' }} + # uses: ./.github/workflows/test-xmake.yml release-clice: permissions: @@ -111,10 +111,10 @@ jobs: needs: - format - deploy - - clice + # - clice - vscode - cmake - - xmake + # - xmake runs-on: ubuntu-latest steps: - name: Check results diff --git a/.github/workflows/test-cmake.yml b/.github/workflows/test-cmake.yml index 92877402..34286459 100644 --- a/.github/workflows/test-cmake.yml +++ b/.github/workflows/test-cmake.yml @@ -26,4 +26,4 @@ jobs: run: pixi run build ${{ matrix.build_type }} ON - name: Test - run: pixi run test ${{ matrix.build_type }} + run: pixi run unit-test ${{ matrix.build_type }} diff --git a/CMakeLists.txt b/CMakeLists.txt index be05958e..df9d5a81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,8 +29,6 @@ if(CLICE_ENABLE_LTO) string(APPEND CMAKE_MODULE_LINKER_FLAGS " -flto=thin") endif() - - if(CMAKE_BUILD_TYPE STREQUAL "Debug") add_compile_options(-fsanitize=address) @@ -112,7 +110,6 @@ if(MSVC OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND else() target_compile_options(clice_options INTERFACE -fno-rtti - -fno-exceptions -Wno-deprecated-declarations -Wno-undefined-inline -ffunction-sections @@ -120,65 +117,75 @@ else() ) endif() -set(FBS_SCHEMA_FILE "${CMAKE_CURRENT_SOURCE_DIR}/include/Index/schema.fbs") -set(GENERATED_HEADER "${CMAKE_CURRENT_BINARY_DIR}/generated/schema_generated.h") +set(FBS_SCHEMA_FILE "${PROJECT_SOURCE_DIR}/src/index/schema.fbs") +set(GENERATED_HEADER "${PROJECT_BINARY_DIR}/generated/schema_generated.h") add_custom_command( - OUTPUT ${GENERATED_HEADER} - COMMAND $ --cpp -o ${CMAKE_CURRENT_BINARY_DIR}/generated ${FBS_SCHEMA_FILE} - DEPENDS ${FBS_SCHEMA_FILE} + OUTPUT "${GENERATED_HEADER}" + COMMAND $ --cpp -o "${PROJECT_BINARY_DIR}/generated" "${FBS_SCHEMA_FILE}" + DEPENDS "${FBS_SCHEMA_FILE}" COMMENT "Generating C++ header from ${FBS_SCHEMA_FILE}" ) -add_custom_target( - generate_flatbuffers_schema - DEPENDS ${GENERATED_HEADER} -) +add_custom_target(generate_flatbuffers_schema DEPENDS "${GENERATED_HEADER}") -set(CONFIG_SOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/config/clang-tidy-config.h") -set(CONFIG_GENERATED_FILE "${CMAKE_CURRENT_BINARY_DIR}/generated/clang-tidy-config.h") - -add_custom_command( - OUTPUT ${CONFIG_GENERATED_FILE} - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CONFIG_SOURCE_FILE} ${CONFIG_GENERATED_FILE} - DEPENDS ${CONFIG_SOURCE_FILE} - COMMENT "Generating C++ header from ${CONFIG_SOURCE_FILE}" +# Temporary migration-only build graph. +add_library(clice-core STATIC + "${PROJECT_SOURCE_DIR}/src/server/server.cpp" + "${PROJECT_SOURCE_DIR}/src/server/worker.cpp" + "${PROJECT_SOURCE_DIR}/src/compile/command.cpp" + "${PROJECT_SOURCE_DIR}/src/compile/toolchain.cpp" + "${PROJECT_SOURCE_DIR}/src/compile/compilation.cpp" + "${PROJECT_SOURCE_DIR}/src/compile/compilation_unit.cpp" + "${PROJECT_SOURCE_DIR}/src/compile/diagnostic.cpp" + "${PROJECT_SOURCE_DIR}/src/compile/directive.cpp" + "${PROJECT_SOURCE_DIR}/src/compile/preamble.cpp" + "${PROJECT_SOURCE_DIR}/src/compile/tidy.cpp" + "${PROJECT_SOURCE_DIR}/src/support/doxygen.cpp" + "${PROJECT_SOURCE_DIR}/src/support/structed_text.cpp" + "${PROJECT_SOURCE_DIR}/src/support/fuzzy_matcher.cpp" + "${PROJECT_SOURCE_DIR}/src/support/glob_pattern.cpp" + "${PROJECT_SOURCE_DIR}/src/support/logging.cpp" + "${PROJECT_SOURCE_DIR}/src/syntax/lexer.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/semantic_tokens.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/document_links.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/document_symbols.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/folding_ranges.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/code_completion.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/hover.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/inlay_hints.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/signature_help.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/formatting.cpp" + "${PROJECT_SOURCE_DIR}/src/feature/diagnostics.cpp" + "${PROJECT_SOURCE_DIR}/src/semantic/resolver.cpp" + "${PROJECT_SOURCE_DIR}/src/semantic/symbol_kind.cpp" + "${PROJECT_SOURCE_DIR}/src/semantic/ast_utility.cpp" + "${PROJECT_SOURCE_DIR}/src/semantic/selection.cpp" + "${PROJECT_SOURCE_DIR}/src/index/include_graph.cpp" + "${PROJECT_SOURCE_DIR}/src/index/tu_index.cpp" + "${PROJECT_SOURCE_DIR}/src/index/usr_generation.cpp" + "${PROJECT_SOURCE_DIR}/src/index/project_index.cpp" + "${PROJECT_SOURCE_DIR}/src/index/merged_index.cpp" ) - -add_custom_target( - generate_config - DEPENDS ${CONFIG_GENERATED_FILE} -) - -file(GLOB_RECURSE CLICE_SOURCES CONFIGURE_DEPENDS - "${PROJECT_SOURCE_DIR}/src/AST/*.cpp" - "${PROJECT_SOURCE_DIR}/src/Async/*.cpp" - "${PROJECT_SOURCE_DIR}/src/Basic/*.cpp" - "${PROJECT_SOURCE_DIR}/src/Compiler/*.cpp" - "${PROJECT_SOURCE_DIR}/src/Index/*.cpp" - "${PROJECT_SOURCE_DIR}/src/Feature/*.cpp" - "${PROJECT_SOURCE_DIR}/src/Server/*.cpp" - "${PROJECT_SOURCE_DIR}/src/Support/*.cpp" -) -add_library(clice-core STATIC "${CLICE_SOURCES}") -add_dependencies(clice-core generate_flatbuffers_schema generate_config) +add_library(clice::core ALIAS clice-core) +add_dependencies(clice-core generate_flatbuffers_schema) target_include_directories(clice-core PUBLIC - "${PROJECT_SOURCE_DIR}/include" - "${CMAKE_CURRENT_BINARY_DIR}/generated" + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_BINARY_DIR}/generated" ) target_link_libraries(clice-core PUBLIC clice_options - libuv::libuv + llvm-libs spdlog::spdlog - tomlplusplus::tomlplusplus roaring::roaring flatbuffers - llvm-libs + eventide::async + eventide::language ) add_executable(clice "${PROJECT_SOURCE_DIR}/src/clice.cc") -target_link_libraries(clice PRIVATE clice-core) +target_link_libraries(clice PRIVATE clice::core eventide::deco) install(TARGETS clice RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) message(STATUS "Copying resource directory for development build") @@ -193,11 +200,21 @@ install( if(CLICE_ENABLE_TEST) file(GLOB_RECURSE CLICE_TEST_SOURCES CONFIGURE_DEPENDS - "${PROJECT_SOURCE_DIR}/tests/unit/*/*.cpp") - add_executable(unit_tests - "${CLICE_TEST_SOURCES}" - "${PROJECT_SOURCE_DIR}/tests/unit/unit_tests.cc" + "${PROJECT_SOURCE_DIR}/tests/unit/*/*_tests.cpp" ) - target_include_directories(unit_tests PUBLIC "${PROJECT_SOURCE_DIR}") - target_link_libraries(unit_tests PRIVATE clice-core cpptrace::cpptrace) + set(CLICE_TEST_SUPPORT_SOURCES + "${PROJECT_SOURCE_DIR}/tests/unit/test/annotation.cpp" + "${PROJECT_SOURCE_DIR}/tests/unit/test/tester.cpp" + ) + + add_executable(unit_tests + "${PROJECT_SOURCE_DIR}/tests/unit/unit_tests.cc" + ${CLICE_TEST_SOURCES} + ${CLICE_TEST_SUPPORT_SOURCES} + ) + target_include_directories(unit_tests PRIVATE + "${PROJECT_SOURCE_DIR}/src" + "${PROJECT_SOURCE_DIR}/tests/unit" + ) + target_link_libraries(unit_tests PRIVATE clice::core eventide::zest) endif() diff --git a/cmake/package.cmake b/cmake/package.cmake index 769c4550..61fb68b7 100644 --- a/cmake/package.cmake +++ b/cmake/package.cmake @@ -7,28 +7,6 @@ setup_llvm("21.1.4+r1") include(FetchContent) set(FETCHCONTENT_UPDATES_DISCONNECTED ON) -if(WIN32) - set(NULL_DEVICE NUL) -else() - set(NULL_DEVICE /dev/null) -endif() - -# libuv -FetchContent_Declare( - libuv - GIT_REPOSITORY https://github.com/libuv/libuv.git - GIT_TAG v1.x - GIT_SHALLOW TRUE - -) - -if(NOT WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Debug") - set(ASAN ON CACHE BOOL "Enable AddressSanitizer for libuv" FORCE) -endif() -set(LIBUV_BUILD_SHARED OFF CACHE BOOL "" FORCE) -set(LIBUV_BUILD_TESTS OFF CACHE BOOL "" FORCE) -set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) - # spdlog FetchContent_Declare( spdlog @@ -66,30 +44,18 @@ set(FLATBUFFERS_BUILD_GRPC OFF CACHE BOOL "" FORCE) set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(FLATBUFFERS_BUILD_FLATHASH OFF CACHE BOOL "" FORCE) -# cpptrace FetchContent_Declare( - cpptrace - GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git - GIT_TAG v1.0.4 + eventide + GIT_REPOSITORY https://github.com/clice-io/eventide + GIT_TAG main GIT_SHALLOW TRUE ) -set(CPPTRACE_DISABLE_CXX_20_MODULES ON CACHE BOOL "" FORCE) +set(EVENTIDE_ENABLE_ZEST ON) +set(EVENTIDE_ENABLE_TEST OFF) +set(EVENTIDE_SERDE_ENABLE_SIMDJSON ON) +set(EVENTIDE_SERDE_ENABLE_YYJSON ON) -FetchContent_MakeAvailable(libuv spdlog tomlplusplus croaring flatbuffers cpptrace) - -if(WIN32) - target_compile_definitions(uv_a PRIVATE _CRT_SECURE_NO_WARNINGS) -endif() - -if(NOT MSVC AND TARGET uv_a) - target_compile_options(uv_a PRIVATE - "-Wno-unused-function" - "-Wno-unused-variable" - "-Wno-unused-but-set-variable" - "-Wno-deprecated-declarations" - "-Wno-missing-braces" - ) -endif() +FetchContent_MakeAvailable(eventide spdlog tomlplusplus croaring flatbuffers) target_compile_definitions(spdlog PUBLIC SPDLOG_USE_STD_FORMAT=1 diff --git a/include/AST/RelationKind.h b/include/AST/RelationKind.h deleted file mode 100644 index d90fe973..00000000 --- a/include/AST/RelationKind.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include "Support/Enum.h" - -namespace clice { - -struct RelationKind : refl::Enum { - enum Kind : uint32_t { - Invalid, - Declaration, - Definition, - Reference, - WeakReference, - // Write Relation. - Read, - Write, - Interface, - Implementation, - /// When target is a type definition of source, source is possible type or constructor. - TypeDefinition, - - /// When target is a base class of source. - Base, - /// When target is a derived class of source. - Derived, - - /// When target is a constructor of source. - Constructor, - /// When target is a destructor of source. - Destructor, - - // When target is a caller of source. - Caller, - // When target is a callee of source. - Callee, - }; - - using Enum::Enum; - - constexpr bool isDeclOrDef() { - return is_one_of(Declaration, Definition); - } - - constexpr bool isReference() { - return is_one_of(Reference, WeakReference); - } - - constexpr bool isBetweenSymbol() { - return is_one_of(Interface, - Implementation, - TypeDefinition, - Base, - Derived, - Constructor, - Destructor); - } - - constexpr bool isCall() { - return is_one_of(Caller, Callee); - } -}; - -} // namespace clice diff --git a/include/AST/SourceCode.h b/include/AST/SourceCode.h deleted file mode 100644 index a07e9ef6..00000000 --- a/include/AST/SourceCode.h +++ /dev/null @@ -1,193 +0,0 @@ -#pragma once - -#include - -#include "clang/Basic/SourceLocation.h" -#include "clang/Lex/Token.h" - -namespace std { - -template <> -struct tuple_size : std::integral_constant {}; - -template <> -struct tuple_element<0, clang::SourceRange> { - using type = clang::SourceLocation; -}; - -template <> -struct tuple_element<1, clang::SourceRange> { - using type = clang::SourceLocation; -}; - -} // namespace std - -namespace clang { - -/// Through ADL, make `clang::SourceRange` could be destructured. -template -clang::SourceLocation get(clang::SourceRange range) { - if constexpr(I == 0) { - return range.getBegin(); - } else { - return range.getEnd(); - } -} - -class Lexer; - -} // namespace clang - -namespace clice { - -struct LocalSourceRange { - /// The begin position offset to the source file. - uint32_t begin = static_cast(-1); - - /// The end position offset to the source file. - uint32_t end = static_cast(-1); - - constexpr bool operator==(const LocalSourceRange& other) const = default; - - constexpr auto length() { - return end - begin; - } - - constexpr bool contains(uint32_t offset) const { - return offset >= begin && offset <= end; - } - - constexpr bool intersects(const LocalSourceRange& other) const { - return begin <= other.end && end >= other.begin; - } - - constexpr bool valid() const { - return begin != -1 && end != -1; - } -}; - -using TokenKind = clang::tok::TokenKind; - -struct Token { - /// Whether this token is at the start of line. - bool is_at_start_of_line = false; - - /// Whether this token is a preprocessor directive. - bool is_pp_keyword = false; - - /// The kind of this token. - TokenKind kind; - - /// The source range of this token. - LocalSourceRange range; - - bool valid() { - return range.valid(); - } - - llvm::StringRef name() const { - return clang::tok::getTokenName(kind); - } - - llvm::StringRef text(llvm::StringRef content) const { - assert(range.valid() && "Invalid source range"); - return content.substr(range.begin, range.end - range.begin); - } - - bool is_eod() const { - return kind == clang::tok::eod; - } - - bool is_eof() const { - return kind == clang::tok::eof; - } - - bool is_identifier() const { - return kind == clang::tok::raw_identifier; - } - - bool is_directive_hash() const { - return is_at_start_of_line && kind == clang::tok::hash; - } - - /// The tokens after the include directive are regarded as - /// a whole token, whose kind is `header_name`. For example - /// `` and `"test.h"` are both header name. - bool is_header_name() const { - return kind == clang::tok::header_name; - } -}; - -class Lexer { -public: - Lexer(llvm::StringRef content, - bool ignore_comments = true, - const clang::LangOptions* lang_opts = nullptr, - bool ignore_end_of_directive = true); - - Lexer(const Lexer&) = delete; - - Lexer(Lexer&&) = delete; - - Lexer& operator=(const Lexer&) = delete; - - Lexer& operator=(Lexer&&) = delete; - - ~Lexer(); - - void lex(Token& token); - - /// Get the token before this token without moving the lexer. - Token last(); - - /// Get the token after this token without moving the lexer. - Token next(); - - /// Advance the lexer and return the next token. - Token advance(); - - /// Advance the lexer if the next token kind is the param. - std::optional advance_if(llvm::function_ref callback); - - std::optional advance_if(llvm::StringRef spelling) { - return advance_if([&](const Token& token) { - return token.is_identifier() && token.text(content) == spelling; - }); - } - - std::optional advance_if(TokenKind kind) { - return advance_if([&](const Token& token) { return token.kind == kind; }); - } - - /// Advance the lexer until meet the specific kind token. - Token advance_until(TokenKind kind); - -private: - /// If this is set to false, the lexer will emit tok::eod at the end - /// of directive. - bool ignore_end_of_directive = true; - - /// Whether we are lexing the preprocessor directive. - bool parse_pp_keyword = false; - - /// Whether we are lexing the header name. - bool parse_header_name = false; - - bool module_declaration_context = true; - - /// The cache of last token. - Token last_token; - - /// The cache of current token. - Token current_token; - - /// The cache of next token. - std::optional next_token; - - /// The lexed content. - llvm::StringRef content; - - std::unique_ptr lexer; -}; - -} // namespace clice diff --git a/include/Async/Async.h b/include/Async/Async.h deleted file mode 100644 index f249b780..00000000 --- a/include/Async/Async.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "Event.h" -#include "FileSystem.h" -#include "Gather.h" -#include "Lock.h" -#include "Network.h" -#include "Sleep.h" -#include "ThreadPool.h" -#include "libuv.h" diff --git a/include/Async/Awaiter.h b/include/Async/Awaiter.h deleted file mode 100644 index 80c11cdd..00000000 --- a/include/Async/Awaiter.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include - -#include "Task.h" -#include "libuv.h" - -namespace clice::async::awaiter { - -template -struct uv_base; - -template - requires (is_uv_handle_v) -struct uv_base { - /// For libuv handles, `uv_close` must be called to release resources. - /// However, `uv_close` can only be async operation. When close is actually called, - /// the promise object may have already been destroyed, leading to undefined behavior - /// such as use-after-free. To avoid this situation, we allocate memory separately - /// for the handle and destroy it in the callback function. - Request& request; - - uv_base() : request(*static_cast(std::malloc(sizeof(Request)))) {} - - ~uv_base() { - uv_close(reinterpret_cast(&request), - [](uv_handle_t* handle) { std::free(handle); }); - } -}; - -template - requires (is_uv_req_v) -struct uv_base { - /// For libuv requests, they don't need to be closed. We can lay them on the promise - /// object directly. - Request request; -}; - -/// The CRTP base class for the awaiter of libuv async operations. The Derived should -/// implement the `start` and `cleanup` functions. -template -struct uv : uv_base { - int error = 0; - promise_base* continuation; - - bool await_ready() const noexcept { - return false; - } - - /// The callback function to handle the async operation. This should always called - /// in the main thread. - static void callback(Request* request, Extras... extras) { - auto& self = *static_cast(request->data); - - /// The derived should implement the cleanup function to release resources or set - /// the error code if the async operation fails. - self.cleanup(extras...); - - /// Then we resume the coroutine. It may destroy the current task, - /// If the task is cancelled and disposable. - self.continuation->resume(); - } - - template - std::coroutine_handle<> await_suspend(std::coroutine_handle waiting) noexcept { - continuation = &waiting.promise(); - this->request.data = static_cast(this); - - auto& self = *static_cast(this); - - /// Start the async operation. - error = self.start(callback); - - /// If the async operation fails, resume the coroutine immediately. - if(error < 0) { - return continuation->resume_handle(); - } - - /// Otherwise, return the coroutine handle to resume later. - return std::noop_coroutine(); - } - - std::expected await_resume() noexcept { - if(error < 0) { - return std::unexpected(std::error_code(error, category())); - } - - if constexpr(!std::is_void_v) { - return static_cast(this)->result(); - } else { - return std::expected(); - } - } -}; - -} // namespace clice::async::awaiter diff --git a/include/Async/Event.h b/include/Async/Event.h deleted file mode 100644 index e5fbf6d9..00000000 --- a/include/Async/Event.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include "Task.h" - -#include "llvm/ADT/ArrayRef.h" - -namespace clice::async { - -namespace awaiter { - -struct event { - bool ready; - llvm::SmallVectorImpl& awaiters; - - bool await_ready() const noexcept { - return ready; - } - - template - void await_suspend(std::coroutine_handle handle) const noexcept { - awaiters.emplace_back(&handle.promise()); - } - - void await_resume() const noexcept {} -}; - -} // namespace awaiter - -class Event { -public: - Event() = default; - - void set() { - ready = true; - for(auto* awaiter: awaiters) { - awaiter->schedule(); - } - } - - void clear() { - ready = false; - awaiters.clear(); - } - - auto operator co_await() { - return awaiter::event{ready, awaiters}; - } - -private: - bool ready = false; - llvm::SmallVector awaiters; -}; - -} // namespace clice::async diff --git a/include/Async/FileSystem.h b/include/Async/FileSystem.h deleted file mode 100644 index 318c3f45..00000000 --- a/include/Async/FileSystem.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -#include -#include - -#include "Awaiter.h" -#include "Task.h" -#include "libuv.h" -#include "Support/Enum.h" -#include "Support/JSON.h" - -#include "llvm/ADT/FunctionExtras.h" -#include "llvm/ADT/StringRef.h" - -namespace clice::async { - -namespace fs { - -struct Mode : refl::Enum { - enum Kind { - /// Open the file for reading. - Read = 0, - - /// Open the file for writing. - Write, - - /// Open the file for reading and writing. - ReadWrite, - - /// If the file does not exist, create it. - Create, - - /// If the file exists, append the data to the end of the file. - Append, - - /// If the file exists, truncate the file to zero length. - Truncate, - - /// If the file exists, fail the open. - Exclusive, - }; - - using Enum::Enum; -}; - -struct handle { -public: - handle(uv_file file) : file(file) {} - - handle(const handle&) = delete; - - handle(handle&& other) noexcept : file(other.file) { - other.file = -1; - } - - ~handle(); - - handle& operator=(const handle&) = delete; - - handle& operator=(handle&& other) noexcept = delete; - - int value() const { - return file; - } - -private: - uv_file file; -}; - -/// Open the file asynchronously. -Result open(std::string path, Mode mode); - -/// Read the file asynchronously, make sure the buffer is valid until the task is done. -Result read(const handle& handle, char* buffer, std::size_t size); - -Result read(std::string path, Mode mode = Mode::Read); - -/// Write the file asynchronously, make sure the buffer is valid until the task is done. -Result write(const handle& handle, char* buffer, std::size_t size); - -Result write(std::string path, - char* buffer, - std::size_t size, - Mode mode = Mode(Mode::Write, Mode::Create, Mode::Truncate)); - -struct Stats { - std::chrono::milliseconds mtime; - size_t size; -}; - -Result stat(std::string path); - -} // namespace fs - -} // namespace clice::async diff --git a/include/Async/Gather.h b/include/Async/Gather.h deleted file mode 100644 index f4117b3f..00000000 --- a/include/Async/Gather.h +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once - -#include -#include - -#include "Event.h" -#include "Task.h" - -namespace clice::async { - -struct none {}; - -template ::value_type> -using task_value_t = std::conditional_t, none, V>; - -template -auto gather(Tasks&&... tasks) -> Task...>> { - constexpr static std::size_t count = sizeof...(Tasks); - - Event event; - std::size_t finished = 0; - - auto run_task = [&](auto& task) -> Task> { - using V = typename std::remove_cvref_t::value_type; - if constexpr(std::is_void_v) { - co_await task; - /// Check if all tasks are finished. If so, set the event to - /// resume the gather handle. - finished += 1; - if(finished == count) { - event.set(); - } - co_return none{}; - } else { - auto result = co_await task; - finished += 1; - if(finished == count) { - event.set(); - } - co_return std::move(result); - } - }; - - auto schedule_task = [&](auto& task) { - auto core = run_task(task); - core.schedule(); - return core; - }; - - std::tuple all = {schedule_task(tasks)...}; - - /// Wait for all tasks to finish. - co_await event; - - /// Return the results of all tasks. - co_return [&](std::index_sequence) { - return std::make_tuple(std::get(all).result()...); - }(std::make_index_sequence{}); -} - -/// Run the tasks in parallel and return the results. -template -auto run(Tasks&&... tasks) { - auto core = gather(std::forward(tasks)...); - core.schedule(); - async::run(); - assert(core.done() && "run: not done"); - return core.result(); -} - -template - requires requires(Coroutine coroutine, ranges::range_value_t value) { - { coroutine(value) } -> std::same_as>; - } -Task gather(Range&& range, - Coroutine&& coroutine, - std::size_t concurrency = std::thread::hardware_concurrency()) { - std::vector> tasks; - tasks.reserve(concurrency); - - auto iter = ranges::begin(range); - auto end = ranges::end(range); - - Event event; - std::size_t finished = 0; - bool cancelled = false; - - auto run_task = [&](auto& value) -> async::Task<> { - /// Execute the first task. - auto task = coroutine(value); - - /// If any task fails, cancel all tasks and return false. - if(auto result = co_await task; !result) { - for(auto& task: tasks) { - task.cancel(); - task.dispose(); - } - cancelled = true; - event.set(); - co_return; - } - - finished += 1; - - /// Check if still have tasks to run. If so, run the next task. - while(iter != end) { - auto task = coroutine(*iter); - iter++; - finished -= 1; - - if(auto result = co_await task; !result) { - for(auto& task: tasks) { - task.cancel(); - task.dispose(); - } - cancelled = true; - event.set(); - co_return; - } - - finished += 1; - } - - /// Check if all tasks are finished. If so, set the event to - /// resume the gather handle. - if(finished == tasks.size()) { - event.set(); - } - }; - - /// Fill tasks. - while(iter != end && tasks.size() < concurrency) { - tasks.emplace_back(run_task(*iter)); - tasks.back().schedule(); - iter++; - } - - co_await event; - - co_return !cancelled; -} - -} // namespace clice::async diff --git a/include/Async/Lock.h b/include/Async/Lock.h deleted file mode 100644 index 67ad9f99..00000000 --- a/include/Async/Lock.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include "Event.h" - -namespace clice::async { - -namespace awaiter { - -struct lock { - llvm::SmallVectorImpl& awaiters; - - bool await_ready() const noexcept { - return false; - } - - template - void await_suspend(std::coroutine_handle handle) const noexcept { - awaiters.emplace_back(&handle.promise()); - } - - void await_resume() const noexcept {} -}; - -} // namespace awaiter - -class Lock { - friend class guard; - -public: - Lock() = default; - - class Guard { - public: - Guard(Lock* lock) : lock(lock) {} - - Guard(Guard&& other) : lock(other.lock) { - other.lock = nullptr; - } - - ~Guard() { - if(!lock) { - return; - } - - lock->locked = false; - if(!lock->awaiters.empty()) { - lock->awaiters.front()->schedule(); - lock->awaiters.erase(lock->awaiters.begin()); - } - } - - private: - Lock* lock; - }; - - /// Try to get the lock. If the lock is locked, the current coroutine will be - /// suspended and wait for the lock to be released. - Task try_lock() { - /// Note that this task also may be canceled, we make sure - /// even cancel, it can resume one task(through destructor). - Guard guard(this); - - if(locked) { - co_await awaiter::lock{awaiters}; - } - - locked = true; - - /// Use `std::move` to make sure it will not resume - /// the awaiter here. - co_return std::move(guard); - } - -private: - bool locked = false; - llvm::SmallVector awaiters; -}; - -} // namespace clice::async diff --git a/include/Async/Network.h b/include/Async/Network.h deleted file mode 100644 index b5dc2933..00000000 --- a/include/Async/Network.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "Task.h" -#include "libuv.h" -#include "Support/JSON.h" - -#include "llvm/ADT/FunctionExtras.h" -#include "llvm/ADT/StringRef.h" - -namespace clice::async::net { - -using Callback = llvm::unique_function(json::Value)>; - -/// Listen on stdin/stdout, callback is called when there is a LSP message available. -void listen(Callback callback); - -/// Listen on the given host and port, callback is called when there is a LSP message available. -void listen(const char* host, unsigned int port, Callback callback); - -/// Write a JSON value to the client. -Task<> write(json::Value value); - -} // namespace clice::async::net diff --git a/include/Async/Sleep.h b/include/Async/Sleep.h deleted file mode 100644 index 101bc643..00000000 --- a/include/Async/Sleep.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -#include "Awaiter.h" - -namespace clice::async { - -namespace awaiter { - -struct sleep : uv { - std::chrono::milliseconds duration; - - int start(auto callback) { - int err = uv_timer_init(async::loop, &request); - if(err < 0) { - return err; - } - return uv_timer_start(&request, callback, duration.count(), 0); - } - - void cleanup() { - error = uv_timer_stop(&request); - } -}; - -} // namespace awaiter - -inline auto sleep(std::chrono::milliseconds duration) { - return awaiter::sleep{{}, duration}; -} - -inline auto sleep(std::size_t milliseconds) { - return sleep(std::chrono::milliseconds(milliseconds)); -} - -}; // namespace clice::async diff --git a/include/Async/Task.h b/include/Async/Task.h deleted file mode 100644 index 78a4f88c..00000000 --- a/include/Async/Task.h +++ /dev/null @@ -1,334 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "Support/Format.h" - -namespace clice::async { - -template -class Task; - -struct promise_base { - enum Flags : uint8_t { - Empty = 0, - - /// The task is cancelled. - Cancelled = 1, - - /// The coroutine handle will be destroyed when the task is done or cancelled. - Disposable = 1 << 1, - - /// The coroutine is done or is cancelled and resumed, means it will never - /// scheduled again. - Finished = 1 << 2, - }; - - uint8_t flags; - - void* data; - - /// The coroutine handle that is waiting for the task to complete. - /// If this is a top-level coroutine, it is empty. - promise_base* continuation = nullptr; - - promise_base* next = nullptr; - - std::source_location location; - - template - void set(std::coroutine_handle handle) { - flags = Empty; - data = handle.address(); - } - - auto handle() const noexcept { - return std::coroutine_handle<>::from_address(data); - } - - void schedule(); - - bool done() const noexcept { - return handle().done(); - } - - void destroy() { - handle().destroy(); - } - - void cancel() { - auto p = this; - while(p) { - p->flags |= Flags::Cancelled; - p = p->next; - } - } - - bool cancelled() const noexcept { - return flags & Flags::Cancelled; - } - - void dispose() { - flags |= Flags::Disposable; - } - - bool disposable() const noexcept { - return flags & Flags::Disposable; - } - - void finish() { - flags |= Flags::Finished; - } - - bool finished() { - return flags & Flags::Finished; - } - - std::coroutine_handle<> resume_handle() { - if(cancelled()) { - /// If the task is cancelled and disposable, destroy the coroutine handle. - auto p = this; - while(p && p->cancelled()) { - auto con = p->continuation; - - if(p->disposable()) { - p->destroy(); - } else { - p->finish(); - } - - p = con; - } - - return std::noop_coroutine(); - } else { - /// Otherwise, resume the coroutine handle. - return handle(); - } - } - - void resume() { - resume_handle().resume(); - } -}; - -namespace awaiter { - -/// The awaiter for the final suspend point of `Task`. -struct final { - promise_base* continuation; - - bool await_ready() noexcept { - return false; - } - - template - std::coroutine_handle<> await_suspend(std::coroutine_handle current) noexcept { - std::coroutine_handle<> handle = std::noop_coroutine(); - - /// In the final suspend point, this coroutine is already done. - /// So try to resume the waiting coroutine if it exists. - if(continuation) { - continuation->next = nullptr; - handle = continuation->resume_handle(); - } - - /// Mark current coroutine as finished. - current.promise().finish(); - - if(current.promise().disposable()) { - /// If this task is disposable, destroy the coroutine handle. - current.destroy(); - } - - return handle; - } - - void await_resume() noexcept {} -}; - -/// The awaiter for the `Task` type. -template -struct task { - std::coroutine_handle

handle; - - bool await_ready() noexcept { - return false; - } - - template - auto await_suspend(std::coroutine_handle waiting) noexcept { - /// Store the waiting coroutine in the promise for later scheduling. - /// It will be scheduled in the final suspend point. - assert(!handle.promise().continuation && "await_suspend: already waiting"); - handle.promise().continuation = &waiting.promise(); - waiting.promise().next = &handle.promise(); - - /// If this `Task` is awaited from another coroutine, we should schedule - /// the this task first. - return handle.promise().resume_handle(); - } - - T await_resume() noexcept { - if constexpr(!std::is_void_v) { - assert(handle.promise().value.has_value() && "await_resume: value not set"); - return std::move(*handle.promise().value); - } - } -}; - -} // namespace awaiter - -template -class Task { -public: - template - struct promise_result { - std::optional value; - - template - void return_value(U&& val) noexcept { - assert(!value.has_value() && "return_value: value already set"); - value.emplace(std::forward(val)); - } - }; - - // WORKAROUND: GCC bug - full specialization in non-namespace scope not supported - // see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85282 - template V> - struct promise_result { - void return_void() noexcept {} - }; - - struct promise_type : promise_base, promise_result { - promise_type(std::source_location location = std::source_location::current()) { - set(handle()); - this->location = location; - }; - - auto get_return_object() { - return Task(handle()); - } - - auto initial_suspend() { - return std::suspend_always(); - } - - auto final_suspend() noexcept { - return awaiter::final{continuation}; - } - - void unhandled_exception() { - std::abort(); - } - - auto handle() { - return std::coroutine_handle::from_promise(*this); - } - }; - - using coroutine_handle = std::coroutine_handle; - - using value_type = T; - -public: - Task() = default; - - Task(coroutine_handle handle) : core(handle) {} - - Task(const Task&) = delete; - - Task(Task&& other) noexcept : core(other.core) { - other.core = nullptr; - } - - Task& operator=(const Task&) = delete; - - Task& operator=(Task&& other) noexcept { - if(core) { - core.destroy(); - } - core = other.core; - other.core = nullptr; - return *this; - } - - ~Task() { - if(core) { - core.destroy(); - } - } - -public: - coroutine_handle handle() const noexcept { - return core; - } - - coroutine_handle release() noexcept { - auto handle = core; - core = nullptr; - return handle; - } - - bool empty() const noexcept { - return !core; - } - - bool done() const noexcept { - return core.done(); - } - - void schedule() { - core.promise().schedule(); - } - - /// Cancel the task, the suspend point after the current one will be skipped. - void cancel() { - core.promise().cancel(); - } - - bool cancelled() { - return core.promise().cancelled(); - } - - /// Dispose the task, it will be destroyed when finished or cancelled. - void dispose() { - core.promise().dispose(); - core = nullptr; - } - - bool finished() { - return core.promise().finished(); - } - - T result() { - if constexpr(!std::is_void_v) { - return std::move(core.promise().value.value()); - } - } - - auto operator co_await() const noexcept { - return awaiter::task{core}; - } - - void stacktrace() { - promise_base* handle = core; - while(handle) { - std::println("{}:{}:{}", - handle->location.file_name(), - handle->location.line(), - handle->location.function_name()); - handle = handle->continuation; - } - } - -private: - coroutine_handle core; -}; - -} // namespace clice::async diff --git a/include/Async/ThreadPool.h b/include/Async/ThreadPool.h deleted file mode 100644 index 52d2f4db..00000000 --- a/include/Async/ThreadPool.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "Awaiter.h" - -namespace clice::async { - -namespace awaiter { - -template -struct value { - std::optional value; -}; - -template <> -struct value {}; - -template -struct thread_pool : value, uv, uv_work_t, Ret, int> { - Work work; - - /// `uv_work_t` has two callback functions, `work_cb` is executed in the thread pool, - /// and `after_work_cb` is executed in the main thread. - static void work_cb(uv_work_t* work) { - auto& awaiter = uv_cast(work); - if constexpr(!std::is_void_v) { - awaiter.value.emplace(awaiter.work()); - } else { - awaiter.work(); - } - } - - int start(auto callback) { - return uv_queue_work(async::loop, &this->request, work_cb, callback); - } - - void cleanup(int status) { - this->error = status; - } - - Ret result() { - if constexpr(!std::is_void_v) { - return std::move(*this->value); - } - } -}; - -} // namespace awaiter - -template > -async::Task submit(Work&& work) { - using W = std::remove_cvref_t; - auto result = co_await awaiter::thread_pool{{}, {}, std::forward(work)}; - if(!result) { - /// Thread pool task should never fails. - std::abort(); - } - co_return std::move(*result); -} - -} // namespace clice::async diff --git a/include/Async/libuv.h b/include/Async/libuv.h deleted file mode 100644 index 02746a8f..00000000 --- a/include/Async/libuv.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#ifdef _WIN32 -#define NOMINMAX -#endif - -#include "uv.h" - -#ifdef _WIN32 -#undef THIS -#endif - -#include -#include -#include -#include - -#include "Support/Logging.h" -#include "Support/TypeTraits.h" - -namespace clice::async { - -/// The default event loop. -extern uv_loop_t* loop; - -template -T& uv_cast(U* u) { - assert(u && u->data && "uv_cast: invalid uv handle"); - return *static_cast*>(u->data); -} - -#define UV_TYPE_ITER(_, name) || std::is_same_v - -/// Check if the type `T` is a libuv handle. -template -constexpr bool is_uv_handle_v = false UV_HANDLE_TYPE_MAP(UV_TYPE_ITER); - -/// Check if the type `T` is a libuv request. -template -constexpr bool is_uv_req_v = false UV_REQ_TYPE_MAP(UV_TYPE_ITER); - -template -constexpr bool is_uv_stream_v = std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v; - -#undef UV_TYPE_ITER - -template -T* uv_cast(U& u) { - if constexpr(std::is_same_v) { - static_assert(is_uv_handle_v>, "uv_cast: invalid uv handle"); - } else if constexpr(std::is_same_v) { - static_assert(is_uv_req_v>, "uv_cast: invalid uv request"); - } else if constexpr(std::is_same_v) { - static_assert(is_uv_stream_v>, "uv_cast: invalid uv stream"); - } else { - static_assert(dependent_false, "uv_cast: invalid type"); - } - return reinterpret_cast(&u); -} - -void uv_check_result(const int result, - const std::source_location location = std::source_location::current()); - -template -class Task; - -template -using Result = Task>; - -const std::error_category& category(); - -void init(); - -void run(); - -void stop(); - -} // namespace clice::async diff --git a/include/Compiler/Scan.h b/include/Compiler/Scan.h deleted file mode 100644 index 10b2dcbf..00000000 --- a/include/Compiler/Scan.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include - -#include "AST/SourceCode.h" - -#include "llvm/ADT/StringRef.h" - -namespace clice { - -struct Inclusion { - /// Whether this file is braced angles. - bool angled; - - /// The line of this inclusion(zero based). - /// std::uint32_t line; - - /// The included file. - llvm::StringRef file; -}; - -struct ScanResult { - /// The module file of this file(may be empty). - std::vector module_name; - - /// The includes of file. - std::vector includes; -}; - -/// Scan the file and return necessary info. -ScanResult scan(llvm::StringRef content); - -} // namespace clice diff --git a/include/Feature/CodeAction.h b/include/Feature/CodeAction.h deleted file mode 100644 index 6f70f09b..00000000 --- a/include/Feature/CodeAction.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/include/Feature/CodeCompletion.h b/include/Feature/CodeCompletion.h deleted file mode 100644 index 54ff65e9..00000000 --- a/include/Feature/CodeCompletion.h +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -#include -#include - -#include "AST/SourceCode.h" - -#include "llvm/ADT/StringRef.h" - -namespace clice { - -struct CompilationParams; - -namespace config { - -struct CodeCompletionOption { - /// Insert placeholder for keywords? function call parameters? template arguments? - bool enable_keyword_snippet = false; - - /// Also apply for lambda ... - bool enable_function_arguments_snippet = false; - bool enable_template_arguments_snippet = false; - - bool insert_paren_in_function_call = false; - /// TODO: Add more detailed option, see - /// https://github.com/llvm/llvm-project/issues/63565 - - bool bundle_overloads = true; - - /// The limits of code completion, 0 is non limit. - std::uint32_t limit = 0; -}; - -}; // namespace config - -namespace feature { - -enum class CompletionItemKind { - None = 0, - Text, - Method, - Function, - Constructor, - Field, - Variable, - Class, - Interface, - Module, - Property, - Unit, - Value, - Enum, - Keyword, - Snippet, - Color, - File, - Reference, - Folder, - EnumMember, - Constant, - Struct, - Event, - Operator, - TypeParameter -}; - -/// Represents a single code completion item to be presented to the user. -struct CompletionItem { - /// The primary label displayed in the completion list. - std::string label; - - /// Additional details, like a function signature, shown next to the label. - std::string detail; - - /// A short description of the item, typically its type or namespace. - std::string description; - - /// Full documentation for the item, shown on selection or hover. - std::string document; - - /// The kind of item (function, class, etc.), used for an icon. - CompletionItemKind kind; - - /// A score for ranking this item against others. Higher is better. - float score; - - /// Whether this item is deprecated (often rendered with a strikethrough). - bool deprecated; - - /// The text edit to be applied when this item is accepted. - struct Edit { - /// The new text to insert, which may be a snippet. - std::string text; - - /// The source range to be replaced by the new text. - LocalSourceRange range; - } edit; -}; - -using CodeCompletionResult = std::vector; - -std::vector code_complete(CompilationParams& params, - const config::CodeCompletionOption& option); - -} // namespace feature - -} // namespace clice diff --git a/include/Feature/CodeLens.h b/include/Feature/CodeLens.h deleted file mode 100644 index 6f70f09b..00000000 --- a/include/Feature/CodeLens.h +++ /dev/null @@ -1 +0,0 @@ -#pragma once diff --git a/include/Feature/Diagnostic.h b/include/Feature/Diagnostic.h deleted file mode 100644 index e1c278c8..00000000 --- a/include/Feature/Diagnostic.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "Compiler/Diagnostic.h" -#include "Server/Convert.h" -#include "Support/JSON.h" - -namespace clice { - -class CompilationUnitRef; - -} - -namespace clice::feature { - -/// FIXME: This is not correct way, we don't want to couple -/// `Feature with Protocol`? Return an array of LSP diagnostic. -json::Value diagnostics(PositionEncodingKind kind, PathMapping mapping, CompilationUnitRef unit); - -} // namespace clice::feature diff --git a/include/Feature/DocumentHighlight.h b/include/Feature/DocumentHighlight.h deleted file mode 100644 index 2d863e71..00000000 --- a/include/Feature/DocumentHighlight.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -namespace clice::proto {} diff --git a/include/Feature/DocumentLink.h b/include/Feature/DocumentLink.h deleted file mode 100644 index f0901e8b..00000000 --- a/include/Feature/DocumentLink.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -#include "AST/SourceCode.h" -#include "Index/Shared.h" - -namespace clice::feature { - -struct DocumentLink { - /// The range of the whole link. - LocalSourceRange range; - - /// The target string path. - std::string file; -}; - -using DocumentLinks = std::vector; - -/// Generate document link for main file. -DocumentLinks document_links(CompilationUnitRef unit); - -/// Generate document link for all source file. -index::Shared index_document_link(CompilationUnitRef unit); - -} // namespace clice::feature diff --git a/include/Feature/DocumentSymbol.h b/include/Feature/DocumentSymbol.h deleted file mode 100644 index f91f043c..00000000 --- a/include/Feature/DocumentSymbol.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "AST/SourceCode.h" -#include "AST/SymbolKind.h" -#include "Index/Shared.h" - -namespace clice::feature { - -struct DocumentSymbol { - /// The range of symbol name in source code. - LocalSourceRange selectionRange; - - /// The range of whole symbol. - LocalSourceRange range; - - /// The symbol kind of this document symbol. - SymbolKind kind; - - /// The symbol name. - std::string name; - - /// Extra information about this symbol. - std::string detail; - - /// The symbols that this symbol contains - std::vector children; -}; - -using DocumentSymbols = std::vector; - -/// Generate document symbols for only interested file. -DocumentSymbols document_symbols(CompilationUnitRef unit); - -/// Generate document symbols for all file in unit. -index::Shared index_document_symbol(CompilationUnitRef unit); - -} // namespace clice::feature diff --git a/include/Feature/FoldingRange.h b/include/Feature/FoldingRange.h deleted file mode 100644 index 8986a48b..00000000 --- a/include/Feature/FoldingRange.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "AST/SourceCode.h" -#include "Index/Shared.h" -#include "Support/Enum.h" - -namespace clice::feature { - -struct FoldingRangeKind : refl::Enum { - enum Kind : uint8_t { - Invalid = 0, - Comment, - Imports, - Region, - Namespace, - Class, - Enum, - Struct, - Union, - LambdaCapture, - FunctionParams, - FunctionBody, - FunctionCall, - CompoundStmt, - AccessSpecifier, - ConditionDirective, - Initializer, - }; - - using Enum::Enum; - - constexpr static auto InvalidEnum = Invalid; -}; - -/// We don't record the coalesced text for a range, because it's rarely useful. -struct FoldingRange { - /// The range to fold. - LocalSourceRange range; - - /// Describes the kind of the folding range. - FoldingRangeKind kind; - - /// The text to display when the folding range is collapsed. - std::string text; -}; - -using FoldingRanges = std::vector; - -/// Generate folding range for interested file only. -FoldingRanges folding_ranges(CompilationUnitRef unit); - -/// Generate folding range for all files. -index::Shared index_folding_range(CompilationUnitRef unit); - -} // namespace clice::feature diff --git a/include/Feature/Formatting.h b/include/Feature/Formatting.h deleted file mode 100644 index 32cef9ef..00000000 --- a/include/Feature/Formatting.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "AST/SourceCode.h" -#include "Protocol/Feature/Formatting.h" - -#include "llvm/ADT/StringRef.h" - -namespace clice::feature { - -std::vector document_format(llvm::StringRef file, - llvm::StringRef content, - std::optional); - -} diff --git a/include/Feature/Hover.h b/include/Feature/Hover.h deleted file mode 100644 index d7670964..00000000 --- a/include/Feature/Hover.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "AST/SourceCode.h" -#include "AST/SymbolKind.h" -#include "Index/Shared.h" - -namespace clice::config { - -struct HoverOptions { - /// Strip doxygen info and merge with lsp info - bool enable_doxygen_parsing = true; - /// If set `false`, the comment will be wrapped - /// in code block and keep ascii typesetting - bool parse_comment_as_markdown = true; - /// Show sugar type - bool show_aka = true; -}; - -} // namespace clice::config - -namespace clice::feature { - -struct HoverItem { - enum class HoverKind : uint8_t { - /// The typename of a variable or a type alias. - Type, - /// Size of type or variable. - Size, - /// Align of type or variable. - Align, - /// Offset of field in a class/struct. - Offset, - /// Bit width of a bit field. - BitWidth, - /// The index of a field in a class/struct. - FieldIndex, - /// The value of an enum item. - EnumValue, - }; - - using enum HoverKind; - - HoverKind kind; - - std::string value; -}; - -/// Hover information for a symbol. -struct Hover { - /// Title - SymbolKind kind; - - std::string name; - - /// Extra information. - std::vector items; - - /// Raw document in the source code. - std::string document; - - /// The full qualified name of the declaration. - std::string qualifier; - - /// The source code of the declaration. - std::string source; -}; - -/// Generate the hover information for the given declaration(for test). -Hover hover(CompilationUnitRef unit, const clang::NamedDecl* decl); - -/// Generate the hover information for the symbol at the given offset. -Hover hover(CompilationUnitRef unit, std::uint32_t offset); - -} // namespace clice::feature diff --git a/include/Feature/InlayHint.h b/include/Feature/InlayHint.h deleted file mode 100644 index a6b2013e..00000000 --- a/include/Feature/InlayHint.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "AST/SourceCode.h" -#include "AST/SymbolID.h" -#include "Index/Shared.h" -#include "Support/JSON.h" - -namespace clice::config { - -struct InlayHintsOptions { - /// If false, inlay hints are completely disabled. - bool enabled = true; - - // Whether specific categories of hints are enabled. - bool parameters = true; - bool deduced_types = true; - bool designators = true; - bool block_end = false; - bool default_arguments = false; - - // Limit the length of type names in inlay hints. (0 means no limit) - uint32_t type_name_limit = 32; -}; - -} // namespace clice::config - -namespace clice::feature { - -enum class InlayHintKind { - Parameter, - InvalidEnum, - DefaultArgument, - Type, - Designator, - BlockEnd, -}; - -struct InlayHint { - /// The position offset of the inlay hint in the source code. - std::uint32_t offset; - - /// The kind/category of the inlay hint. - InlayHintKind kind; - - /// The label parts of the inlay hint. - /// Each SymbolID consists of two parts: the symbol name and its USR hash. - /// For symbols without a USR (e.g., built-in types or function parameters), - /// the symbol hash will be empty. - /// Otherwise, the symbol hash is non-empty and can be used for "go-to-definition". - std::vector parts; -}; - -auto inlay_hints(CompilationUnitRef unit, - LocalSourceRange target, - const config::InlayHintsOptions& options) -> std::vector; - -} // namespace clice::feature diff --git a/include/Feature/Lookup.h b/include/Feature/Lookup.h deleted file mode 100644 index 8ad88da1..00000000 --- a/include/Feature/Lookup.h +++ /dev/null @@ -1,85 +0,0 @@ -#pragma once - -#include "AST/SymbolKind.h" -#include "Server/Protocol.h" -#include "Support/Struct.h" - -namespace clice::proto { - -struct WorkDoneProgressOptions { - /// Report on work done progress. - bool workDoneProgress = false; -}; - -struct PartialResultParams {}; - -/// The options of the all lookup. -using LookupOptions = WorkDoneProgressOptions; - -/// The parameters of the simple lookup(definition, declaration, -/// type definition, implementation and reference). -inherited_struct(ReferenceParams, TextDocumentPositionParams, PartialResultParams){}; - -/// The result of the simple lookup. -using ReferenceResult = std::vector; - -/// The parameters of the all hierarchy resolve(call hierarchy and type hierarchy) -using HierarchyPrepareParams = TextDocumentPositionParams; - -struct HierarchyItem { - /// The name of the item. - string name; - - /// The kind of the item. - SymbolKind kind; - - /// The resource identifier of this item. - DocumentUri uri; - - /// The range enclosing this symbol not including leading/trailing whitespace - /// but everything else, e.g. comments and code. - Range range; - - /// The range that should be selected and revealed when this symbol is being - /// picked, e.g. the name of a function. Must be contained by the - /// [`range`](#CallHierarchyItem.range). - Range selectionRange; - - /// A customized data of the item. We use it to store - /// the USR hash of the item. - uint64_t data = 0; -}; - -using HierarchyPrepareResult = std::vector; - -/// The parameters of the both call hierarchy and type hierarchy. -inherited_struct(HierarchyParams, TextDocumentPositionParams, PartialResultParams) { - HierarchyItem item; -}; - -struct CallHierarchyIncomingCall { - /// The item that makes the call. - HierarchyItem from; - - /// The ranges at which the calls appear. This is relative to the caller - /// denoted by [`this.from`](#CallHierarchyIncomingCall.from). - std::vector fromRanges; -}; - -using CallHierarchyIncomingCallsResult = std::vector; - -struct CallHierarchyOutgoingCall { - /// The item that is called. - HierarchyItem to; - - /// The range at which this item is called. This is the range relative to - /// the caller, e.g the item passed to `callHierarchy/outgoingCalls` request. - std::vector fromRanges; -}; - -using CallHierarchyOutgoingCallsResult = std::vector; - -/// The result of the both super and sub type hierarchy. -using TypeHierarchyResult = std::vector; - -} // namespace clice::proto diff --git a/include/Feature/SemanticToken.h b/include/Feature/SemanticToken.h deleted file mode 100644 index 5e2ecb23..00000000 --- a/include/Feature/SemanticToken.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "AST/SourceCode.h" -#include "AST/SymbolKind.h" -#include "Index/Shared.h" - -namespace clice::config { - -struct SemanticTokensOption {}; - -}; // namespace clice::config - -namespace clice::feature { - -struct SemanticToken { - LocalSourceRange range; - SymbolKind kind; - SymbolModifiers modifiers; -}; - -using SemanticTokens = std::vector; - -/// Generate semantic tokens for the interested file only. -SemanticTokens semantic_tokens(CompilationUnitRef unit); - -/// Generate semantic tokens for all files. -index::Shared index_semantic_token(CompilationUnitRef unit); - -} // namespace clice::feature diff --git a/include/Feature/SignatureHelp.h b/include/Feature/SignatureHelp.h deleted file mode 100644 index 8e8aa882..00000000 --- a/include/Feature/SignatureHelp.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include -#include - -#include "Protocol/Feature/SignatureHelp.h" - -#include "llvm/ADT/StringRef.h" - -namespace clice { - -struct CompilationParams; - -namespace config { - -struct SignatureHelpOption {}; - -} // namespace config - -namespace feature { - -proto::SignatureHelp signature_help(CompilationParams& params, - const config::SignatureHelpOption& option); - -} // namespace feature - -} // namespace clice diff --git a/include/Protocol/Basic.h b/include/Protocol/Basic.h deleted file mode 100644 index c0ee8ffa..00000000 --- a/include/Protocol/Basic.h +++ /dev/null @@ -1,135 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace clice::proto { - -using integer = std::int32_t; -/// range in [0, 2^31- 1] -using uinteger = std::uint32_t; -using decimal = double; - -using string = std::string; - -template -using array = std::vector; - -template -using optional = std::optional; - -using PositionEncodingKind = string; - -struct WorkDoneProgressOptions { - bool workDoneProgress; -}; - -using URI = string; -using DocumentUri = string; - -enum class ErrorCodes : integer { - /// Defined by JSON-RPC. - ParseError = -32700, - InvalidRequest = -32600, - MethodNotFound = -32601, - InvalidParams = -32602, - InternalError = -32603, - /// JSON-RPC error code indicating a server error. - serverErrorStart = -32099, - serverErrorEnd = -32000, - ServerNotInitialized = -32002, - UnknownErrorCode = -32001, - - /// Defined by the protocol. - RequestFailed = -32803, - ServerCancelled = -32802, - ContentModified = -32801, - RequestCancelled = -32800 -}; - -struct Position { - /// Line position in a document (zero-based). - uinteger line; - - /// Character offset on a line in a document (zero-based). - /// The meaning of this offset is determined by the negotiated - /// `PositionEncodingKind`. - uinteger character; - - constexpr friend bool operator==(const Position&, const Position&) = default; -}; - -struct Range { - /// The range's start position. - Position start; - - /// The range's end position. - Position end; - - constexpr friend bool operator==(const Range&, const Range&) = default; -}; - -struct Location { - DocumentUri uri; - - Range range; -}; - -struct TextEdit { - /// The range of the text document to be manipulated. To insert - /// text into a document create a range where start === end. - Range range; - - // The string to be inserted. For delete operations use an - // empty string. - string newText; -}; - -struct TextDocumentItem { - /// The text document's URI. - DocumentUri uri; - - /// The text document's language identifier. - string languageId; - - /// The version number of this document (it will strictly increase after each - /// change, including undo/redo). - uinteger version; - - /// The content of the opened text document. - string text; -}; - -struct TextDocumentIdentifier { - /// The text document's URI. - DocumentUri uri; -}; - -struct VersionedTextDocumentIdentifier { - /// The text document's URI. - DocumentUri uri; - - /// The version of document. - integer version; -}; - -struct TextDocumentPositionParams { - /// The text document. - TextDocumentIdentifier textDocument; - - /// The position inside the text document. - Position position; -}; - -struct MarkupContent { - /// The type of the Markup. - string kind; - - /// The content itself. - string value; -}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/CallHierarchy.h b/include/Protocol/Feature/CallHierarchy.h deleted file mode 100644 index 95a24d8e..00000000 --- a/include/Protocol/Feature/CallHierarchy.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct CallHierarchyClientCapabilities {}; - -using CallHierarchyOptions = WorkDoneProgressOptions; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/CodeAction.h b/include/Protocol/Feature/CodeAction.h deleted file mode 100644 index ddb70555..00000000 --- a/include/Protocol/Feature/CodeAction.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct CodeActionClientCapabilities {}; - -struct CodeActionOptions {}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/CodeCompletion.h b/include/Protocol/Feature/CodeCompletion.h deleted file mode 100644 index 2c7be90f..00000000 --- a/include/Protocol/Feature/CodeCompletion.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct CompletionClientCapabilities {}; - -struct CompletionOptions { - /// The additional characters, beyond the defaults provided by the client (typically - /// [a-zA-Z]), that should automatically trigger a completion request. For example - ///`.` in JavaScript represents the beginning of an object property or method and is - /// thus a good candidate for triggering a completion request. - // - /// Most tools trigger a completion request automatically without explicitly - /// requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they - /// do so when the user starts to type an identifier. For example if the user - /// types `c` in a JavaScript file code complete will automatically pop up - /// present `console` besides others as a completion item. Characters that - /// make up identifiers don't need to be listed here. - array triggerCharacters; - - /// The server provides support to resolve additional information for a completion item. - bool resolveProvider; - - struct CompletionItemCapabilities { - /// The server has support for completion item label - /// details (see also `CompletionItemLabelDetails`) when receiving - /// a completion item in a resolve call. - bool labelDetailsSupport; - }; - - /// The server supports the following `CompletionItem` specific capabilities. - CompletionItemCapabilities completionItem; -}; - -using CompletionParams = TextDocumentPositionParams; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/CodeLens.h b/include/Protocol/Feature/CodeLens.h deleted file mode 100644 index 12a1a0e9..00000000 --- a/include/Protocol/Feature/CodeLens.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct CodeLensClientCapabilities {}; - -struct CodeLensOptions {}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/Declaration.h b/include/Protocol/Feature/Declaration.h deleted file mode 100644 index 31b95cf5..00000000 --- a/include/Protocol/Feature/Declaration.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct DeclarationClientCapabilities {}; - -using DeclarationOptions = WorkDoneProgressOptions; - -using DeclarationParams = TextDocumentPositionParams; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/Definition.h b/include/Protocol/Feature/Definition.h deleted file mode 100644 index 86d97366..00000000 --- a/include/Protocol/Feature/Definition.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct DefinitionClientCapabilities {}; - -using DefinitionOptions = WorkDoneProgressOptions; - -using DefinitionParams = TextDocumentPositionParams; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/Diagnostic.h b/include/Protocol/Feature/Diagnostic.h deleted file mode 100644 index 1501409d..00000000 --- a/include/Protocol/Feature/Diagnostic.h +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct PublishDiagnosticsClientCapabilities {}; - -struct DiagnosticClientCapabilities {}; - -enum class DiagnosticSeverity : std::uint8_t { - /// Reports an error. - Error = 1, - - /// Reports a warning. - Warning = 2, - - /// Reports an information. - Information = 3, - - /// Reports a hint. - Hint = 4, -}; - -enum class DiagnosticTag : std::uint8_t { - /// Unused or unnecessary code. Clients are allowed to render diagnostics - /// with this tag faded out instead of having an error squiggle. - Unnecessary = 1, - - /// Deprecated or obsolete code. Clients are allowed to rendered - /// diagnostics with this tag strike through. - Deprecated = 2, -}; - -struct CodeDescription { - /// An URI to open with more information about the diagnostic error. - URI uri; -}; - -/// Represents a related message and source code location for a diagnostic. -/// This should be used to point to code locations that cause or are related to -/// a diagnostics, e.g when duplicating a symbol in a scope. -struct DiagnosticRelatedInformation { - /// The location of this related diagnostic information. - Location location; - - /// The message of this related diagnostic information. - string message; -}; - -struct Diagnostic { - /// The range at which the message applies. - Range range; - - /// The diagnostic's severity. To avoid interpretation mismatches when a - /// server is used with different clients it is highly recommended that - /// servers always provide a severity value. If omitted, it’s recommended - /// for the client to interpret it as an Error severity. - DiagnosticSeverity severity; - - /// The diagnostic's code, which might appear in the user interface. - string code; - - /// An optional property to describe the error code. - optional codeDescription; - - /// A human-readable string describing the source of this - /// diagnostic, e.g. 'typescript' or 'super lint'. - string source; - - /// The diagnostic's message. - string message; - - /// Additional metadata about the diagnostic. - array tags; - - /// An array of related diagnostic information, e.g. when symbol-names within - /// a scope collide all definitions can be marked via this property. - array relatedInformation; -}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/DocumentHighlight.h b/include/Protocol/Feature/DocumentHighlight.h deleted file mode 100644 index dff17e97..00000000 --- a/include/Protocol/Feature/DocumentHighlight.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct DocumentHighlightClientCapabilities {}; - -using DocumentHighlightOptions = bool; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/DocumentLink.h b/include/Protocol/Feature/DocumentLink.h deleted file mode 100644 index d9ab2534..00000000 --- a/include/Protocol/Feature/DocumentLink.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct DocumentLinkClientCapabilities { - /// Whether the client supports the `tooltip` property on `DocumentLink`. - bool tooltipSupport = false; -}; - -struct DocumentLinkOptions { - /// Document links have a resolve provider as well. - bool resolveProvider; -}; - -struct DocumentLinkParams { - /// The document to provide document links for. - TextDocumentIdentifier textDocument; -}; - -/// A document link is a range in a text document that links to an internal or -/// external resource, like another text document or a web site. -struct DocumentLink { - /// The range this link applies to. - Range range; - - /// The uri this link points to. If missing a resolve request is sent later. - URI target; - - /// The tooltip text when you hover over this link. - /// - /// If a tooltip is provided, is will be displayed in a string that includes - /// instructions on how to trigger the link, such as `{0} (ctrl + click)`. - /// The specific instructions vary depending on OS, user settings, and - /// localization. - /// FIXME: string tooltip; -}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/DocumentSymbol.h b/include/Protocol/Feature/DocumentSymbol.h deleted file mode 100644 index 34ffcf70..00000000 --- a/include/Protocol/Feature/DocumentSymbol.h +++ /dev/null @@ -1,112 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -enum class SymbolKind : std::uint8_t { - File = 1, - Module = 2, - Namespace = 3, - Package = 4, - Class = 5, - Method = 6, - Property = 7, - Field = 8, - Constructor = 9, - Enum = 10, - Interface = 11, - Function = 12, - Variable = 13, - Constant = 14, - String = 15, - Number = 16, - Boolean = 17, - Array = 18, - Object = 19, - Key = 20, - Null = 21, - EnumMember = 22, - Struct = 23, - Event = 24, - Operator = 25, - TypeParameter = 26, -}; - -enum class SymbolTag { - /// Render a symbol as obsolete, usually using a strike-out. - Deprecated = 1, -}; - -struct DocumentSymbolClientCapabilities { - /// Specific capabilities for the `SymbolKind` in the - /// `textDocument/documentSymbol` request. - struct { - /// The symbol kind values the client supports. When this - /// property exists the client also guarantees that it will - /// handle values outside its set gracefully and falls back - /// to a default value when unknown. - // - /// If this property is not present the client only supports - /// the symbol kinds from `File` to `Array` as defined in - /// the initial version of the protocol. - array valueSet; - } symbolKind; - - /// The client supports hierarchical document symbols. - bool hierarchicalDocumentSymbolSupport; - - /// The client supports tags on `SymbolInformation`. Tags are supported on - /// `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. - /// Clients supporting tags have to handle unknown tags gracefully. - struct { - /// The tags supported by the client. - array valueSet; - } tagSupport; - - /// The client supports an additional label presented in the UI when - /// registering a document symbol provider. - bool labelSupport; -}; - -struct DocumentSymbolOptions {}; - -struct DocumentSymbolParams { - /// The text document. - TextDocumentIdentifier textDocument; -}; - -/// Represents programming constructs like variables, classes, interfaces etc. -/// that appear in a document. Document symbols can be hierarchical and they -/// have two ranges: one that encloses its definition and one that points to its -/// most interesting range, e.g. the range of an identifier. -struct DocumentSymbol { - /// The name of this symbol. Will be displayed in the user interface and - /// therefore must not be an empty string or a string only consisting of - /// white spaces. - string name; - - /// More detail for this symbol, e.g the signature of a function. - string detail; - - /// The kind of this symbol. - SymbolKind kind; - - /// Tags for this document symbol. - array tags; - - /// The range enclosing this symbol not including leading/trailing whitespace - /// but everything else like comments. This information is typically used to - /// determine if the clients cursor is inside the symbol to reveal it in the - /// UI. - Range range; - - /// The range that should be selected and revealed when this symbol is being - /// picked, e.g. the name of a function. Must be contained by the `range`. - Range selectionRange; - - /// Children of this symbol, e.g. properties of a class. - array children; -}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/FoldingRange.h b/include/Protocol/Feature/FoldingRange.h deleted file mode 100644 index 61581a3d..00000000 --- a/include/Protocol/Feature/FoldingRange.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct FoldingRangeClientCapabilities { - /// The maximum number of folding ranges that the client prefers to receive - /// per document. The value serves as a hint, servers are free to follow the - /// limit. - optional rangeLimit; - - /// If set, the client signals that it only supports folding complete lines. - /// If set, client will ignore specified `startCharacter` and `endCharacter` - /// properties in a FoldingRange. - bool lineFoldingOnly = false; - - /// Specific options for the folding range kind. - struct { - /// The folding range kind values the client supports. When this - /// property exists the client also guarantees that it will - /// handle values outside its set gracefully and falls back - /// to a default value when unknown. - array valueSet; - } foldingRangeKind; - - /// Specific options for the folding range. - struct { - /// If set, the client signals that it supports setting collapsedText on - /// folding ranges to display custom labels instead of the default text. - bool collapsedText = false; - } foldingRange; -}; - -using FoldingRangeOptions = bool; - -struct FoldingRangeParams { - /// The text document. - TextDocumentIdentifier textDocument; -}; - -using FoldingRangeKind = string; - -struct FoldingRange { - /// The zero-based start line of the range to fold. The folded area starts - /// after the line's last character. To be valid, the end must be zero or - /// larger and smaller than the number of lines in the document. - uinteger startLine; - - /// The zero-based character offset from where the folded range starts. If - /// not defined, defaults to the length of the start line. - uinteger startCharacter; - - /// The zero-based end line of the range to fold. The folded area ends with - /// the line's last character. To be valid, the end must be zero or larger - /// and smaller than the number of lines in the document. - uinteger endLine; - - /// The zero-based character offset before the folded range ends. If not - /// defined, defaults to the length of the end line. - uinteger endCharacter; - - /// Describes the kind of the folding range such as `comment` or `region`. - /// The kind is used to categorize folding ranges and used by commands like - /// 'Fold all comments'. See [FoldingRangeKind](#FoldingRangeKind) for an - /// enumeration of standardized kinds. - FoldingRangeKind kind; - - /// The text that the client should show when the specified range is - /// collapsed. If not defined or not supported by the client, a default - /// will be chosen by the client. - string collapsedText; -}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/Formatting.h b/include/Protocol/Feature/Formatting.h deleted file mode 100644 index f0168ee8..00000000 --- a/include/Protocol/Feature/Formatting.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct DocumentFormattingClientCapabilities {}; - -using DocumentFormattingOptions = bool; - -struct DocumentFormattingParams { - /// The document to format. - TextDocumentIdentifier textDocument; -}; - -struct DocumentRangeFormattingParams { - /// The document to format. - TextDocumentIdentifier textDocument; - - /// The range to format - Range range; -}; - -struct DocumentRangeFormattingClientCapabilities {}; - -using DocumentRangeFormattingOptions = bool; - -struct DocumentOnTypeFormattingClientCapabilities {}; - -struct DocumentOnTypeFormattingOptions {}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/Hover.h b/include/Protocol/Feature/Hover.h deleted file mode 100644 index c722be1c..00000000 --- a/include/Protocol/Feature/Hover.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct HoverClientCapabilities {}; - -using HoverOptions = bool; - -using HoverParams = TextDocumentPositionParams; - -struct Hover { - /// The hover's content - MarkupContent contents; - - /// An optional range is a range inside a text document - /// that is used to visualize a hover, e.g. by changing the background color. - /// FIXME: Range range; -}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/Implementation.h b/include/Protocol/Feature/Implementation.h deleted file mode 100644 index fd1308e2..00000000 --- a/include/Protocol/Feature/Implementation.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct ImplementationClientCapabilities {}; - -using ImplementationOptions = WorkDoneProgressOptions; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/InlayHint.h b/include/Protocol/Feature/InlayHint.h deleted file mode 100644 index ba3e4e20..00000000 --- a/include/Protocol/Feature/InlayHint.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct InlayHintClientCapabilities { - /// Indicates which properties a client can resolve lazily on an inlay hint. - struct { - /// The properties that a client can resolve lazily. - array properties; - } resolveSupport; -}; - -struct InlayHintOptions { - /// The server provides support to resolve additional - /// information for an inlay hint item. - bool resolveProvider; -}; - -struct InlayHintParams { - /// The text document. - TextDocumentIdentifier textDocument; - - /// The visible document range for which inlay hints should be computed. - Range range; -}; - -enum class InlayHintKind { - /// An inlay hint that for a type annotation. - Type = 1, - - /// An inlay hint that is for a parameter. - Parameter = 2, -}; - -struct InlayHintLabelPart { - /// The value of this label part. - string value; - - /// An optional source code location that represents this - /// label part. - /// - /// The editor will use this location for the hover and for code navigation - /// features: This part will become a clickable link that resolves to the - /// definition of the symbol at the given location (not necessarily the - /// location itself), it shows the hover that shows at the given location, - /// and it shows a context menu with further code navigation commands. - /// - /// Depending on the client capability `inlayHint.resolveSupport` clients - /// might resolve this property late using the resolve request. - /// FIXME: Location location; -}; - -struct InlayHint { - /// The position of this hint. - /// - /// If multiple hints have the same position, they will be shown in the order - /// they appear in the response. - Position position; - - /// The label of this hint. A human readable string or an array of - /// InlayHintLabelPart label parts. - /// - /// *Note* that neither the string nor the label part can be empty. - /// TODO: Use label - array label; - - /// The kind of this hint. Can be omitted in which case the client - /// should fall back to a reasonable default. - InlayHintKind kind; -}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/Reference.h b/include/Protocol/Feature/Reference.h deleted file mode 100644 index 4f19e8e8..00000000 --- a/include/Protocol/Feature/Reference.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct ReferenceClientCapabilities {}; - -using ReferenceOptions = WorkDoneProgressOptions; - -using ReferenceParams = TextDocumentPositionParams; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/Rename.h b/include/Protocol/Feature/Rename.h deleted file mode 100644 index d9b2e6a3..00000000 --- a/include/Protocol/Feature/Rename.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct RenameClientCapabilities {}; - -struct RenameOptions {}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/SemanticTokens.h b/include/Protocol/Feature/SemanticTokens.h deleted file mode 100644 index 37b7aa11..00000000 --- a/include/Protocol/Feature/SemanticTokens.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct SemanticTokensClientCapabilities {}; - -struct SemanticTokensLegend { - /// The token types a server uses. - array tokenTypes; - - /// The token modifiers a server uses. - array tokenModifiers; -}; - -struct SemanticTokensOptions { - /// The legend used by the server. - SemanticTokensLegend legend; - - /// Server supports providing semantic tokens for a specific - /// range of a document. - bool range = false; - - /// Server supports providing semantic tokens for a full document. - bool full = true; -}; - -struct SemanticTokensParams { - /// The text document. - TextDocumentIdentifier textDocument; -}; - -struct SemanticTokens {}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/SignatureHelp.h b/include/Protocol/Feature/SignatureHelp.h deleted file mode 100644 index 633bf4c2..00000000 --- a/include/Protocol/Feature/SignatureHelp.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct SignatureHelpClientCapabilities { - /** - * The client supports the `activeParameter` property on - * `SignatureInformation` literal. - * - * @since 3.16.0 - */ -}; - -struct SignatureHelpOptions { - /// The characters that trigger signature help automatically. - array triggerCharacters; - - /// List of characters that re-trigger signature help. - /// - /// These trigger characters are only active when signature help is already - /// showing. All trigger characters are also counted as re-trigger - /// characters. - array retriggerCharacters; -}; - -using SignatureHelpParams = TextDocumentPositionParams; - -struct ParameterInformation { - std::array label; -}; - -struct SignatureInformation { - string label; - - MarkupContent document; - - array parameters; - - uinteger activeParameter; -}; - -struct SignatureHelp { - array signatures; - - uinteger activeSignature; -}; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/TypeDefinition.h b/include/Protocol/Feature/TypeDefinition.h deleted file mode 100644 index fc46707e..00000000 --- a/include/Protocol/Feature/TypeDefinition.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct TypeDefinitionClientCapabilities {}; - -using TypeDefinitionOptions = WorkDoneProgressOptions; - -} // namespace clice::proto diff --git a/include/Protocol/Feature/TypeHierarchy.h b/include/Protocol/Feature/TypeHierarchy.h deleted file mode 100644 index f2151d9a..00000000 --- a/include/Protocol/Feature/TypeHierarchy.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../Basic.h" - -namespace clice::proto { - -struct TypeHierarchyClientCapabilities {}; - -using TypeHierarchyOptions = WorkDoneProgressOptions; - -} // namespace clice::proto diff --git a/include/Protocol/Lifecycle.h b/include/Protocol/Lifecycle.h deleted file mode 100644 index 6c8122d9..00000000 --- a/include/Protocol/Lifecycle.h +++ /dev/null @@ -1,205 +0,0 @@ -#pragma once - -#include "Basic.h" -#include "Notebook.h" -#include "TextDocument.h" -#include "Workspace.h" - -/// clice currently ignores all `dynamicRegistration` field in LSP specification. - -namespace clice::proto { - -struct LSPInfo { - /// The name of server or client. - std::string name; - - /// The version of server or client. - std::string version; -}; - -struct WindowCapacities {}; - -struct RegularExpressionsClientCapabilities {}; - -struct MarkdownClientCapabilities {}; - -struct GeneralCapacities { - /// FIXME: staleRequestSupport - - /// Client capabilities specific to regular expressions. - optional regularExpressions; - - /// Client capabilities specific to the client's markdown parser. - optional markdown; - - /// The position encodings supported by the client. - optional> positionEncodings; -}; - -struct ClientCapabilities { - /// Workspace specific client capabilities. - WorkspaceClientCapabilities workspace; - - /// Text document specific client capabilities. - TextDocumentClientCapabilities textDocument; - - /// Capabilities specific to the notebook document support. - NotebookDocumentClientCapabilities notebookDocument; - - /// Window specific client capabilities. - WindowCapacities window; - - /// General client capabilities. - GeneralCapacities general; -}; - -struct InitializeParams { - /// Information about client. - LSPInfo clientInfo; - - /// The capabilities provided by the client (editor or tool). - ClientCapabilities capabilities; - - /// The workspace folders configured in the client when the server starts. - /// This property is only available if the client supports workspace folders. - /// It can be `null` if the client supports workspace folders but none are - /// configured. - optional> workspaceFolders; - - /// The rootUri of the workspace. Is null if no - /// folder is open. If both `rootPath` and `rootUri` are set - /// `rootUri` wins. - /// - /// Deprecated in favour of `workspaceFolders` - optional rootUri; -}; - -struct ServerCapabilities { - /// The position encoding the server picked from the encodings offered - /// by the client via the client capability `general.positionEncodings`. - PositionEncodingKind positionEncoding; - - /// Defines how text documents are synced. - TextDocumentSyncOptions textDocumentSync; - - /// Defines how notebook documents are synced. - /// FIXME: NotebookDocumentSyncOptions notebookDocumentSync; - - /// The server provides completion support. - CompletionOptions completionProvider; - - /// The server provides hover support. - HoverOptions hoverProvider; - - /// The server provides signature help support. - SignatureHelpOptions signatureHelpProvider; - - /// The server provides go to declaration support. - DeclarationOptions declarationProvider; - - /// The server provides goto definition support. - DefinitionOptions definitionProvider; - - /// The server provides goto type definition support. - /// FIXME: TypeDefinitionOptions typeDefinitionProvider; - - /// The server provides goto implementation support. - /// FIXME: ImplementationOptions implementationProvider; - - /// The server provides find references support. - ReferenceOptions referencesProvider; - - /// The server provides document highlight support. - /// FIXME: DocumentHighlightOptions documentHighlightProvider; - - /// The server provides document symbol support. - DocumentSymbolOptions documentSymbolProvider; - - /// The server provides code actions. The `CodeActionOptions` return type is - /// only valid if the client signals code action literal support via the - /// property `textDocument.codeAction.codeActionLiteralSupport`. - /// FIXME: CodeActionOptions codeActionProvider; - - /// The server provides code lens. - /// FIXME: CodeLensOptions codeLensProvider; - - /// The server provides document link support. - DocumentLinkOptions documentLinkProvider; - - /// The server provides color provider support. - /// FIXME: DocumentColorOptions colorProvider; - - /// The server provides document formatting. - DocumentFormattingOptions documentFormattingProvider; - - /// The server provides document range formatting. - DocumentRangeFormattingOptions documentRangeFormattingProvider; - - /// The server provides document formatting on typing. - /// FIXME: DocumentOnTypeFormattingOptions documentOnTypeFormattingProvider; - - /// The server provides rename support. RenameOptions may only be specified if the client - /// states that it supports `prepareSupport` in its initial `initialize` request. - /// FIXME: RenameOptions renameProvider; - - /// The server provides folding provider support. - FoldingRangeOptions foldingRangeProvider; - - /// The server provides execute command support. - /// FIXME: ExecuteCommandOptions executeCommandProvider; - - /// The server provides selection range support. - /// FIXME: SelectionRangeOptions selectionRangeProvider; - - /// The server provides linked editing range support. - /// FIXME: LinkedEditingRangeOptions linkedEditingRangeProvider; - - /// The server provides call hierarchy support. - /// FIXME: CallHierarchyOptions callHierarchyProvider; - - /// The server provides semantic tokens support. - SemanticTokensOptions semanticTokensProvider; - - /// Whether server provides moniker support. - /// FIXME: MonikerOptions monikerProvider; - - /// The server provides type hierarchy support. - /// FIXME: TypeHierarchyOptions typeHierarchyProvider; - - /// The server provides inline values. - /// FIXME: InlineValueOptions inlineValueProvider; - - /// The server provides inlay hints. - InlayHintOptions inlayHintProvider; - - /// The server has support for pull model diagnostics. - /// FIXME: DiagnosticOptions diagnosticProvider; - - /// The server provides workspace symbol support. - WorkspaceSymbolOptions workspaceSymbolProvider; - - /// Workspace specific server capabilities. - WorkspaceServerCapabilities workspace; -}; - -struct InitializeResult { - /// Information about the server. - LSPInfo serverInfo; - - /// The capabilities the language server provides. - ServerCapabilities capabilities; -}; - -struct Empty {}; - -using InitializedParams = Empty; - -using ShutdownParams = Empty; - -using ShutdownResult = Empty; - -using ExitParams = Empty; - -using ExitResult = Empty; - -} // namespace clice::proto diff --git a/include/Protocol/Notebook.h b/include/Protocol/Notebook.h deleted file mode 100644 index 331353b4..00000000 --- a/include/Protocol/Notebook.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "Basic.h" - -namespace clice::proto { - -struct NotebookDocumentClientCapabilities {}; - -} // namespace clice::proto diff --git a/include/Protocol/Protocol.h b/include/Protocol/Protocol.h deleted file mode 100644 index ab248b0d..00000000 --- a/include/Protocol/Protocol.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "Lifecycle.h" diff --git a/include/Protocol/TextDocument.h b/include/Protocol/TextDocument.h deleted file mode 100644 index b06621b5..00000000 --- a/include/Protocol/TextDocument.h +++ /dev/null @@ -1,201 +0,0 @@ -#pragma once - -#include "Basic.h" -#include "Feature/CallHierarchy.h" -#include "Feature/CodeAction.h" -#include "Feature/CodeCompletion.h" -#include "Feature/CodeLens.h" -#include "Feature/Declaration.h" -#include "Feature/Definition.h" -#include "Feature/Diagnostic.h" -#include "Feature/DocumentHighlight.h" -#include "Feature/DocumentLink.h" -#include "Feature/DocumentSymbol.h" -#include "Feature/FoldingRange.h" -#include "Feature/Formatting.h" -#include "Feature/Hover.h" -#include "Feature/Implementation.h" -#include "Feature/InlayHint.h" -#include "Feature/Reference.h" -#include "Feature/Rename.h" -#include "Feature/SemanticTokens.h" -#include "Feature/SignatureHelp.h" -#include "Feature/TypeDefinition.h" -#include "Feature/TypeHierarchy.h" - -namespace clice::proto { - -struct TextDocumentSyncClientCapabilities {}; - -struct TextDocumentClientCapabilities { - optional synchronization; - - /// Capabilities specific to the `textDocument/completion` request. - optional completion; - - /// Capabilities specific to the `textDocument/hover` request. - optional hover; - - /// Capabilities specific to the `textDocument/signatureHelp` request. - optional signatureHelp; - - /// Capabilities specific to the `textDocument/declaration` request. - optional declaration; - - /// Capabilities specific to the `textDocument/definition` request. - optional definition; - - /// Capabilities specific to the `textDocument/typeDefinition` request. - optional typeDefinition; - - /// Capabilities specific to the `textDocument/implementation` request. - optional implementation; - - /// Capabilities specific to the `textDocument/references` request. - optional references; - - /// Capabilities specific to the `textDocument/documentHighlight` request. - optional documentHighlight; - - /// Capabilities specific to the `textDocument/documentSymbol` request. - optional documentSymbol; - - /// Capabilities specific to the `textDocument/codeAction` request. - optional codeAction; - - /// Capabilities specific to the `textDocument/codeLens` request. - optional codeLens; - - /// Capabilities specific to the `textDocument/documentLink` request. - optional documentLink; - - /// Capabilities specific to the `textDocument/documentColor` and the - /// `textDocument/colorPresentation` request. - /// FIXME: optional colorProvider; - - /// Capabilities specific to the `textDocument/formatting` request. - optional formatting; - - /// Capabilities specific to the `textDocument/rangeFormatting` request. - optional rangeFormatting; - - /// Capabilities specific to the `textDocument/onTypeFormatting` request. - optional onTypeFormatting; - - /// Capabilities specific to the `textDocument/rename` request. - optional rename; - - /// Capabilities specific to the `textDocument/publishDiagnostics` notification. - optional publishDiagnostics; - - /// Capabilities specific to the `textDocument/foldingRange` request. - optional foldingRange; - - /// Capabilities specific to the `textDocument/selectionRange` request. - /// FIXME: optional selectionRange; - - /// Capabilities specific to the `textDocument/linkedEditingRange` request. - /// FIXME: optional linkedEditingRange; - - /// Capabilities specific to the various call hierarchy requests. - optional callHierarchy; - - /// Capabilities specific to the various semantic token requests. - optional semanticTokens; - - /// Capabilities specific to the `textDocument/moniker` request. - /// FIXME: optional moniker; - - /// Capabilities specific to the various type hierarchy requests. - optional typeHierarchy; - - /// Capabilities specific to the `textDocument/inlineValue` request. - /// FIXME: optional inlineValue; - - /// Capabilities specific to the `textDocument/inlayHint` request. - optional inlayHint; - - /// Capabilities specific to the diagnostic pull model. - optional diagnostic; -}; - -enum class TextDocumentSyncKind : std::uint8_t { - /// Documents should not be synced at all. - None = 0, - - /// Documents are synced by always sending the full content of the document. - Full = 1, - - /// Documents are synced by sending the full content on open. After that - /// only incremental updates to the document are sent. - Incremental = 2, -}; - -struct TextDocumentSyncOptions { - /// Open and close notifications are sent to the server. If omitted open - /// close notifications should not be sent. - bool openClose = true; - - /// Change notifications are sent to the server. - TextDocumentSyncKind change = TextDocumentSyncKind::Incremental; - - /// If present will save notifications are sent to the server. If omitted - /// the notification should not be sent. - /// FIXME: bool willSave; - - /// If present will save wait until requests are sent to the server. If - /// omitted the request should not be sent. - /// FIXME: bool willSaveWaitUntil; - - /// If present save notifications are sent to the server. If omitted the - /// notification should not be sent. - bool save = true; -}; - -struct DidOpenTextDocumentParams { - /// The document that was opened. - TextDocumentItem textDocument; -}; - -struct TextDocumentContentChangeEvent { - /// The new text of the whole document. - string text; -}; - -struct DidChangeTextDocumentParams { - /// The document that did change. The version number points - /// to the version after all provided content changes have - /// been applied. - VersionedTextDocumentIdentifier textDocument; - - /// The actual content changes. The content changes describe single state - /// changes to the document. So if there are two content changes c1 (at - /// array index 0) and c2 (at array index 1) for a document in state S then - /// c1 moves the document from S to S' and c2 from S' to S''. So c1 is - /// computed on the state S and c2 is computed on the state S'. - // - /// To mirror the content of a document using change events use the following - /// approach: - /// - start with the same initial content - /// - apply the 'textDocument/didChange' notifications in the order you - /// receive them. - /// - apply the `TextDocumentContentChangeEvent`s in a single notification - /// in the order you receive them. - array contentChanges; -}; - -struct DidSaveTextDocumentParams { - /// The document that was saved. - TextDocumentIdentifier textDocument; - - /// Optional the content when saved. Depends on the includeText value - /// when the save notification was requested. - string text; -}; - -struct DidCloseTextDocumentParams { - /// The document that was closed. - TextDocumentIdentifier textDocument; -}; - -} // namespace clice::proto diff --git a/include/Protocol/Workspace.h b/include/Protocol/Workspace.h deleted file mode 100644 index b078a327..00000000 --- a/include/Protocol/Workspace.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "Basic.h" - -namespace clice::proto { - -struct WorkspaceFolder { - /// The associated URI for this workspace folder. - URI uri; - - /// The name of the workspace folder. Used to refer to this - /// workspace folder in the user interface. - string name; -}; - -struct WorkspaceClientCapabilities {}; - -struct WorkspaceSymbolOptions {}; - -struct WorkspaceFoldersServerCapabilities { - /// The server has support for workspace folders. - bool supported = true; -}; - -struct WorkspaceServerCapabilities { - /// The server supports workspace folder. - WorkspaceFoldersServerCapabilities workspaceFolders; -}; - -} // namespace clice::proto diff --git a/include/Server/Config.h b/include/Server/Config.h deleted file mode 100644 index 951437bc..00000000 --- a/include/Server/Config.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" - -namespace clice::config { - -struct ProjectOptions { - bool root = true; - - bool clang_tidy = false; - - std::size_t max_active_file = 8; - - std::string cache_dir = "${workspace}/.clice/cache"; - - std::string index_dir = "${workspace}/.clice/index"; - - std::string logging_dir = "${workspace}/.clice/logging"; - - std::vector compile_commands_paths = {"${workspace}/build"}; -}; - -struct Rule { - /// All patterns of the rule. - llvm::SmallVector patterns; - - /// The commands that you want to remove from original command. - llvm::SmallVector remove; - - /// The commands that you want to append from original command. - llvm::SmallVector append; -}; - -struct Config { - /// The workspace of this config file. - std::string workspace; - - /// Project level configs. - ProjectOptions project; - - /// All rules used for specific files. - llvm::SmallVector rules; - - auto parse(llvm::StringRef workspace) -> std::expected; -}; - -}; // namespace clice::config diff --git a/include/Server/Convert.h b/include/Server/Convert.h deleted file mode 100644 index a1a30b03..00000000 --- a/include/Server/Convert.h +++ /dev/null @@ -1,305 +0,0 @@ -#pragma once - -#include "Compiler/Diagnostic.h" -#include "Feature/CodeCompletion.h" -#include "Feature/SemanticToken.h" -#include "Protocol/Protocol.h" -#include "Support/FileSystem.h" -#include "Support/JSON.h" - -namespace clice { - -enum class PositionEncodingKind { - UTF8, - UTF16, - UTF32, -}; - -struct PathMapping { - std::string to_path(llvm::StringRef uri) { - /// FIXME: Path mapping. - return fs::toPath(uri); - } - - std::string to_uri(llvm::StringRef path) { - /// FIXME: Path mapping. - return fs::toURI(path); - } -}; - -/// @brief Iterates over Unicode codepoints in a UTF-8 encoded string and invokes a callback for -/// each codepoint. -/// -/// Processes the input UTF-8 string, calculating the length of each Unicode codepoint in both -/// UTF-8 (bytes) and UTF-16 (code units), and passes these lengths to the callback. -/// Iteration stops early if the callback returns `false`. -/// -/// ASCII characters are treated as 1-byte UTF-8 codepoints with a UTF-16 length of 1. -/// Non-ASCII characters are processed based on their leading byte to determine UTF-8 length: -/// - Valid lengths are 2 to 4 bytes. -/// - Astral codepoints (UTF-8 length of 4) have a UTF-16 length of 2 code units. -/// Invalid UTF-8 sequences are treated as single-byte ASCII characters. -/// -/// Returns `false` if the callback stops the iteration. -template -bool iterateCodepoints(llvm::StringRef content, const Callback& callback) { - // Iterate over the input string, processing each codepoint. - for(size_t index = 0; index < content.size();) { - unsigned char c = static_cast(content[index]); - - // Handle ASCII characters (1-byte UTF-8, 1-code-unit UTF-16). - if(!(c & 0x80)) [[likely]] { - if(!callback(1, 1)) { - return true; - } - - ++index; - continue; - } - - // Determine the length of the codepoint in UTF-8 by counting the leading 1s. - size_t length = llvm::countl_one(c); - - // Validate UTF-8 encoding: length must be between 2 and 4. - if(length < 2 || length > 4) [[unlikely]] { - assert(false && "Invalid UTF-8 sequence"); - - // Treat the byte as an ASCII character. - if(!callback(1, 1)) { - return true; - } - - ++index; - continue; - } - - // Advance the index by the length of the current UTF-8 codepoint. - index += length; - - // Calculate the UTF-16 length: astral codepoints (4-byte UTF-8) take 2 code units. - if(!callback(length, length == 4 ? 2 : 1)) { - return true; - } - } - - return false; -} - -/// Remeasure the length (character count) of the content with the specified encoding kind. -inline std::uint32_t remeasure(llvm::StringRef content, PositionEncodingKind kind) { - if(kind == PositionEncodingKind::UTF8) { - return content.size(); - } - - if(kind == PositionEncodingKind::UTF16) { - std::uint32_t length = 0; - iterateCodepoints(content, [&](std::uint32_t, std::uint32_t utf16Length) { - length += utf16Length; - return true; - }); - return length; - } - - if(kind == PositionEncodingKind::UTF32) { - std::uint32_t length = 0; - iterateCodepoints(content, [&](std::uint32_t, std::uint32_t) { - length += 1; - return true; - }); - return length; - } - - std::unreachable(); -} - -class PositionConverter { -public: - PositionConverter(llvm::StringRef content, PositionEncodingKind encoding) : - content(content), encoding(encoding) {} - - /// Convert a offset to a proto::Position with given encoding. - /// The input offset must be UTF-8 encoded and in order. - proto::Position toPosition(uint32_t offset) { - assert(offset <= content.size() && "Offset is out of range"); - assert(offset >= lastInput && "Offset must be in order"); - - /// Fast path: return the last output. - if(offset == lastInput) [[unlikely]] { - return lastOutput; - } - - /// The length of the current line. - std::uint32_t lineLength = 0; - - /// Move the line offset to the current line. - for(std::uint32_t i = lastLineOffset; i < offset; i++) { - lineLength += 1; - if(content[i] == '\n') { - line += 1; - lastLineOffset += lineLength; - lineLength = 0; - } - } - - /// Get the content of the current line. - auto lineContent = content.substr(lastLineOffset, lineLength); - auto position = proto::Position{ - .line = line, - .character = remeasure(lineContent, encoding), - }; - - /// Cache the result. - lastInput = offset; - lastOutput = position; - - return position; - } - - template - void to_positions(Range&& range, const Proj&& proj = {}) { - std::vector offsets; - for(auto&& item: range) { - auto [begin, end] = proj(item); - offsets.emplace_back(begin); - offsets.emplace_back(end); - } - - ranges::sort(offsets); - - for(auto&& offset: offsets) { - if(auto it = cache.find(offset); it == cache.end()) { - cache.try_emplace(offset, toPosition(offset)); - } - } - } - - proto::Position lookup(uint32_t offset) { - auto it = cache.find(offset); - assert(it != cache.end() && "Offset is not cached"); - return it->second; - } - - proto::Range lookup(LocalSourceRange range) { - auto it = cache.find(range.begin); - assert(it != cache.end() && "Offset is not cached"); - auto begin = it->second; - it = cache.find(range.end); - assert(it != cache.end() && "Offset is not cached"); - auto end = it->second; - return proto::Range{begin, end}; - } - -private: - std::uint32_t line = 0; - /// The offset of the last line end. - std::uint32_t lastLineOffset = 0; - - /// The input offset of last call. - std::uint32_t lastInput = 0; - proto::Position lastOutput = {0, 0}; - - llvm::DenseMap cache; - - llvm::StringRef content; - PositionEncodingKind encoding; -}; - -inline std::uint32_t to_offset(clice::PositionEncodingKind kind, - llvm::StringRef content, - proto::Position position) { - std::uint32_t offset = 0; - for(auto i = 0; i < position.line; i++) { - auto pos = content.find('\n'); - assert(pos != llvm::StringRef::npos && "Line value is out of range"); - - offset += pos + 1; - content = content.substr(pos + 1); - } - - /// Drop the content after the line. - content = content.take_until([](char c) { return c == '\n'; }); - assert(position.character <= content.size() && "Character value is out of range"); - - if(position.character == 0) { - return offset; - } - - if(kind == PositionEncodingKind::UTF8) { - offset += position.character; - return offset; - } - - if(kind == PositionEncodingKind::UTF16) { - iterateCodepoints(content, [&](std::uint32_t utf8Length, std::uint32_t utf16Length) { - assert(position.character >= utf16Length && "Character value is out of range"); - position.character -= utf16Length; - offset += utf8Length; - return position.character != 0; - }); - return offset; - } - - if(kind == PositionEncodingKind::UTF32) { - iterateCodepoints(content, [&](std::uint32_t utf8Length, std::uint32_t) { - assert(position.character >= 1 && "Character value is out of range"); - position.character -= 1; - offset += utf8Length; - return position.character != 0; - }); - return offset; - } - - std::unreachable(); -} - -} // namespace clice - -namespace clice::proto { - -inline SymbolKind kind_map(clice::SymbolKind kind) { - switch(kind.kind()) { - case clice::SymbolKind::Comment: return SymbolKind::String; - case clice::SymbolKind::Number: return SymbolKind::Number; - case clice::SymbolKind::Character: return SymbolKind::String; - case clice::SymbolKind::String: return SymbolKind::String; - case clice::SymbolKind::Keyword: return SymbolKind::Variable; - case clice::SymbolKind::Directive: return SymbolKind::Variable; - case clice::SymbolKind::Header: return SymbolKind::String; - case clice::SymbolKind::Module: return SymbolKind::Module; - case clice::SymbolKind::Macro: return SymbolKind::Function; - case clice::SymbolKind::MacroParameter: return SymbolKind::Variable; - case clice::SymbolKind::Namespace: return SymbolKind::Namespace; - case clice::SymbolKind::Class: return SymbolKind::Class; - case clice::SymbolKind::Struct: return SymbolKind::Struct; - case clice::SymbolKind::Union: return SymbolKind::Class; - case clice::SymbolKind::Enum: return SymbolKind::Enum; - case clice::SymbolKind::Type: return SymbolKind::TypeParameter; - case clice::SymbolKind::Field: return SymbolKind::Field; - case clice::SymbolKind::EnumMember: return SymbolKind::EnumMember; - case clice::SymbolKind::Function: return SymbolKind::Function; - case clice::SymbolKind::Method: return SymbolKind::Method; - case clice::SymbolKind::Variable: return SymbolKind::Variable; - case clice::SymbolKind::Parameter: return SymbolKind::Variable; - case clice::SymbolKind::Label: return SymbolKind::Variable; - case clice::SymbolKind::Concept: return SymbolKind::TypeParameter; - case clice::SymbolKind::Attribute: return SymbolKind::Variable; - case clice::SymbolKind::Operator: - case clice::SymbolKind::Paren: - case clice::SymbolKind::Bracket: - case clice::SymbolKind::Brace: - case clice::SymbolKind::Angle: return SymbolKind::Operator; - case clice::SymbolKind::Conflict: - case clice::SymbolKind::Invalid: - default: return SymbolKind::Null; - } -} - -json::Value to_json(clice::PositionEncodingKind kind, - llvm::StringRef content, - llvm::ArrayRef tokens); - -json::Value to_json(clice::PositionEncodingKind kind, - llvm::StringRef content, - llvm::ArrayRef items); - -} // namespace clice::proto diff --git a/include/Server/Indexer.h b/include/Server/Indexer.h deleted file mode 100644 index eb1b591b..00000000 --- a/include/Server/Indexer.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include -#include - -#include "Config.h" -#include "Convert.h" -#include "Async/Async.h" -#include "Compiler/Command.h" -#include "Index/MergedIndex.h" -#include "Index/ProjectIndex.h" -#include "Protocol/Protocol.h" - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/StringMap.h" - -namespace clice { - -class CompilationUnit; - -class Indexer { -public: - Indexer(CompilationDatabase& database, - config::Config& config, - const PositionEncodingKind& kind) : - database(database), config(config), encoding_kind(kind) {} - - async::Task<> index(llvm::StringRef path); - - async::Task<> index(llvm::StringRef path, llvm::StringRef content); - - async::Task<> schedule_next(); - - async::Task<> index_all(); - - index::MergedIndex& get_index(std::uint32_t path_id) { - auto [it, success] = in_memory_indices.try_emplace(path_id); - if(!success) { - return it->second; - } - - auto it2 = project_index.indices.find(path_id); - if(it2 != project_index.indices.end()) { - auto path = project_index.path_pool.path(it2->second); - it->second = index::MergedIndex::load(path); - } - - return it->second; - } - - using Result = async::Task>; - - void load_from_disk(); - - void save_to_disk(); - - auto lookup(llvm::StringRef path, std::uint32_t offset, RelationKind kind) -> Result; - - auto declaration(llvm::StringRef path, std::uint32_t offset) -> Result; - - auto definition(llvm::StringRef path, std::uint32_t offset) -> Result; - - auto references(llvm::StringRef path, std::uint32_t offset) -> Result; - - /// TODO: Calls ... - - /// TODO: Types ... - -private: - CompilationDatabase& database; - - config::Config& config; - - const PositionEncodingKind& encoding_kind; - - index::ProjectIndex project_index; - - PathMapping mapping; - - llvm::DenseMap in_memory_indices; - - /// Currently indexes tasks ... - std::vector> workings; - - /// FIXME: Use a LRU to make sure we won't index a file twice ... - std::deque waitings; - - async::Event update_event; -}; - -} // namespace clice diff --git a/include/Server/Server.h b/include/Server/Server.h deleted file mode 100644 index 9a2794ff..00000000 --- a/include/Server/Server.h +++ /dev/null @@ -1,246 +0,0 @@ -#pragma once - -#include "Config.h" -#include "Convert.h" -#include "Indexer.h" -#include "Async/Async.h" -#include "Compiler/Command.h" -#include "Compiler/Diagnostic.h" -#include "Compiler/Preamble.h" -#include "Feature/DocumentLink.h" -#include "Protocol/Protocol.h" - -namespace clice { - -struct OpenFile { - /// The file version, every edition will increase it. - std::uint32_t version = 0; - - /// The file content. - std::string content; - - /// We build PCH for every opened file. - std::optional pch; - async::Task pch_build_task; - async::Event pch_built_event; - std::vector pch_includes; - - /// For each opened file, we would like to build an AST for it. - std::shared_ptr ast; - async::Task<> ast_build_task; - async::Lock ast_built_lock; - - /// For header with context, it may have multiple ASTs, use - /// an chain to store them. - std::unique_ptr next; -}; - -/// A manager for all OpenFile with LRU cache. -class ActiveFileManager { -public: - /// Use shared_ptr to manage the lifetime of OpenFile object in async function. - using ActiveFile = std::shared_ptr; - - /// A double-linked list to store all opened files. While the `first` field of pair (each node - /// of list) refers to a key in `index`, the `second` field refers to the OpenFile object. - /// In another word, the `index` holds the ownership of path and the `items` holds the - /// ownership of OpenFile object. - using ListContainer = std::list>; - - struct ActiveFileIterator : public ListContainer::const_iterator {}; - - constexpr static size_t DefaultMaxActiveFileNum = 8; - constexpr static size_t UnlimitedActiveFileNum = 512; - -public: - /// Create an ActiveFileManager with a default size. - ActiveFileManager() : capability(DefaultMaxActiveFileNum) {} - - ActiveFileManager(const ActiveFileManager&) = delete; - ActiveFileManager& operator=(const ActiveFileManager&) = delete; - - /// Set the maximum active file count and it will be clamped to [1, UnlimitedActiveFileNum]. - void set_capability(size_t size) { - // Use static_cast to make MSVC happy. - capability = std::clamp(size, static_cast(1), UnlimitedActiveFileNum); - } - - /// Get the maximum size of the cache. - size_t max_size() const { - return capability; - } - - /// Get the current size of the cache. - size_t size() const { - return index.size(); - } - - /// Try get OpenFile from manager, default construct one if not exists. - [[nodiscard]] ActiveFile& get_or_add(llvm::StringRef path); - - /// Add a OpenFile to the manager. - ActiveFile& add(llvm::StringRef path, OpenFile file); - - [[nodiscard]] bool contains(llvm::StringRef path) const { - return index.contains(path); - } - - ActiveFileIterator begin() const { - return ActiveFileIterator(items.begin()); - } - - ActiveFileIterator end() const { - return ActiveFileIterator(items.end()); - } - -private: - ActiveFile& lru_put_impl(llvm::StringRef path, OpenFile file); - -private: - /// The maximum size of the cache. - size_t capability; - - /// The first element is the most recently used, and the last - /// element is the least recently used. - /// When a file is accessed, it will be moved to the front of the list. - /// When a new file is added, if the size exceeds the maximum size, - /// the last element will be removed. - ListContainer items; - - /// A map from path to the iterator of the list. - llvm::StringMap index; -}; - -class Server { -public: - Server(); - - using Self = Server; - - using Callback = async::Task (*)(Server&, json::Value); - - template - void register_callback(llvm::StringRef name) { - using MF = decltype(method); - static_assert(std::is_member_function_pointer_v, ""); - using F = member_type_t; - using Ret = function_return_t; - using Params = std::tuple_element_t<0, function_args_t>; - - Callback callback = [](Server& server, json::Value value) -> async::Task { - if constexpr(std::is_same_v>) { - co_await (server.*method)(json::deserialize(value)); - co_return json::Value(nullptr); - } else { - co_return co_await (server.*method)(json::deserialize(value)); - } - }; - - callbacks.try_emplace(name, callback); - } - - async::Task<> on_receive(json::Value value); - -private: - /// Send a request to the client. - async::Task<> request(llvm::StringRef method, json::Value params); - - /// Send a notification to the client. - async::Task<> notify(llvm::StringRef method, json::Value params); - - /// Send a response to the client. - async::Task<> response(json::Value id, json::Value result); - - async::Task<> response(json::Value id, proto::ErrorCodes code, llvm::StringRef message = ""); - - /// Send an register capability to the client. - async::Task<> registerCapacity(llvm::StringRef id, - llvm::StringRef method, - json::Value registerOptions); - -private: - async::Task on_initialize(proto::InitializeParams params); - - async::Task<> on_initialized(proto::InitializedParams); - - async::Task on_shutdown(proto::ShutdownParams params); - - async::Task<> on_exit(proto::ExitParams params); - -private: - /// Load the cache info from disk. - void load_cache_info(); - - /// Save the cache info to disk. - void save_cache_info(); - - async::Task build_pch(std::string file, std::string preamble); - - async::Task<> build_ast(std::string file, std::string content); - - async::Task> add_document(std::string path, std::string content); - -private: - async::Task<> on_did_open(proto::DidOpenTextDocumentParams params); - - async::Task<> on_did_change(proto::DidChangeTextDocumentParams params); - - async::Task<> on_did_save(proto::DidSaveTextDocumentParams params); - - async::Task<> on_did_close(proto::DidCloseTextDocumentParams params); - -private: - using Result = async::Task; - - auto on_completion(proto::CompletionParams params) -> Result; - - auto on_hover(proto::HoverParams params) -> Result; - - auto on_signature_help(proto::SignatureHelpParams params) -> Result; - - auto on_go_to_declaration(proto::DeclarationParams params) -> Result; - - auto on_go_to_definition(proto::DefinitionParams params) -> Result; - - auto on_find_references(proto::ReferenceParams params) -> Result; - - auto on_document_symbol(proto::DocumentSymbolParams params) -> Result; - - auto on_document_link(proto::DocumentLinkParams params) -> Result; - - auto on_document_format(proto::DocumentFormattingParams params) -> Result; - - auto on_document_range_format(proto::DocumentRangeFormattingParams params) -> Result; - - auto on_folding_range(proto::FoldingRangeParams params) -> Result; - - auto on_semantic_token(proto::SemanticTokensParams params) -> Result; - - auto on_inlay_hint(proto::InlayHintParams params) -> Result; - -private: - /// The current request id. - std::uint32_t server_request_id = 0; - std::uint32_t client_request_id = 0; - - /// All registered LSP callbacks. - llvm::StringMap callbacks; - - PositionEncodingKind kind = PositionEncodingKind::UTF16; - - std::string workspace; - - /// The compilation database. - CompilationDatabase database; - - /// All opening files. - ActiveFileManager opening_files; - - PathMapping mapping; - - config::Config config; - - Indexer indexer; -}; - -} // namespace clice diff --git a/include/Server/Version.h b/include/Server/Version.h deleted file mode 100644 index 5fe4f0e7..00000000 --- a/include/Server/Version.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -namespace clice::config { - -constexpr inline std::string_view version = "0.0.1"; -constexpr inline std::string_view llvm_version = "20.1.5"; - -} // namespace clice::config diff --git a/include/Support/Assert.h b/include/Support/Assert.h deleted file mode 100644 index 80d6d236..00000000 --- a/include/Support/Assert.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Format.h" - -namespace clice { - -#ifndef NDEBUG -#define ASSERT(expr, message, ...) \ - if(!(expr)) { \ - llvm::errs() << "ASSERT FAIL: " << std::format(message, ##__VA_ARGS__); \ - std::abort(); \ - } -#else -#define ASSERT(expr, message, ...) -#endif - -} // namespace clice diff --git a/include/Support/Binary.h b/include/Support/Binary.h deleted file mode 100644 index 9cb791b6..00000000 --- a/include/Support/Binary.h +++ /dev/null @@ -1,312 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "Enum.h" -#include "FixedString.h" -#include "Format.h" -#include "Struct.h" - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/MemoryBuffer.h" - -namespace clice::binary { - -template -struct array { - /// The offset to the beginning of binary buffer. - uint32_t offset; - - /// The size of array. - uint32_t size; -}; - -using string = array; - -/// Check whether a type can be directly binarized. -template -constexpr inline bool is_directly_binarizable_v = [] { - if constexpr(std::is_integral_v || refl::reflectable_enum) { - return true; - } else if constexpr(refl::reflectable_struct) { - return refl::member_types::apply( - []() { return (is_directly_binarizable_v && ...); }); - } else { - return false; - } -}(); - -template -consteval auto binarify(); - -template -using binarify_t = typename decltype(binarify())::type; - -template -consteval auto binarify() { - if constexpr(is_directly_binarizable_v) { - return identity(); - } else if constexpr(std::is_same_v) { - return identity(); - } else if constexpr(is_specialization_of) { - return identity>(); - } else if constexpr(is_specialization_of) { - return tuple_to_list_t::apply( - [] { return identity...>>(); }); - } else if constexpr(refl::reflectable_struct) { - return refl::member_types::apply( - [] { return identity...>>(); }); - } else { - static_assert(dependent_false, "unsupported type"); - } -} - -/// A section in the binary data. -template -struct Section { - /// Current count of elements. - uint32_t count = 0; - - /// Total count of elements in the section. - uint32_t total = 0; - - /// Offset of the section. - uint32_t offset = 0; -}; - -template -consteval auto layout() { - if constexpr(is_directly_binarizable_v) { - return std::tuple<>(); - } else if constexpr(std::is_same_v) { - return std::tuple>(); - } else if constexpr(is_specialization_of) { - using V = typename T::value_type; - if constexpr(std::is_same_v) { - return std::tuple>(); - } else { - return std::tuple_cat(std::tuple>(), layout()); - } - } else if constexpr(is_specialization_of) { - return tuple_to_list_t::apply( - [] { return std::tuple_cat(layout()...); }); - } else if constexpr(refl::reflectable_struct) { - return refl::member_types::apply( - [] { return std::tuple_cat(layout()...); }); - } else { - static_assert(dependent_false, "unsupported type"); - } -} - -/// Get the binary layout of a type. Make sure every type in the -/// layout is unique. -template -using layout_t = tuple_uniuqe_t())>; - -template -struct Packer { - /// The layout of the binary data. - layout_t layout = {}; - - /// The total size of the binary data. - uint32_t size = 0; - - /// The buffer to store the binary data. - std::vector buffer; - - /// Recursively traverse the object and calculate the size of each section. - template - void init(const Object& object) { - if constexpr(std::same_as) { - std::get>(layout).total += object.size() + 1; - } else if constexpr(requires { typename Object::value_type; }) { - std::get>(layout).total += object.size(); - for(const auto& element: object) { - init(element); - } - } else if constexpr(refl::reflectable_struct) { - refl::foreach(object, [&](auto, auto& field) { init(field); }); - } - } - - template - requires (is_directly_binarizable_v && !refl::reflectable_struct) - Object write(const Object& object) { - return object; - } - - template - requires (std::is_same_v) - string write(const Object& object) { - auto& section = std::get>(layout); - uint32_t size = object.size(); - uint32_t offset = section.offset + section.count; - section.count += size + 1; - - std::memcpy(buffer.data() + offset, object.data(), size); - buffer[offset + size] = '\0'; - - return string{offset, size}; - } - - template - requires (is_specialization_of) - array write(const Object& object) { - auto& section = std::get>(layout); - uint32_t size = object.size(); - uint32_t offset = section.offset + section.count * sizeof(binarify_t); - section.count += size; - - for(std::size_t i = 0; i < size; ++i) { - ::new (buffer.data() + offset + i * sizeof(binarify_t)) auto{write(object[i])}; - } - - return array{offset, size}; - } - - template - requires (refl::reflectable_struct) - std::array)> write(const Object& object) { - std::array)> buffer; - std::memset(buffer.data(), 0, sizeof(buffer)); - - binarify_t result; - refl::foreach(result, object, [&](auto& lhs, auto& rhs) { - auto offset = reinterpret_cast(&lhs) - reinterpret_cast(&result); - ::new (buffer.data() + offset) auto{write(rhs)}; - }); - - return buffer; - } - - std::vector pack(const auto& object) { - /// First initialize the layout. - init(object); - - /// Calculate the total size of the binary data and - /// the offset of each section. - size = sizeof(binarify_t); - - auto try_each = [&](auto, Section& field) { - static_assert(alignof(binarify_t) <= 8, "Alignment not supported."); - - /// Make sure each section is aligned to 8 bytes. - if(size % 8 != 0) { - size += 8 - size % 8; - } - - field.offset = size; - size += field.total * sizeof(binarify_t); - }; - - refl::foreach(layout, try_each); - - /// Make sure the buffer is clean. So we can compare the result. - /// Every padding in the struct should be filled with 0. - buffer.resize(size, 0); - - /// Write the object to the buffer. - auto result = write(object); - std::memcpy(buffer.data(), &result, sizeof(result)); - - return std::move(buffer); - } -}; - -/// A helper class to access the binary data. -template -struct Proxy { - using underlying_type = binarify_t; - const void* base; - const void* data; - - const auto& value() const { - return *reinterpret_cast(data); - } - - template - auto get() const { - return Proxy>{base, &std::get(value())}; - } - - template - auto get() const { - constexpr auto& names = refl::member_names(); - - constexpr auto index = []() { - for(std::size_t i = 0; i < names.size(); ++i) { - if(names[i] == name) { - return i; - } - } - return names.size(); - }(); - - return this->template get(); - } - - auto as_string() const { - auto [offset, size] = value(); - return llvm::StringRef{reinterpret_cast(base) + offset, size}; - } - - auto as_array() const { - auto [offset, size] = value(); - using U = binarify_t; - return llvm::ArrayRef{ - reinterpret_cast(static_cast(base) + offset), - size, - }; - } - - auto operator[](std::size_t index) const { - return Proxy{base, &as_array()[index]}; - } - - auto size() const { - return value().size; - } - - auto operator->() const { - return &value(); - } - - operator const underlying_type&() const { - return value(); - } -}; - -/// Binirize an object. -template -auto serialize(const Object& object) { - auto buffer = Packer().pack(object); - auto proxy = Proxy{buffer.data(), buffer.data()}; - return std::tuple(std::move(buffer), proxy); -} - -template -Object deserialize(Proxy proxy) { - if constexpr(is_directly_binarizable_v) { - return proxy.value(); - } else if constexpr(std::is_same_v) { - return proxy.as_string().str(); - } else if constexpr(is_specialization_of) { - Object result; - for(std::size_t i = 0; i < proxy.size(); i++) { - result.emplace_back(deserialize(proxy[i])); - } - return result; - } else if constexpr(refl::reflectable_struct) { - return [&](std::index_sequence) { - return Object{deserialize(proxy.template get())...}; - }(std::make_index_sequence()>()); - } else { - static_assert(dependent_false, ""); - } -} - -} // namespace clice::binary diff --git a/include/Support/Compare.h b/include/Support/Compare.h deleted file mode 100644 index c9c999fb..00000000 --- a/include/Support/Compare.h +++ /dev/null @@ -1,137 +0,0 @@ -#pragma once - -#include - -#include "Enum.h" -#include "Struct.h" - -namespace clice::refl { - -template -struct Equal { - constexpr static bool equal(const LHS& lhs, const RHS& rhs) { - return lhs == rhs; - } -}; - -struct equal_t { - template - constexpr static bool operator()(const LHS& lhs, const RHS& rhs) { - return Equal::equal(lhs, rhs); - } -}; - -constexpr inline equal_t equal; - -template -struct Equal> { - constexpr static bool equal(const std::vector& lhs, const std::vector& rhs) { - if(lhs.size() != rhs.size()) { - return false; - } - - for(std::size_t i = 0; i < lhs.size(); ++i) { - if(!refl::equal(lhs[i], rhs[i])) { - return false; - } - } - - return true; - } -}; - -template -struct Equal { - constexpr static bool equal(E lhs, E rhs) { - return lhs.value() == rhs.value(); - } -}; - -template - requires (!requires(T lhs, T rhs) { - { lhs == rhs } -> std::convertible_to; - }) -struct Equal { - constexpr static bool equal(const T& lhs, const T& rhs) { - return foreach(lhs, rhs, [](const auto& lhs, const auto& rhs) { - return refl::equal(lhs, rhs); - }); - } -}; - -template -struct Less { - constexpr static bool less(const LHS& lhs, const RHS& rhs) { - return lhs < rhs; - } -}; - -struct less_t { - template - constexpr static bool operator()(const LHS& lhs, const RHS& rhs) { - return Less::less(lhs, rhs); - } -}; - -constexpr inline less_t less; - -template -struct Less> { - constexpr static bool less(const std::vector& lhs, const std::vector& rhs) { - if(lhs.size() != rhs.size()) { - return lhs.size() < rhs.size(); - } - - for(std::size_t i = 0; i < lhs.size(); ++i) { - if(refl::less(lhs[i], rhs[i])) { - return true; - } - } - - return false; - } -}; - -template -struct Less { - constexpr static bool less(E lhs, E rhs) { - return lhs.value() < rhs.value(); - } -}; - -template - requires (!requires(T lhs, T rhs) { - { lhs < rhs } -> std::convertible_to; - }) -struct Less { - constexpr static bool less(const T& lhs, const T& rhs) { - bool result = false; - foreach(lhs, rhs, [&](const auto& lhs, const auto& rhs) { - /// return false to break the loop. - if(refl::less(lhs, rhs)) { - result = true; - return false; - } - - if(refl::less(rhs, lhs)) { - result = false; - return false; - } - - /// continue the loop. - return true; - }); - return result; - } -}; - -struct less_equal_t { - template - constexpr static bool operator()(const LHS& lhs, const RHS& rhs) { - return equal(lhs, rhs) || less(lhs, rhs); - } -}; - -constexpr inline less_equal_t less_equal; - -} // namespace clice::refl diff --git a/include/Support/Enum.h b/include/Support/Enum.h deleted file mode 100644 index b7e9cbf0..00000000 --- a/include/Support/Enum.h +++ /dev/null @@ -1,301 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "Support/TypeTraits.h" - -namespace clice::refl { - -template - requires std::is_enum_v -constexpr auto underlying_value(T value) { - return static_cast>(value); -} - -template - requires std::is_enum_v -consteval auto enum_name() { - std::string_view name = std::source_location::current().function_name(); -#if __GNUC__ || __clang__ - std::size_t start = name.find('=') + 2; - std::size_t end = name.size() - 1; -#elif _MSC_VER - std::size_t start = name.find('<') + 1; - std::size_t end = name.rfind(">("); -#else - static_assert(false, "Not supported compiler"); -#endif - name = name.substr(start, end - start); - start = name.rfind("::"); - return start == std::string_view::npos ? name : name.substr(start + 2); -} - -template -consteval auto enum_max() { - constexpr auto value = std::bit_cast(static_cast>(N)); - if constexpr(enum_name().find(")") == std::string_view::npos) - return enum_max(); - else - return N; -} - -template -struct enum_table { - constexpr static std::array table = - [](std::index_sequence) { - return std::array{enum_name(Is)>()...}; - }(std::make_index_sequence{}); -}; - -template ()> -constexpr std::string_view enum_name(E value) { - return enum_table::table[static_cast>(value) - begin]; -} - -/// A helper class to define enum. -template -class Enum { -public: - /// Tag to indicate this is a special enum. - constexpr inline static bool reflectable_enum = true; - - using underlying_type = underlying; - - constexpr Enum() : m_Value(invalid()) {} - - /// A integral must explicitly convert to the enum. - explicit constexpr Enum(underlying value) : m_Value(value) {} - - /// Allow the enum to be constructed from the enum value. - template Kind> - constexpr Enum(Kind kind) : m_Value(kind) { - static_assert(sizeof(underlying) >= sizeof(typename Derived::Kind), - "Underlying type is too small to hold all enum values."); - } - - constexpr Enum(const Enum&) = default; - - constexpr Enum& operator=(const Enum&) = default; - - /// Get the underlying value of the enum. - constexpr underlying value() const { - return m_Value; - } - - /// Get the enum value. - constexpr auto kind() const { - return static_cast(m_Value); - } - - /// Get the name of the enum. - constexpr std::string_view name() const { - using E = typename Derived::Kind; - return refl::enum_name(static_cast(m_Value)); - } - - template ... Kinds> - constexpr bool is_one_of(Kinds... kinds) const { - return ((m_Value == underlying_value(kinds)) || ...); - } - - constexpr explicit operator bool() const { - return m_Value != invalid(); - } - - constexpr friend bool operator==(Enum lhs, Enum rhs) = default; - - constexpr static auto& all() { - return enum_table::table; - } - -private: - consteval static underlying begin() { - if constexpr(requires { Derived::FirstEnum; }) { - return Derived::FirstEnum; - } else { - return 0; - } - } - - consteval static underlying end() { - if constexpr(requires { Derived::LastEnum; }) { - return Derived::LastEnum; - } else { - return refl::enum_max(); - } - } - - consteval static underlying invalid() { - if constexpr(requires { Derived::InvalidEnum; }) { - return Derived::InvalidEnum; - } else { - static_assert(dependent_false, "Invalid enum value is not defined."); - } - } - -private: - underlying m_Value; -}; - -template -class Enum { -public: - /// Tag to indicate this is a special enum. - constexpr inline static bool reflectable_enum = true; - - using underlying_type = underlying; - - Enum() = default; - - /// A integral must explicitly convert to the enum. - explicit constexpr Enum(underlying value) : m_Value(value) {} - - /// Allow the enum to be constructed from the enum value. - template ... Kinds> - constexpr Enum(Kinds... kind) : m_Value(((1 << underlying_value(kind)) | ...)) { - static_assert(sizeof(underlying) * 8 >= end(), - "Underlying type is too small to hold all enum values."); - } - - constexpr Enum(const Enum&) = default; - - constexpr Enum& operator=(const Enum&) = default; - - /// Get the underlying value of the enum. - constexpr underlying value() const { - return m_Value; - } - - /// Get the name of the enum. - constexpr std::string name() const { - std::string masks; - bool isFirst = true; - for(std::size_t i = 0; i < sizeof(underlying) * 8; i++) { - bool hasBit = m_Value & (1 << i); - - if(!hasBit) { - continue; - } - - if(isFirst) { - isFirst = false; - } else { - masks += " | "; - } - - using E = typename Derived::Kind; - masks += refl::enum_name(static_cast(i)); - } - return masks; - } - - constexpr static auto& all() { - return enum_table::table; - } - - constexpr explicit operator bool() const { - return m_Value != 0; - } - - constexpr friend bool operator==(Enum lhs, Enum rhs) = default; - - template Kind> - constexpr Enum operator|(Kind kind) const { - return Enum(m_Value | (1 << underlying_value(kind))); - } - - template Kind> - constexpr Enum operator&(Kind kind) const { - return Enum(m_Value & (1 << underlying_value(kind))); - } - - constexpr Enum operator&(Enum e) const { - return Enum(m_Value & e.value()); - } - - template Kind> - constexpr Enum& operator|=(Kind kind) { - m_Value |= (1 << underlying_value(kind)); - return *this; - } - - template Kind> - constexpr Enum& operator&=(Kind kind) { - m_Value &= (1 << underlying_value(kind)); - return *this; - } - - template ... Kinds> - constexpr bool is_one_of(Kinds... kinds) const { - return (((*this) & (kinds)) || ...); - } - -private: - consteval static std::size_t begin() { - if constexpr(requires { Derived::FirstEnum; }) { - return Derived::FirstEnum; - } else { - return 0; - } - } - - consteval static std::size_t end() { - if constexpr(requires { Derived::LastEnum; }) { - return Derived::LastEnum; - } else { - return refl::enum_max(); - } - } - -private: - underlying m_Value = 0; -}; - -template - requires (!integral) -class Enum { -public: - /// Tag to indicate this is a special enum. - constexpr inline static bool reflectable_enum = true; - - using underlying_type = underlying; - - constexpr Enum(underlying value) { - static_assert( - requires { Derived::All; }, - "Derived enum must define all possible enum values."); - - for(auto& element: Derived::All) { - if(element == value) { - m_Value = element; - } - } - - assert(!m_Value.empty() && "Invalid enum value."); - } - - constexpr Enum(const Enum&) = default; - - constexpr friend bool operator==(Enum lhs, Enum rhs) = default; - - constexpr underlying value() const { - return m_Value; - } - -private: - underlying m_Value; -}; - -template -concept reflectable_enum = requires { - T::reflectable_enum; - requires T::reflectable_enum; -}; - -} // namespace clice::refl diff --git a/include/Support/FixedString.h b/include/Support/FixedString.h deleted file mode 100644 index 829c34d1..00000000 --- a/include/Support/FixedString.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include - -namespace clice { - -template -struct fixed_string : std::array { - template - constexpr fixed_string(const char (&str)[M]) { - for(std::size_t i = 0; i < N; ++i) { - this->data()[i] = str[i]; - } - this->data()[N] = '\0'; - } - - constexpr fixed_string(const char* str) { - for(std::size_t i = 0; i < N; ++i) { - this->data()[i] = str[i]; - } - this->data()[N] = '\0'; - } - - constexpr auto size() const { - return N; - } - - constexpr operator std::string_view() const { - return {this->data(), N}; - } -}; - -template -fixed_string(const char (&)[M]) -> fixed_string; - -} // namespace clice diff --git a/include/Support/Format.h b/include/Support/Format.h deleted file mode 100644 index 4d8e8424..00000000 --- a/include/Support/Format.h +++ /dev/null @@ -1,184 +0,0 @@ -#pragma once - -#include -#include - -#include "Support/JSON.h" -#include "Support/Ranges.h" - -#include "llvm/Support/Error.h" - -template <> -struct std::formatter : std::formatter { - using Base = std::formatter; - - template - constexpr auto parse(ParseContext& ctx) { - return Base::parse(ctx); - } - - template - auto format(llvm::StringRef s, FormatContext& ctx) const { - return Base::format(std::string_view(s.str()), ctx); - } -}; - -template -struct std::formatter> : std::formatter { - using Base = std::formatter; - - template - constexpr auto parse(ParseContext& ctx) { - return Base::parse(ctx); - } - - template - auto format(const llvm::SmallString& s, FormatContext& ctx) const { - return Base::format(llvm::StringRef(s), ctx); - } -}; - -template <> -struct std::formatter : std::formatter { - using Base = std::formatter; - - template - constexpr auto parse(ParseContext& ctx) { - return Base::parse(ctx); - } - - template - auto format(const llvm::Error& e, FormatContext& ctx) const { - llvm::SmallString<128> buffer; - llvm::raw_svector_ostream os(buffer); - os << e; - return Base::format(buffer, ctx); - } -}; - -template <> -struct std::formatter : std::formatter { - using Base = std::formatter; - - template - constexpr auto parse(ParseContext& ctx) { - return Base::parse(ctx); - } - - template - auto format(const std::error_code& e, FormatContext& ctx) const { - return Base::format(e.message(), ctx); - } -}; - -template <> -struct std::formatter : std::formatter { - using Base = std::formatter; - - int indent = 0; - - template - constexpr auto parse(ParseContext& ctx) { - auto it = ctx.begin(); - auto end = ctx.end(); - if(it == end) { - return it; - } - - int parsed_indent = 0; - while(it != end && *it >= '0' && *it <= '9') { - parsed_indent = parsed_indent * 10 + (*it - '0'); - ++it; - } - indent = parsed_indent; - - return it; - } - - template - auto format(const clice::json::Value& value, FormatContext& ctx) const { - llvm::SmallString<128> buffer; - llvm::raw_svector_ostream os{buffer}; - llvm::json::OStream(os, indent).value(value); - return Base::format(buffer, ctx); - } -}; - -template -struct std::formatter : std::formatter { - using Base = std::formatter; - - template - constexpr auto parse(ParseContext& ctx) { - return Base::parse(ctx); - } - - template - auto format(const E& e, FormatContext& ctx) const { - return Base::format(e.name(), ctx); - } -}; - -namespace clice { - -/// Dump object to string for debugging. Note that it is not efficient -/// and should not be used except for debugging. -template -std::string dump(const Object& object) { - if constexpr(std::is_fundamental_v) { - return std::format("{}", object); - } else if constexpr(std::is_same_v || - std::is_same_v || - std::is_same_v) { - return std::format("\"{}\"", object); - } else if constexpr(ranges::range) { - constexpr bool is_sequence = sequence_range; - std::string result = is_sequence ? "[" : "{"; - if constexpr(map_range) { - for(auto&& [key, value]: object) { - result += std::format("\"{}\": {}, ", dump(key), dump(value)); - } - } else { - for(auto&& value: object) { - result += std::format("{}, ", dump(value)); - } - } - if(!object.empty()) { - result.pop_back(); - result.pop_back(); - } - result += is_sequence ? "]" : "}"; - return result; - } else if constexpr(std::is_enum_v) { - return std::format("\"{}\"", refl::enum_name(object)); - } else if constexpr(refl::reflectable_enum) { - return std::format("\"{}\"", object); - } else if constexpr(refl::reflectable_struct) { - std::string result = "{"; - refl::foreach(object, [&](auto name, auto value) { - result += std::format("\"{}\": {}, ", name, dump(value)); - }); - if(refl::member_count() != 0) { - result.pop_back(); - result.pop_back(); - } - result += "}"; - return result; - } else { - static_assert(dependent_false, "Cannot dump object"); - } -} - -template -std::string pretty_dump(const Object& object, std::size_t indent = 2) { - std::string repr = dump(object); - auto json = json::parse(repr); - if(!json) { - std::println("{} {}", json.takeError(), repr); - std::abort(); - } - llvm::SmallString<128> buffer = {std::format("{{0:{}}}", indent)}; - return llvm::formatv(buffer.c_str(), *json); -} - -} // namespace clice diff --git a/include/Support/Hash.h b/include/Support/Hash.h deleted file mode 100644 index aafb2a67..00000000 --- a/include/Support/Hash.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include "Struct.h" - -#include "llvm/Support/HashBuilder.h" - -namespace clice::refl { - -template -struct Hash { - static llvm::hash_code hash(const auto& value) { - return llvm::hash_value(value); - } -}; - -template -llvm::hash_code hash(const Value& value) { - return Hash::hash(value); -} - -template -struct Hash> { - static llvm::hash_code hash(const std::vector& value) { - llvm::SmallVector hashes; - hashes.reserve(value.size()); - for(const auto& element: value) { - hashes.emplace_back(refl::hash(element)); - } - return llvm::hash_combine_range(hashes.begin(), hashes.end()); - }; -}; - -template -struct Hash { - static llvm::hash_code hash(const T& value) { - llvm::SmallVector hashes; - foreach(value, [&](auto, const auto& member) { hashes.emplace_back(refl::hash(member)); }); - return llvm::hash_combine_range(hashes.begin(), hashes.end()); - } -}; - -} // namespace clice::refl diff --git a/include/Support/JSON.h b/include/Support/JSON.h deleted file mode 100644 index dffe70bf..00000000 --- a/include/Support/JSON.h +++ /dev/null @@ -1,338 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "Enum.h" -#include "Ranges.h" -#include "Struct.h" -#include "TypeTraits.h" - -#include "llvm/Support/JSON.h" - -namespace clice::json { - -using namespace llvm::json; - -/// Specialize this struct to provide custom serialization and deserialization for a type. -template -struct Serde; - -template -concept serializable = requires { sizeof(Serde); }; - -/// Serialize an object to a JSON value. -template -json::Value serialize(const V& v) { - return Serde::serialize(v); -} - -/// Deserialize a JSON value to an object. -template -T deserialize(const json::Value& value) { - return Serde::deserialize(value); -} - -template <> -struct Serde { - static json::Value serialize(auto&& value) { - return json::Value(std::forward(value)); - } - - static json::Value deserialize(auto&& value) { - return json::Value(std::forward(value)); - } -}; - -template <> -struct Serde { - static json::Value serialize(std::nullptr_t) { - return json::Value(nullptr); - } - - static std::nullptr_t deserialize(const json::Value& value) { - assert(value.kind() == json::Value::Null && "Expect null"); - return nullptr; - } -}; - -template <> -struct Serde { - static json::Value serialize(std::nullopt_t) { - return json::Value(nullptr); - } - - static std::nullopt_t deserialize(const json::Value& value) { - assert(value.kind() == json::Value::Null && "Expect null"); - return std::nullopt; - } -}; - -template <> -struct Serde { - static json::Value serialize(bool v) { - return json::Value(v); - } - - static bool deserialize(const json::Value& value) { - assert(value.kind() == json::Value::Boolean && "Expect boolean"); - return value.getAsBoolean().value(); - } -}; - -template -struct Serde { - static json::Value serialize(I v) { - return json::Value(static_cast(v)); - } - - static I deserialize(const json::Value& value) { - assert(value.kind() == json::Value::Number && "Expect number"); - return static_cast(value.getAsInteger().value()); - } -}; - -template - requires std::is_enum_v -struct Serde { - static json::Value serialize(E v) { - return json::Value(static_cast(v)); - } - - static E deserialize(const json::Value& value) { - assert(value.kind() == json::Value::Number && "Expect number"); - return static_cast(value.getAsInteger().value()); - } -}; - -template -struct Serde { - static json::Value serialize(F v) { - return json::Value(static_cast(v)); - } - - static F deserialize(const json::Value& value) { - assert(value.kind() == json::Value::Number && "Expect number"); - return static_cast(value.getAsNumber().value()); - } -}; - -template <> -struct Serde { - static json::Value serialize(const char* v) { - return json::Value(llvm::StringRef(v)); - } -}; - -template -struct Serde { - static json::Value serialize(const char (&v)[N]) { - return json::Value(llvm::StringRef(v, N)); - } -}; - -template <> -struct Serde { - using V = std::string; - - static json::Value serialize(const V& v) { - return json::Value(v); - } - - static V deserialize(const json::Value& value) { - assert(value.kind() == json::Value::String && "Expect a string"); - return value.getAsString().value().str(); - } -}; - -template <> -struct Serde { - using V = std::string_view; - - static json::Value serialize(const V& v) { - return json::Value(llvm::StringRef(v.data(), v.size())); - } - - static V deserialize(const json::Value& value) { - assert(value.kind() == json::Value::String && "Expect string"); - return value.getAsString().value(); - } -}; - -template <> -struct Serde { - using V = llvm::StringRef; - - static json::Value serialize(const V& v) { - return json::Value(v.str()); - } - - static V deserialize(const json::Value& value) { - assert(value.kind() == json::Value::String && "Expect string"); - return value.getAsString().value(); - } -}; - -template -struct Serde> { - using V = llvm::SmallString; - - static json::Value serialize(const V& v) { - return json::Value(v.str()); - } - - static V deserialize(const json::Value& value) { - assert(value.kind() == json::Value::String && "Expect string"); - return V{value.getAsString().value().str()}; - } -}; - -template -struct Serde { - using key_type = typename Range::key_type; - using mapped_type = typename Range::mapped_type; - - template - static json::Value serialize(const Range& range, Serdes&&... serdes) { - json::Object object; - for(const auto& [key, value]: range) { - if constexpr(std::is_constructible_v) { - object.try_emplace(key, json::serialize(value, std::forward(serdes)...)); - } else { - object.try_emplace( - llvm::formatv("{}", json::serialize(key, std::forward(serdes)...)), - json::serialize(value, std::forward(serdes)...)); - } - } - return object; - } - - template - static Range deserialize(const json::Value& value, Serdes&&... serdes) { - assert(value.kind() == json::Value::Object && "JSON must be object"); - Range range; - for(auto& [name, value]: *value.getAsObject()) { - if constexpr(std::is_constructible_v) { - range.try_emplace( - name, - json::deserialize(value, std::forward(serdes)...)); - } else { - if(auto key = json::parse(name)) { - range.try_emplace( - json::deserialize(std::move(*key), - std::forward(serdes)...), - json::deserialize(value, std::forward(serdes)...)); - } - } - } - return range; - } -}; - -template -struct Serde { - using key_type = typename Range::key_type; - - template - static json::Value serialize(const Range& range, Serdes&&... serdes) { - json::Array array; - for(const auto& element: range) { - array.emplace_back(json::serialize(element, std::forward(serdes)...)); - } - return array; - } - - template - static Range deserialize(const json::Value& value, Serdes&&... serdes) { - assert(value.kind() == json::Value::Array && "JSON must be array"); - Range range; - for(auto& element: *value.getAsArray()) { - range.emplace(json::deserialize(element, std::forward(serdes)...)); - } - return range; - } -}; - -template -struct Serde { - using value_type = typename Range::value_type; - - template - static json::Value serialize(const Range& range, Serdes&&... serdes) { - json::Array array; - for(const auto& element: range) { - array.emplace_back(json::serialize(element, std::forward(serdes)...)); - } - return array; - } - - template - static Range deserialize(const json::Value& value, Serdes&&... serdes) { - assert(value.kind() == json::Value::Array && "JSON must be array"); - Range range; - for(auto& element: *value.getAsArray()) { - range.emplace_back( - json::deserialize(element, std::forward(serdes)...)); - } - return range; - } -}; - -template -struct Serde { - static json::Value serialize(const E& e) { - return json::Value(e.value()); - } - - static E deserialize(const json::Value& value) { - return E(json::deserialize(value)); - } -}; - -template -constexpr inline bool is_optional_v = false; - -template -constexpr inline bool is_optional_v> = true; - -template - requires (!sequence_range) -struct Serde { - template - static json::Value serialize(const T& t) { - json::Object object; - refl::foreach(t, [&](std::string_view name, const Field& field) { - if constexpr(is_optional_v) { - if(field) { - object.try_emplace(llvm::StringRef(name), json::serialize(*field)); - } - } else { - object.try_emplace(llvm::StringRef(name), json::serialize(field)); - } - }); - return object; - } - - template - static T deserialize(const json::Value& value) { - T t = {}; - if constexpr(!std::is_empty_v) { - assert(value.kind() == json::Value::Object && "Expect an object"); - refl::foreach(t, [&](std::string_view name, auto&& member) { - using Field = std::remove_cvref_t; - if(auto v = value.getAsObject()->get(llvm::StringRef(name))) { - if constexpr(is_optional_v) { - member.emplace(json::deserialize(*v)); - } else { - member = json::deserialize(*v); - } - } - }); - } - return t; - } -}; - -} // namespace clice::json diff --git a/include/Support/Ranges.h b/include/Support/Ranges.h deleted file mode 100644 index cf44025d..00000000 --- a/include/Support/Ranges.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include - -namespace clice { - -namespace ranges = std::ranges; -namespace views = std::views; - -enum class RangeKind { - Map = 0, - Set, - Sequence, - Invalid, -}; - -template -constexpr inline RangeKind range_kind = [] { - if constexpr(std::same_as>>) { - return RangeKind::Invalid; - } else if constexpr(requires { typename Range::key_type; }) { - if constexpr(requires { typename Range::mapped_type; }) { - return RangeKind::Map; - } else { - return RangeKind::Set; - } - } else { - return RangeKind::Sequence; - } -}(); - -template -concept map_range = ranges::input_range && range_kind == RangeKind::Map; - -template -concept set_range = ranges::input_range && range_kind == RangeKind::Set; - -template -concept sequence_range = ranges::input_range && range_kind == RangeKind::Sequence; - -} // namespace clice diff --git a/include/Support/Struct.h b/include/Support/Struct.h deleted file mode 100644 index 524dfe16..00000000 --- a/include/Support/Struct.h +++ /dev/null @@ -1,377 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "Support/TypeTraits.h" - -namespace clice::refl { - -namespace impl { - -struct Any { - consteval Any(std::size_t); - - template - consteval operator T() const; -}; - -template -consteval auto test() { - return [](std::index_sequence) { - return requires { T{Any(I)...}; }; - }(std::make_index_sequence{}); -} - -template -consteval auto member_count() { - if constexpr(test() && !test()) { - return N; - } else { - return member_count(); - } -} - -template -struct wrapper { - T value; - - constexpr wrapper(T value) : value(value) {} -}; - -template -union storage_t { - char dummy; - T value; - - storage_t() {} - - ~storage_t() {} -}; - -template -inline storage_t storage; - -template -consteval auto member_name() { - std::string_view name = std::source_location::current().function_name(); -#if __GNUC__ && (!__clang__) && (!_MSC_VER) - std::size_t start = name.rfind("::") + 2; - std::size_t end = name.rfind(')'); - name = name.substr(start, end - start); -#elif __clang__ - std::size_t start = name.rfind(".") + 1; - std::size_t end = name.rfind('}'); - name = name.substr(start, end - start); -#elif _MSC_VER - std::size_t start = name.rfind("->") + 2; - std::size_t end = name.rfind('}'); - name = name.substr(start, end - start); -#else - static_assert(false, "Not supported compiler"); -#endif - if(name.rfind("::") != std::string_view::npos) { - name = name.substr(name.rfind("::") + 2); - } - return name; -} - -template -constexpr inline auto to_string_literal_impl = [] { - if constexpr(N == 0) { - return std::array{'0', '\0'}; - } else { - constexpr auto length = [] { - std::size_t result = 0; - for(std::size_t n = N; n; n /= 10) { - ++result; - } - return result; - }(); - - std::array result = {}; - std::size_t n = N; - for(std::size_t i = length; i; n /= 10, i--) { - result[i - 1] = '0' + n % 10; - } - result[length] = '\0'; - return result; - } -}(); - -} // namespace impl - -template -constexpr std::string_view to_string_literal() { - return {impl::to_string_literal_impl.data()}; -} - -template -struct Struct; - -/// To check if the type is reflectable_struct. -template -concept reflectable_struct = Struct>::reflectable_struct; - -/// Get the member count of the type. -template -constexpr static std::size_t member_count() { - return Struct>::member_count; -} - -/// Get the all member names of the type. -template -constexpr static auto& member_names() { - return Struct>::member_names; -} - -/// Get the member name of the type at index N. -template -constexpr static std::string_view member_name() { - return member_names()[N]; -} - -/// Get the member types of the type. -template -constexpr decltype(auto) member_value(T&& object) { - return *std::get(Struct>::collect_members(object)); -} - -template -using member_types = - tuple_to_list_t::collect_members(std::declval())), std::remove_pointer_t>; - -template -using member_type = std::tuple_element_t::to_tuple>; - -template -concept TupleLike = requires { std::tuple_size::value; }; - -/// Specialize for aggregate class. -template - requires std::is_aggregate_v && (!TupleLike) -struct Struct { - constexpr inline static bool reflectable_struct = true; - - constexpr inline static auto member_count = impl::member_count(); - - template - constexpr static auto collect_members(Object&& object) { - // clang-format off - if constexpr (member_count == 0) { - return std::tuple{}; - } else if constexpr (member_count == 1) { - auto&& [e1] = object; - return std::tuple{ &e1 }; - } else if constexpr (member_count == 2) { - auto&& [e1, e2] = object; - return std::tuple{ &e1, &e2 }; - } else if constexpr (member_count == 3) { - auto&& [e1, e2, e3] = object; - return std::tuple{ &e1, &e2, &e3 }; - } else if constexpr (member_count == 4) { - auto&& [e1, e2, e3, e4] = object; - return std::tuple{ &e1, &e2, &e3, &e4 }; - } else if constexpr (member_count == 5) { - auto&& [e1, e2, e3, e4, e5] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5 }; - } else if constexpr (member_count == 6) { - auto&& [e1, e2, e3, e4, e5, e6] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6 }; - } else if constexpr (member_count == 7) { - auto&& [e1, e2, e3, e4, e5, e6, e7] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7 }; - } else if constexpr (member_count == 8) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8 }; - } else if constexpr (member_count == 9) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9 }; - } else if constexpr (member_count == 10) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10 }; - } else if constexpr (member_count == 11) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11 }; - } else if constexpr (member_count == 12) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12 }; - } else if constexpr (member_count == 13) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13 }; - } else if constexpr (member_count == 14) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14 }; - } else if constexpr (member_count == 15) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15 }; - } else if constexpr (member_count == 16) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16 }; - } else if constexpr (member_count == 17) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17 }; - } else if constexpr (member_count == 18) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18 }; - } else if constexpr (member_count == 19) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19 }; - } else if constexpr (member_count == 20) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20 }; - } else if constexpr (member_count == 21) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21 }; - } else if constexpr (member_count == 22) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22 }; - } else if constexpr (member_count == 23) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23 }; - } else if constexpr (member_count == 24) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24 }; - } else if constexpr (member_count == 25) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25 }; - } else if constexpr (member_count == 26) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26 }; - } else if constexpr (member_count == 27) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27 }; - } else if constexpr (member_count == 28) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27, &e28 }; - } else if constexpr (member_count == 29) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27, &e28, &e29 }; - } else if constexpr (member_count == 30) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27, &e28, &e29, &e30 }; - } else if constexpr (member_count == 31) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27, &e28, &e29, &e30, &e31 }; - } else if constexpr (member_count == 32) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31, e32] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27, &e28, &e29, &e30, &e31, &e32 }; - } else if constexpr (member_count == 33) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31, e32, e33] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27, &e28, &e29, &e30, &e31, &e32, &e33 }; - } else if constexpr (member_count == 34) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31, e32, e33, e34] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27, &e28, &e29, &e30, &e31, &e32, &e33, &e34 }; - } else if constexpr (member_count == 35) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31, e32, e33, e34, e35] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27, &e28, &e29, &e30, &e31, &e32, &e33, &e34, &e35 }; - } else if constexpr (member_count == 36) { - auto&& [e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12, e13, e14, e15, e16, e17, e18, e19, e20, e21, e22, e23, e24, e25, e26, e27, e28, e29, e30, e31, e32, e33, e34, e35, e36] = object; - return std::tuple{ &e1, &e2, &e3, &e4, &e5, &e6, &e7, &e8, &e9, &e10, &e11, &e12, &e13, &e14, &e15, &e16, &e17, &e18, &e19, &e20, &e21, &e22, &e23, &e24, &e25, &e26, &e27, &e28, &e29, &e30, &e31, &e32, &e33, &e34, &e35, &e36 }; - } else { - // For counts greater than 36, trigger a compile-time error - static_assert(member_count <= 36, "Not supported member count"); - } - // clang-format on - } - - constexpr inline static auto member_names = [](std::index_sequence) { - if constexpr(member_count == 0) { - return std::array{}; - } else { - constexpr auto members = collect_members(impl::storage.value); - return std::array{impl::member_name(members)>()...}; - } - }(std::make_index_sequence{}); -}; - -template -struct Inheritance : Ts... {}; - -/// Use to define a reflectable_struct struct with inheritance. -#define inherited_struct(name, ...) \ - struct name##Body; \ - using name = clice::refl::Inheritance<__VA_ARGS__, name##Body>; \ - struct name##Body - -template -struct Struct> { - constexpr inline static bool reflectable_struct = (refl::reflectable_struct && ...); - - constexpr static std::size_t member_count = (impl::member_count() + ...); - - template - constexpr static auto collect_members(Object&& object) { - if constexpr(std::is_const_v>) { - return std::tuple_cat(Struct::collect_members(static_cast(object))...); - } else { - return std::tuple_cat(Struct::collect_members(static_cast(object))...); - } - } - - constexpr inline static auto member_names = [](std::index_sequence) { - if constexpr(member_count == 0) { - return std::array{}; - } else { - constexpr auto members = collect_members(impl::storage>.value); - return std::array{impl::member_name(members)>()...}; - } - }(std::make_index_sequence{}); -}; - -template -struct Struct { - constexpr inline static bool reflectable_struct = true; - - constexpr inline static std::size_t member_count = std::tuple_size_v; - - template - constexpr static auto collect_members(Object&& object) { - return std::apply([](auto&&... args) { return std::tuple{&args...}; }, object); - } - - constexpr inline static auto member_names = [](std::index_sequence) { - if constexpr(member_count == 0) { - return std::array{}; - } else { - return std::array{to_string_literal()...}; - } - }(std::make_index_sequence{}); -}; - -/// Turn the return value of the callable to bool. -template -constexpr auto foldable(const Callable& callable) { - return [&](auto&&... args) { - using Ret = std::invoke_result_t; - if constexpr(std::is_void_v) { - callable(args...); - return true; - } else { - return bool(callable(args...)); - } - }; -} - -template -constexpr bool foreach(Object&& object, const Callback& callback) { - auto foldable = refl::foldable(callback); - return [&](std::index_sequence) { - return (foldable(refl::member_name(), refl::member_value(object)) && ...); - }(std::make_index_sequence()>{}); -} - -/// Invoke callback for each member of lhs and rhs, return false -/// in callback to abort the iteration. Return true if all members are visited. -template -constexpr bool foreach(LHS&& lhs, RHS&& rhs, const Callback& callback) { - static_assert(member_count() == member_count(), "Member count mismatch"); - auto foldable = refl::foldable(callback); - return [&](std::index_sequence) { - return (foldable(refl::member_value(lhs), refl::member_value(rhs)) && ...); - }(std::make_index_sequence()>{}); -} - -} // namespace clice::refl diff --git a/include/Support/TypeTraits.h b/include/Support/TypeTraits.h deleted file mode 100644 index d6b8f3e0..00000000 --- a/include/Support/TypeTraits.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once - -#include -#include - -namespace clice { - -template -struct identity { - using type = T; -}; - -template -using identity_t = T; - -template -struct type_list { - constexpr static auto apply(auto&& lambda) { - return lambda.template operator()(); - } - - using to_tuple = std::tuple; -}; - -/// Turn a tuple into a type list. -/// @param Tuple The tuple to convert. -/// @param Map The mapping function to apply to each type in the tuple. -/// @param isalias If isalias is false, mapping result is `typename Map::type`. -template typename Map = identity_t, bool isalias = true> -struct tuple_to_list; - -template typename Map> -struct tuple_to_list, Map, true> { - using type = type_list...>; -}; - -template typename Map> -struct tuple_to_list, Map, false> { - using type = type_list::type...>; -}; - -template typename Map = identity_t, bool isalias = true> -using tuple_to_list_t = typename tuple_to_list::type; - -template -struct tuple_uniuqe { - using type = Tuple; -}; - -/// Uniuqe the types in the tuple. -template -using tuple_uniuqe_t = typename tuple_uniuqe::type; - -template - requires (!std::is_same_v && ...) -struct tuple_uniuqe> { - using type = decltype(std::tuple_cat(std::declval>(), - std::declval>>())); -}; - -template - requires (std::is_same_v || ...) -struct tuple_uniuqe> { - using type = tuple_uniuqe_t>; -}; - -template -struct replace_cv_ref; - -template -struct replace_cv_ref { - using type = Target&; -}; - -template -struct replace_cv_ref { - using type = Target&&; -}; - -template -struct replace_cv_ref { - using type = const Target&; -}; - -template -struct replace_cv_ref { - using type = const Target&&; -}; - -/// Replace the cv-qualifiers and reference of Source with Target. -/// For example, `replace_cv_ref_t` is `const double&`. -template -using replace_cv_ref_t = typename replace_cv_ref::type; - -template typename HKT> -constexpr bool is_specialization_of = false; - -template