#pragma once #include #include "Async.h" #include "llvm/ADT/StringMap.h" #include "Compiler/Compiler.h" namespace clice { class ASTInfo; struct File; struct Task { /// Whether this task is a build task. bool isBuild = false; /// The coroutine handle of this task. std::coroutine_handle<> waiting; }; struct File { bool isIdle = true; /// The compiler instance of this file. ASTInfo compiler; std::deque waitings; }; class Scheduler { public: async::promise updatePCH(llvm::StringRef path, llvm::StringRef content, llvm::ArrayRef args); async::promise updatePCM() { co_return; } async::promise buildAST(llvm::StringRef path, llvm::StringRef content); async::promise add(llvm::StringRef path, llvm::StringRef content); async::promise update(llvm::StringRef path, llvm::StringRef content); async::promise save(llvm::StringRef path); async::promise close(llvm::StringRef path); /// Schedule a task for a file. If the file is building, the task will be /// appended to the task list of the file and wait for the building to finish. /// Otherwise, the task will be executed immediately. template auto schedule(llvm::StringRef path, Task&& task) -> async::promise()))> { auto& file = files[path]; if(!file.isIdle) { co_await async::suspend([&](auto handle) { file.waitings.push_back({.isBuild = false, .waiting = handle}); }); } file.isIdle = false; auto& compiler = file.compiler; auto result = co_await async::schedule_task([&task, &compiler] { return task(compiler); }); if(!file.waitings.empty()) { auto task = std::move(file.waitings.front()); async::schedule(task.waiting); file.waitings.pop_front(); } file.isIdle = true; co_return result; } private: llvm::StringMap pchs; llvm::StringMap files; }; } // namespace clice