From 939dbc3dc51292a657ce852f67cae94944d4d912 Mon Sep 17 00:00:00 2001 From: ykiko Date: Wed, 27 Nov 2024 23:21:52 +0800 Subject: [PATCH] Refactor `log`. --- docs/design/SemanticTokens-example.cpp | 28 ---- docs/feature/SemanticTokens-example.cpp | 61 +++++++++ include/Compiler/Semantic.h | 7 +- include/Server/Async.h | 92 +++++++------ include/Server/Logger.h | 35 +++-- include/Support/Format.h | 26 +++- src/Feature/SemanticTokens.cpp | 67 ++++++++++ src/Server/Async.cpp | 60 ++++----- src/Server/Config.cpp | 8 +- src/Server/Server.cpp | 4 +- src/Server/Transport.cpp | 165 ------------------------ tests/ASTVisitor/test.cpp | 14 +- 12 files changed, 273 insertions(+), 294 deletions(-) delete mode 100644 docs/design/SemanticTokens-example.cpp create mode 100644 docs/feature/SemanticTokens-example.cpp delete mode 100644 src/Server/Transport.cpp diff --git a/docs/design/SemanticTokens-example.cpp b/docs/design/SemanticTokens-example.cpp deleted file mode 100644 index 3c0f2c84..00000000 --- a/docs/design/SemanticTokens-example.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// This is an example file that shows the usage of semantic tokens. -// clang-format off - - - char character = 'a'; -// ^ ^ -// keyword character - - int number = 1; -// ^ ^ -// keyword number - - const char* string = "Hello, World!"; -// ^ ^ -// keyword string - - #pragma once -// ^ ^ -// directive pragma - - #include -// ^ ^ -// directive header - - #define MAX 100 -// ^ ^ -// directive macro - diff --git a/docs/feature/SemanticTokens-example.cpp b/docs/feature/SemanticTokens-example.cpp new file mode 100644 index 00000000..8bb69c6a --- /dev/null +++ b/docs/feature/SemanticTokens-example.cpp @@ -0,0 +1,61 @@ +/* + * Block comment + */ +#include +#include + +#define STRINGIFY(x) #x + +using namespace std; // line comment + +namespace foo { + +typedef struct Struct { + int field; +} Typedef; + +enum Enum { Foo = 1, Bar = 2 }; + +Typedef* globalVar; +extern Typedef* externVar; + +template +class Class { + T n; + +public: + /** + */ + void function(int param1, int param2, int param3) { + int localVar1, localVar2, localVar3; + int* localVar = new int[1]; + std::vector vec = {1, 2, 3}; + this->n = N; + localVar1 = param1 + param2 + localVar3; + + label: + printf("Formatted string %d\n\g", localVar[0]); + printf(R"**(Formatted raw-string %d\n)**", 1); + +/** + * Macro documentation comment + * @param A description + */ +#define FOO(A) A +#ifdef DEBUG + printf("debug"); +#endif + } +}; + +template +concept Concept = requires(T t) { t.field; }; + +template +struct Widget { + Widget(T t); +}; + +template +Widget(T) -> Widget; +} // namespace foo diff --git a/include/Compiler/Semantic.h b/include/Compiler/Semantic.h index bb220bac..a5b2d5fa 100644 --- a/include/Compiler/Semantic.h +++ b/include/Compiler/Semantic.h @@ -59,8 +59,8 @@ public: using Base = clang::RecursiveASTVisitor; SemanticVisitor(Compiler& compiler, bool mainFileOnly = false) : - sema(compiler.sema()), resolver(compiler.resolver()), srcMgr(compiler.srcMgr()), - tokBuf(compiler.tokBuf()), mainFileOnly(mainFileOnly) {} + sema(compiler.sema()), pp(compiler.pp()), resolver(compiler.resolver()), + srcMgr(compiler.srcMgr()), tokBuf(compiler.tokBuf()), mainFileOnly(mainFileOnly) {} public: @@ -548,11 +548,12 @@ public: } protected: + bool mainFileOnly; clang::Sema& sema; + clang::Preprocessor& pp; TemplateResolver& resolver; clang::SourceManager& srcMgr; clang::syntax::TokenBuffer& tokBuf; - bool mainFileOnly; llvm::SmallVector decls; }; diff --git a/include/Server/Async.h b/include/Server/Async.h index bc7f065c..29e7cef8 100644 --- a/include/Server/Async.h +++ b/include/Server/Async.h @@ -6,6 +6,8 @@ #include "llvm/ADT/FunctionExtras.h" #include "llvm/Support/raw_ostream.h" +#include "Server/Logger.h" + #include "Support/JSON.h" #include @@ -25,6 +27,11 @@ struct promise; extern uv_loop_t* loop; +#define uv_check_call(func, ...) \ + if(int error = func(__VA_ARGS__); error < 0) { \ + log::fatal("An error occurred in " #func ": {0}", uv_strerror(error)); \ + } + template T& uv_cast(U* u) { assert(u && u->data && "uv_cast: invalid uv handle"); @@ -79,12 +86,15 @@ inline void schedule(std::coroutine_handle<> handle) { assert(handle && "schedule: invalid coroutine handle"); uv_async_t* async = new uv_async_t(); async->data = handle.address(); - uv_async_init(loop, async, [](uv_async_t* async) { + + auto callback = [](uv_async_t* async) { auto handle = std::coroutine_handle<>::from_address(async->data); handle.resume(); uv_close((uv_handle_t*)async, [](uv_handle_t* handle) { delete handle; }); - }); - uv_async_send(async); + }; + + uv_check_call(uv_async_init, loop, async, callback); + uv_check_call(uv_async_send, async); } template @@ -101,22 +111,23 @@ struct task_awaiter : result { static_assert(!std::is_reference_v, "return type must not be a reference"); this->caller = caller; uv_work_t* work = new uv_work_t{.data = this}; - uv_queue_work( - loop, - work, - [](uv_work_t* work) { - auto& awaiter = uv_cast(work); - if constexpr(!std::is_void_v) { - new (&awaiter.value) Ret(awaiter.task()); - } else { - awaiter.task(); - } - }, - [](uv_work_t* work, int status) { - auto& awaiter = uv_cast(work); - awaiter.caller.resume(); - delete work; - }); + + auto work_cb = [](uv_work_t* work) { + auto& awaiter = uv_cast(work); + if constexpr(!std::is_void_v) { + new (&awaiter.value) Ret(awaiter.task()); + } else { + awaiter.task(); + } + }; + + auto after_work_cb = [](uv_work_t* work, int status) { + auto& awaiter = uv_cast(work); + awaiter.caller.resume(); + delete work; + }; + + uv_check_call(uv_queue_work, loop, work, work_cb, after_work_cb); } }; @@ -137,16 +148,15 @@ struct sleep_awaiter { void await_suspend(std::coroutine_handle<> caller) noexcept { this->caller = caller; uv_timer_t* timer = new uv_timer_t{.data = this}; - uv_timer_init(loop, timer); - uv_timer_start( - timer, - [](uv_timer_t* timer) { - auto& awaiter = uv_cast(timer); - awaiter.caller.resume(); - uv_close((uv_handle_t*)timer, [](uv_handle_t* handle) { delete handle; }); - }, - ms.count(), - 0); + uv_check_call(uv_timer_init, loop, timer); + + auto callback = [](uv_timer_t* timer) { + auto& awaiter = uv_cast(timer); + awaiter.caller.resume(); + uv_close((uv_handle_t*)timer, [](uv_handle_t* handle) { delete handle; }); + }; + + uv_check_call(uv_timer_start, timer, callback, ms.count(), 0); } void await_resume() noexcept {} @@ -168,25 +178,25 @@ struct fs_awaiter { void await_suspend(std::coroutine_handle<> caller) noexcept { this->caller = caller; uv_fs_t* req = new uv_fs_t{.data = this}; - uv_fs_open(loop, req, path.c_str(), UV_FS_O_RDONLY, 0, [](uv_fs_t* req) { + + auto callback = [](uv_fs_t* req) { auto& awaiter = uv_cast(req); if(req->result < 0) { - llvm::errs() << "Error: " << uv_strerror(req->result) << "\n"; + log::fatal("An error occurred while opening file: {0}", uv_strerror(req->result)); awaiter.caller.resume(); delete req; return; } - uv_fs_close(loop, req, req->result, [](uv_fs_t* req) { - auto& awaiter = uv_cast(req); - uv_timespec_t& mtime = req->statbuf.st_mtim; - using namespace std::chrono; - awaiter.modified = - system_clock::time_point(seconds(mtime.tv_sec) + nanoseconds(mtime.tv_nsec)); - awaiter.caller.resume(); - delete req; - }); - }); + uv_timespec_t& mtime = req->statbuf.st_mtim; + using namespace std::chrono; + awaiter.modified = + system_clock::time_point(seconds(mtime.tv_sec) + nanoseconds(mtime.tv_nsec)); + awaiter.caller.resume(); + delete req; + }; + + uv_check_call(uv_fs_open, loop, req, path.c_str(), UV_FS_O_RDONLY, 0, callback); } decltype(auto) await_resume() noexcept { diff --git a/include/Server/Logger.h b/include/Server/Logger.h index c3af42b2..621c4b04 100644 --- a/include/Server/Logger.h +++ b/include/Server/Logger.h @@ -2,16 +2,16 @@ #include #include -#include +#include namespace clice::log { enum class Level { INFO, - ERROR, WARN, DEBUG, TRACE, + FATAL, }; template @@ -21,11 +21,11 @@ void log(Level level, std::string_view fmt, Args&&... args) { auto time = chrono::zoned_time(chrono::current_zone(), now); auto tag = [&] { switch(level) { - case Level::INFO: return "\033[32mINFO\033[0m"; // Green - case Level::ERROR: return "\033[31mERROR\033[0m"; // Red - case Level::WARN: return "\033[33mWARN\033[0m"; // Yellow - case Level::DEBUG: return "\033[36mDEBUG\033[0m"; // Cyan - case Level::TRACE: return "\033[35mTRACE\033[0m"; // Magenta + case Level::INFO: return "\033[32mINFO\033[0m"; // Green + case Level::WARN: return "\033[33mWARN\033[0m"; // Yellow + case Level::DEBUG: return "\033[36mDEBUG\033[0m"; // Cyan + case Level::TRACE: return "\033[35mTRACE\033[0m"; // Magenta + case Level::FATAL: return "\033[31mFATAL ERROR\033[0m"; // Red } }(); llvm::errs() << std::format("[{0:%Y-%m-%d %H:%M:%S}] [{1}] ", time, tag) @@ -37,14 +37,25 @@ void info(std::format_string fmt, Args&&... args) { log::log(Level::INFO, fmt.get(), std::forward(args)...); } -template -void error(std::format_string fmt, Args&&... args) { - log::log(Level::ERROR, fmt.get(), std::forward(args)...); -} - template void warn(std::format_string fmt, Args&&... args) { log::log(Level::WARN, fmt.get(), std::forward(args)...); } +template +void debug(std::format_string fmt, Args&&... args) { + log::log(Level::DEBUG, fmt.get(), std::forward(args)...); +} + +template +void trace(std::format_string fmt, Args&&... args) { + log::log(Level::TRACE, fmt.get(), std::forward(args)...); +} + +template +void fatal [[noreturn]] (std::format_string fmt, Args&&... args) { + log::log(Level::FATAL, fmt.get(), std::forward(args)...); + std::terminate(); +} + } // namespace clice::log diff --git a/include/Support/Format.h b/include/Support/Format.h index a410c629..f7bac512 100644 --- a/include/Support/Format.h +++ b/include/Support/Format.h @@ -3,16 +3,38 @@ #include #include "llvm/ADT/StringRef.h" +#include "Error.h" template <> struct std::formatter : std::formatter { + using Base = std::formatter; + template constexpr auto parse(ParseContext& ctx) { - return std::formatter::parse(ctx); + return Base::parse(ctx); } template auto format(llvm::StringRef s, FormatContext& ctx) const { - return std::formatter::format(std::string_view(s.str()), ctx); + 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::Error& e, FormatContext& ctx) const { + llvm::SmallString<128> buffer; + llvm::raw_svector_ostream os(buffer); + os << e; + return Base::format(buffer, ctx); + } +}; + diff --git a/src/Feature/SemanticTokens.cpp b/src/Feature/SemanticTokens.cpp index d20b2050..4f668005 100644 --- a/src/Feature/SemanticTokens.cpp +++ b/src/Feature/SemanticTokens.cpp @@ -613,6 +613,73 @@ public: } proto::SemanticTokens build() { + /// Collect semantic from spelled tokens. + auto mainFileID = srcMgr.getMainFileID(); + auto spelledTokens = tokBuf.spelledTokens(mainFileID); + for(auto& token: spelledTokens) { + proto::SemanticTokenType type = proto::SemanticTokenType::Invalid; + llvm::outs() << clang::tok::getTokenName(token.kind()) << " " + << pp.getIdentifierInfo(token.text(srcMgr))->isKeyword(pp.getLangOpts()) + << "\n"; + + auto kind = token.kind(); + switch(kind) { + case clang::tok::numeric_constant: { + type = proto::SemanticTokenType::Number; + break; + } + + case clang::tok::char_constant: + case clang::tok::wide_char_constant: + case clang::tok::utf8_char_constant: + case clang::tok::utf16_char_constant: + case clang::tok::utf32_char_constant: { + type = proto::SemanticTokenType::Character; + break; + } + + case clang::tok::string_literal: + case clang::tok::wide_string_literal: + case clang::tok::utf8_string_literal: + case clang::tok::utf16_string_literal: + case clang::tok::utf32_string_literal: { + type = proto::SemanticTokenType::String; + break; + } + + case clang::tok::ampamp: /// and + case clang::tok::ampequal: /// and_eq + case clang::tok::amp: /// bitand + case clang::tok::pipe: /// bitor + case clang::tok::tilde: /// compl + case clang::tok::exclaim: /// not + case clang::tok::exclaimequal: /// not_eq + case clang::tok::pipepipe: /// or + case clang::tok::pipeequal: /// or_eq + case clang::tok::caret: /// xor + case clang::tok::caretequal: { /// xor_eq + /// Clang will lex above keywords as corresponding operators. But we want to + /// highlight them as keywords. So check whether their text is same as the + /// operator spelling. If not, it indicates that they are keywords. + if(token.text(srcMgr) != clang::tok::getPunctuatorSpelling(kind)) { + type = proto::SemanticTokenType::Operator; + } + } + + default: { + if(pp.getIdentifierInfo(token.text(srcMgr))->isKeyword(pp.getLangOpts())) { + type = proto::SemanticTokenType::Keyword; + break; + } + } + } + + if(type != proto::SemanticTokenType::Invalid) { + addToken(token.location(), type); + } + } + + /// Collect semantic tokens from AST. TraverseAST(sema.getASTContext()); proto::SemanticTokens result; diff --git a/src/Server/Async.cpp b/src/Server/Async.cpp index 96b5a724..8338a2cd 100644 --- a/src/Server/Async.cpp +++ b/src/Server/Async.cpp @@ -64,12 +64,12 @@ void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { async::schedule(callback(std::move(*json))); buffer.consume(); } else { - llvm::errs() << "JSON PARSE ERROR " << json.takeError() << "\n"; + log::fatal("An error occurred while parsing JSON: {0}", json.takeError()); } } } else if(nread < 0) { if(nread != UV_EOF) { - fprintf(stderr, "Error reading from stdin: %s\n", uv_strerror(nread)); + log::fatal("An error occurred while reading: {0}", uv_strerror(nread)); } uv_close((uv_handle_t*)stream, NULL); } @@ -84,9 +84,16 @@ void start_server(Callback callback) { async::callback = std::move(callback); writer = reinterpret_cast(&out); - int r = uv_read_start((uv_stream_t*)&in, async::on_alloc, async::on_read); + uv_check_call(uv_pipe_init, async::loop, &in, 0); + uv_check_call(uv_pipe_init, async::loop, &out, 0); - uv_run(async::loop, UV_RUN_DEFAULT); + uv_check_call(uv_pipe_open, &in, 0); + uv_check_call(uv_pipe_open, &out, 1); + + uv_check_call(uv_read_start, (uv_stream_t*)&in, async::on_alloc, async::on_read); + + log::info("Server started in pipe mode"); + uv_check_call(uv_run, async::loop, UV_RUN_DEFAULT); } void start_server(Callback callback, const char* ip, unsigned int port) { @@ -96,28 +103,27 @@ void start_server(Callback callback, const char* ip, unsigned int port) { async::callback = std::move(callback); writer = reinterpret_cast(&client); - uv_tcp_init(async::loop, &server); - uv_tcp_init(async::loop, &client); + uv_check_call(uv_tcp_init, async::loop, &server); + uv_check_call(uv_tcp_init, async::loop, &client); - struct sockaddr_in addr; - uv_ip4_addr(ip, port, &addr); + struct ::sockaddr_in addr; + uv_check_call(uv_ip4_addr, ip, port, &addr); + uv_check_call(uv_tcp_bind, &server, (const struct sockaddr*)&addr, 0); - uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); - int r = uv_listen((uv_stream_t*)&server, 128, [](uv_stream_t* server, int status) { + auto on_connection = [](uv_stream_t* server, int status) { if(status < 0) { - llvm::errs() << "New connection error\n"; - return; + log::fatal("An error occurred while listening: {0}", uv_strerror(status)); } - if(uv_accept(server, (uv_stream_t*)&client) == 0) { - llvm::errs() << "Client connected.\n"; - uv_read_start((uv_stream_t*)&client, async::on_alloc, async::on_read); - } else { - uv_close((uv_handle_t*)&client, NULL); - } - }); + uv_check_call(uv_accept, server, (uv_stream_t*)&client); + log::info("New connection accepted"); + uv_check_call(uv_read_start, (uv_stream_t*)&client, async::on_alloc, async::on_read); + }; - uv_run(async::loop, UV_RUN_DEFAULT); + uv_check_call(uv_listen, (uv_stream_t*)&server, 128, on_connection); + + log::info("Server started in socket mode at {0}:{1}", ip, port); + uv_check_call(uv_run, async::loop, UV_RUN_DEFAULT); } void write(json::Value id, json::Value result) { @@ -128,11 +134,13 @@ void write(json::Value id, json::Value result) { }; struct Buffer { + uv_write_t req; llvm::SmallString<128> header; llvm::SmallString<4096> message; }; Buffer* buffer = new Buffer(); + buffer->req.data = buffer; llvm::raw_svector_ostream os(buffer->message); os << response; @@ -145,23 +153,15 @@ void write(json::Value id, json::Value result) { uv_buf_init(buffer->message.data(), buffer->message.size()), }; - uv_write_t* req = new uv_write_t(); - req->data = buffer; - auto on_write = [](uv_write_t* req, int status) { if(status < 0) { - llvm::errs() << "Write error: " << uv_strerror(status) << "\n"; + log::fatal("An error occurred while writing: {0}", uv_strerror(status)); } delete static_cast(req->data); - delete req; }; - int r = uv_write(req, writer, bufs, 2, on_write); - - if(r) { - llvm::errs() << "Write error: " << uv_strerror(r) << "\n"; - } + uv_check_call(uv_write, &buffer->req, writer, bufs, 2, on_write); } } // namespace clice::async diff --git a/src/Server/Config.cpp b/src/Server/Config.cpp index bb191963..0571ee7e 100644 --- a/src/Server/Config.cpp +++ b/src/Server/Config.cpp @@ -68,10 +68,9 @@ std::string replace(std::string_view text) { int parse(llvm::StringRef execute, llvm::StringRef filepath) { auto toml = toml::parse_file(filepath); if(toml.failed()) { - llvm::errs() << std::format("Failed to parse config file: {}, Beacuse {}\n", - filepath, - toml.error().description()); - return -1; + log::fatal("Failed to parse config file: {0}, Beacuse {1}", + filepath, + toml.error().description()); } auto table = toml["server"]; @@ -88,7 +87,6 @@ int parse(llvm::StringRef execute, llvm::StringRef filepath) { config.server.address = address.as_string()->get(); } - llvm::outs() << "Server:" << json::serialize(config.server) << "\n"; } return 0; diff --git a/src/Server/Server.cpp b/src/Server/Server.cpp index 101f825b..884e68eb 100644 --- a/src/Server/Server.cpp +++ b/src/Server/Server.cpp @@ -54,14 +54,14 @@ void Server::run(int argc, const char** argv) { co_await iter->second(std::move(*id), params ? std::move(*params) : json::Value(nullptr)); } else { - log::error("Unknown request: {0}", name.str()); + log::warn("Unknown request: {0}", name.str()); } } else { if(auto iter = notifications.find(name); iter != notifications.end()) { log::info("Notification: {0}", name.str()); co_await iter->second(params ? std::move(*params) : json::Value(nullptr)); } else { - log::error("Unknown notification: {0}", name.str()); + log::warn("Unknown notification: {0}", name.str()); } } } diff --git a/src/Server/Transport.cpp b/src/Server/Transport.cpp deleted file mode 100644 index 9243a485..00000000 --- a/src/Server/Transport.cpp +++ /dev/null @@ -1,165 +0,0 @@ - -#include -#include -#include - -#include -#include -#include - -namespace clice { - -void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { - static llvm::SmallString<4096> buffer; - buffer.resize_for_overwrite(suggested_size); - buf->base = buffer.data(); - buf->len = suggested_size; -} - -void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - if(nread > 0) { - printf("Received from stdin: %.*s", (int)nread, buf->base); - } else if(nread < 0) { - if(nread != UV_EOF) { - fprintf(stderr, "Error reading from stdin: %s\n", uv_strerror(nread)); - } - uv_close((uv_handle_t*)stream, NULL); - } -} - -void on_write(uv_write_t* req, int status) { - if(status < 0) { - fprintf(stderr, "Write error: %s\n", uv_strerror(status)); - } else { - printf("Write completed successfully.\n"); - } - free(req); -} - -void test_pipe(const char* data) { - static uv_pipe_t stdin_pipe; - static uv_pipe_t stdout_pipe; - - auto loop = uv_default_loop(); - uv_pipe_init(loop, &stdin_pipe, 0); - uv_pipe_open(&stdin_pipe, 0); - - uv_pipe_init(loop, &stdout_pipe, 0); - uv_pipe_open(&stdout_pipe, 1); - - uv_read_start((uv_stream_t*)&stdin_pipe, on_alloc_buffer, on_read); - - uv_buf_t buf = uv_buf_init((char*)data, strlen(data)); - uv_write_t* write_req = (uv_write_t*)malloc(sizeof(uv_write_t)); - uv_write(write_req, (uv_stream_t*)&stdout_pipe, &buf, 1, on_write); -} - -void test_socket(const char* data) { - static uv_loop_t* loop = uv_default_loop(); - static uv_tcp_t server; - static uv_tcp_t client; - - uv_tcp_init(loop, &server); - uv_tcp_init(loop, &client); - - sockaddr_in addr; - uv_ip4_addr("0.0.0.0", 7000, &addr); - uv_tcp_bind(&server, (const sockaddr*)&addr, 0); - - int r = uv_listen((uv_stream_t*)&server, 128, [](uv_stream_t* server, int status) { - if(status < 0) { - fprintf(stderr, "New connection error\n"); - return; - } - - if(uv_accept(server, (uv_stream_t*)&client) == 0) { - printf("Client connected.\n"); - uv_read_start((uv_stream_t*)&client, on_alloc_buffer, on_read); - } else { - uv_close((uv_handle_t*)&client, NULL); - } - }); - - if(r) { - fprintf(stderr, "Listen error: %s\n", uv_strerror(r)); - } - - uv_buf_t buf = uv_buf_init((char*)data, strlen(data)); - uv_write_t* write_req = (uv_write_t*)malloc(sizeof(uv_write_t)); - uv_write(write_req, (uv_stream_t*)&client, &buf, 1, on_write); -} - -void test_thread_pool() { - uv_loop_t* loop = uv_default_loop(); - uv_work_t* work = new uv_work_t(); - auto work_cb = [](uv_work_t* req) { - // in thread pool - printf("Hello from thread pool.\n"); - }; - auto after_work_cb = [](uv_work_t* req, int status) { - /// in main thread - printf("Thread pool work completed.\n"); - free(req); - }; - uv_queue_work(loop, work, work_cb, after_work_cb); -} - -void test_fs_event() { - uv_loop_t* loop = uv_default_loop(); - uv_fs_event_t fs_event; - uv_fs_event_init(loop, &fs_event); - auto on_fs_event = [](uv_fs_event_t* handle, const char* filename, int events, int status) { - if(status < 0) { - fprintf(stderr, "Error: %s\n", uv_strerror(status)); - return; - } - - char path[1024]; - size_t size = sizeof(path); - int ret = uv_fs_event_getpath(handle, path, &size); - - if(ret == 0) { - path[size] = '\0'; - printf("File change detected in: %s\n", path); - } else { - fprintf(stderr, "Failed to get path: %s\n", uv_strerror(ret)); - } - - if(filename) { - printf(" Affected file: %s\n", filename); - } - - if(events & UV_RENAME) { - printf(" Event: File renamed\n"); - } - if(events & UV_CHANGE) { - printf(" Event: File changed\n"); - } - }; - - const char* path = "./watched_dir"; - int ret = uv_fs_event_start(&fs_event, on_fs_event, path, 0); - if(ret < 0) { - fprintf(stderr, "Failed to start file watcher: %s\n", uv_strerror(ret)); - } -} - -void test_event_loop() { - auto on_prepare = [](uv_prepare_t* handle) { - static int count = 0; - printf("Prepare callback: count = %d\n", count++); - if(count >= 5) { - uv_prepare_stop(handle); - } - }; - - uv_loop_t* loop = uv_default_loop(); - uv_prepare_t prepare_handle; - uv_prepare_init(loop, &prepare_handle); - - uv_prepare_start(&prepare_handle, on_prepare); -} - -} // namespace clice - - diff --git a/tests/ASTVisitor/test.cpp b/tests/ASTVisitor/test.cpp index 2e603ef0..434d78d6 100644 --- a/tests/ASTVisitor/test.cpp +++ b/tests/ASTVisitor/test.cpp @@ -1,7 +1,9 @@ -void foo [[gnu::format(printf, 1, 3)]] (const char* s, char* buf, ...); +void test(int and x); -void __attribute__((__format__(printf, 1, 3))) bar(const char* s, char* buf, ...); - -void foo2(int x) { - if(x < 3) [[unlikely]] {} -} +// void foo [[gnu::format(printf, 1, 3)]] (const char* s, char* buf, ...); +// +// void __attribute__((__format__(printf, 1, 3))) bar(const char* s, char* buf, ...); +// +// void foo2(int x) { +// if(x < 3) [[unlikely]] {} +// }