Skip to content

Commit cfbbe6f

Browse files
committed
chore: LSP Server
1 parent 431c8b0 commit cfbbe6f

File tree

7 files changed

+1380
-125
lines changed

7 files changed

+1380
-125
lines changed

packages/cxx-gen-lsp/src/gen_requests_cc.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,23 +88,63 @@ class RequestGenerator {
8888
}
8989

9090
if (isRequest(request) && request.result) {
91-
const resultTypeName = typeName.replace(/Request$/, "Response");
91+
const responseTypeName = typeName.replace(/Request$/, "Response");
92+
const resultTypeName = toCppType(request.result);
93+
9294
this.emit();
93-
this.emit(`auto ${resultTypeName}::id() const -> std::variant<long, std::string> {`);
95+
this.emit(`auto ${responseTypeName}::id() const -> std::variant<long, std::string> {`);
9496
this.emit(` const auto& id = repr_->at("id");`);
9597
this.emit(` if (id.is_string()) return id.get<std::string>();`);
9698
this.emit(` return id.get<long>();`);
9799
this.emit(`}`);
98100
this.emit();
99-
this.emit(`auto ${resultTypeName}::id(long id) -> ${resultTypeName}& {`);
101+
this.emit(`auto ${responseTypeName}::id(long id) -> ${responseTypeName}& {`);
100102
this.emit(` (*repr_)["id"] = id;`);
101103
this.emit(` return *this;`);
102104
this.emit(`}`);
103105
this.emit();
104-
this.emit(`auto ${resultTypeName}::id(std::string id) -> ${resultTypeName}& {`);
106+
this.emit(`auto ${responseTypeName}::id(std::string id) -> ${responseTypeName}& {`);
105107
this.emit(` (*repr_)["id"] = std::move(id);`);
106108
this.emit(` return *this;`);
107109
this.emit(`}`);
110+
this.emit();
111+
this.emit(`auto ${responseTypeName}::result() const -> ${resultTypeName} {`);
112+
switch (request.result.kind) {
113+
case "base": {
114+
if (request.result.name === "null") {
115+
this.emit(` return nullptr;`);
116+
} else {
117+
this.emit(` return repr_->at("result").get<${toCppType(request.result)}>(); // base`);
118+
}
119+
break;
120+
}
121+
122+
case "reference": {
123+
if (this.structByName.has(request.result.name)) {
124+
this.emit(` if (!repr_->contains("result")) (*repr_)["result"] = nullptr;`);
125+
this.emit(` return ${resultTypeName}(repr_->at("result")); // reference`);
126+
} else {
127+
this.emit(` lsp_runtime_error("${responseTypeName}::result() - not implemented yet");`);
128+
}
129+
break;
130+
}
131+
132+
default: {
133+
this.emit(` lsp_runtime_error("${responseTypeName}::result() - not implemented yet");`);
134+
}
135+
} // swtch
136+
this.emit(`}`);
137+
this.emit();
138+
this.emit(`auto ${responseTypeName}::result(${resultTypeName} result) -> ${responseTypeName}& {`);
139+
switch (request.result.kind) {
140+
case "base":
141+
this.emit(` (*repr_)["result"] = std::move(result); // base`);
142+
break;
143+
default:
144+
this.emit(` lsp_runtime_error("${responseTypeName}::result() - not implemented yet");`);
145+
} // switch
146+
this.emit(` return *this;`);
147+
this.emit(`}`);
108148
}
109149
});
110150

packages/cxx-gen-lsp/src/gen_requests_h.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,22 @@ export function gen_requests_h({ model, outputDirectory }: { model: MetaModel; o
4444

4545
const requestsAndNotifications: Array<Request | Notification> = [...model.requests, ...model.notifications];
4646

47+
emit();
48+
emit(`#define FOR_EACH_LSP_REQUEST_TYPE(V) \\`);
49+
model.requests.forEach((request, index) => {
50+
const nameWithoutSuffix = request.typeName.replace(/Request$/, "");
51+
const sep = index + 1 < model.requests.length ? " \\" : "";
52+
emit(` V(${nameWithoutSuffix}, "${request.method}")${sep}`);
53+
});
54+
55+
emit();
56+
emit(`#define FOR_EACH_LSP_NOTIFICATION_TYPE(V) \\`);
57+
model.notifications.forEach((notification, index) => {
58+
const nameWithoutSuffix = notification.typeName.replace(/Notification$/, "");
59+
const sep = index + 1 < model.notifications.length ? " \\" : "";
60+
emit(` V(${nameWithoutSuffix}, "${notification.method}")${sep}`);
61+
});
62+
4763
requestsAndNotifications.forEach((request) => {
4864
const typeName = request.typeName;
4965
emit();
@@ -89,6 +105,35 @@ export function gen_requests_h({ model, outputDirectory }: { model: MetaModel; o
89105
}
90106
});
91107

108+
emit();
109+
emit(`template <typename Visitor>`);
110+
emit(`auto visitRequest(Visitor&& visitor, const LSPRequest& request, const std::string_view& method) -> void {`);
111+
emit(`#define PROCESS_REQUEST_TYPE(NAME, METHOD) \\`);
112+
emit(` if (method == METHOD) \\`);
113+
emit(` return visitor(static_cast<const NAME##Request&>(request));`);
114+
emit();
115+
emit(`FOR_EACH_LSP_REQUEST_TYPE(PROCESS_REQUEST_TYPE)`);
116+
emit();
117+
emit(`#undef PROCESS_REQUEST_TYPE`);
118+
emit();
119+
emit(` lsp_runtime_error("unknown request type");`);
120+
emit(`}`);
121+
emit();
122+
emit(`template <typename Visitor>`);
123+
emit(
124+
`auto visitNotification(Visitor&& visitor, const LSPRequest& notification, const std::string_view& method) -> void {`,
125+
);
126+
emit(`#define PROCESS_NOTIFICATION_TYPE(NAME, METHOD) \\`);
127+
emit(` if (method == METHOD) \\`);
128+
emit(` return visitor(static_cast<const NAME##Notification&>(notification));`);
129+
emit();
130+
emit(`FOR_EACH_LSP_NOTIFICATION_TYPE(PROCESS_NOTIFICATION_TYPE)`);
131+
emit();
132+
emit(`#undef PROCESS_NOTIFICATION_TYPE`);
133+
emit();
134+
emit(` lsp_runtime_error("unknown notification type");`);
135+
emit(`}`);
136+
92137
emit();
93138
emit(`}`);
94139

src/frontend/cxx/frontend.cc

Lines changed: 2 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <format>
4141

4242
#include "ast_printer.h"
43+
#include "lsp_server.h"
4344
#include "verify_diagnostics_client.h"
4445

4546
// std
@@ -292,124 +293,6 @@ auto runOnFile(const CLI& cli, const std::string& fileName) -> bool {
292293
return !diagnosticsClient.hasErrors();
293294
}
294295

295-
auto startServer(const CLI& cli) -> bool {
296-
Control control;
297-
VerifyDiagnosticsClient diagnosticsClient;
298-
TranslationUnit unit(&control, &diagnosticsClient);
299-
300-
auto preprocesor = unit.preprocessor();
301-
302-
std::unique_ptr<Toolchain> toolchain;
303-
304-
if (cli.opt_verify) {
305-
diagnosticsClient.setVerify(true);
306-
preprocesor->setCommentHandler(&diagnosticsClient);
307-
}
308-
309-
auto toolchainId = cli.getSingle("-toolchain");
310-
311-
if (!toolchainId) {
312-
toolchainId = "wasm32";
313-
}
314-
315-
if (toolchainId == "darwin" || toolchainId == "macos") {
316-
toolchain = std::make_unique<MacOSToolchain>(preprocesor);
317-
} else if (toolchainId == "wasm32") {
318-
auto wasmToolchain = std::make_unique<Wasm32WasiToolchain>(preprocesor);
319-
320-
fs::path app_dir;
321-
322-
#if __wasi__
323-
app_dir = fs::path("/usr/bin/");
324-
#elif !defined(CXX_NO_FILESYSTEM)
325-
app_dir = std::filesystem::canonical(
326-
std::filesystem::path(cli.app_name).remove_filename());
327-
#elif __unix__ || __APPLE__
328-
char* app_name = realpath(cli.app_name.c_str(), nullptr);
329-
app_dir = fs::path(app_name).remove_filename().string();
330-
std::free(app_name);
331-
#endif
332-
333-
wasmToolchain->setAppdir(app_dir.string());
334-
335-
if (auto paths = cli.get("--sysroot"); !paths.empty()) {
336-
wasmToolchain->setSysroot(paths.back());
337-
} else {
338-
auto sysroot_dir = app_dir / std::string("../lib/wasi-sysroot");
339-
wasmToolchain->setSysroot(sysroot_dir.string());
340-
}
341-
342-
toolchain = std::move(wasmToolchain);
343-
} else if (toolchainId == "linux") {
344-
std::string host;
345-
#ifdef __aarch64__
346-
host = "aarch64";
347-
#elif __x86_64__
348-
host = "x86_64";
349-
#endif
350-
351-
std::string arch = cli.getSingle("-arch").value_or(host);
352-
toolchain = std::make_unique<GCCLinuxToolchain>(preprocesor, arch);
353-
} else if (toolchainId == "windows") {
354-
auto windowsToolchain = std::make_unique<WindowsToolchain>(preprocesor);
355-
356-
if (auto paths = cli.get("-vctoolsdir"); !paths.empty()) {
357-
windowsToolchain->setVctoolsdir(paths.back());
358-
}
359-
360-
if (auto paths = cli.get("-winsdkdir"); !paths.empty()) {
361-
windowsToolchain->setWinsdkdir(paths.back());
362-
}
363-
364-
if (auto versions = cli.get("-winsdkversion"); !versions.empty()) {
365-
windowsToolchain->setWinsdkversion(versions.back());
366-
}
367-
368-
toolchain = std::move(windowsToolchain);
369-
}
370-
371-
if (toolchain) {
372-
control.setMemoryLayout(toolchain->memoryLayout());
373-
374-
if (!cli.opt_nostdinc) toolchain->addSystemIncludePaths();
375-
376-
if (!cli.opt_nostdincpp) toolchain->addSystemCppIncludePaths();
377-
378-
toolchain->addPredefinedMacros();
379-
}
380-
381-
for (const auto& path : cli.get("-I")) {
382-
preprocesor->addSystemIncludePath(path);
383-
}
384-
385-
if (cli.opt_v) {
386-
std::cerr << std::format("#include <...> search starts here:\n");
387-
const auto& paths = preprocesor->systemIncludePaths();
388-
for (auto it = rbegin(paths); it != rend(paths); ++it) {
389-
std::cerr << std::format(" {}\n", *it);
390-
}
391-
std::cerr << std::format("End of search list.\n");
392-
}
393-
394-
for (const auto& macro : cli.get("-D")) {
395-
auto sep = macro.find_first_of("=");
396-
397-
if (sep == std::string::npos) {
398-
preprocesor->defineMacro(macro, "1");
399-
} else {
400-
preprocesor->defineMacro(macro.substr(0, sep), macro.substr(sep + 1));
401-
}
402-
}
403-
404-
for (const auto& macro : cli.get("-U")) {
405-
preprocesor->undefMacro(macro);
406-
}
407-
408-
std::cerr << "Starting LSP server" << std::endl;
409-
410-
return true;
411-
}
412-
413296
} // namespace
414297

415298
auto main(int argc, char* argv[]) -> int {
@@ -434,9 +317,7 @@ auto main(int argc, char* argv[]) -> int {
434317
int existStatus = EXIT_SUCCESS;
435318

436319
if (cli.opt_lsp) {
437-
if (!startServer(cli)) {
438-
existStatus = EXIT_FAILURE;
439-
}
320+
existStatus = lsp::startServer(cli);
440321
} else {
441322
for (const auto& fileName : inputFiles) {
442323
if (!runOnFile(cli, fileName)) {

0 commit comments

Comments
 (0)