some update.
This commit is contained in:
@@ -1,8 +1,76 @@
|
||||
#include <Clang/Clang.h>
|
||||
#include <filesystem>
|
||||
#include <clang/Basic/Diagnostic.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/Frontend/FrontendActions.h>
|
||||
#include <clang/Frontend/TextDiagnosticPrinter.h>
|
||||
#include <clang/Sema/Sema.h>
|
||||
#include <clang/Tooling/CompilationDatabase.h>
|
||||
#include <clang/Tooling/Syntax/Tokens.h>
|
||||
#include <clang/Lex/PreprocessorOptions.h>
|
||||
#include <clang/Tooling/DependencyScanning/DependencyScanningTool.h>
|
||||
|
||||
namespace clice {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
assert(argc == 2 && "Usage: Preamble <source-file>");
|
||||
llvm::outs() << "running Preamble...\n";
|
||||
|
||||
|
||||
std::vector<const char*> args = {
|
||||
"/home/ykiko/Project/C++/clice/external/llvm/bin/clang++",
|
||||
"-Xclang",
|
||||
"-no-round-trip-args",
|
||||
"-std=c++20",
|
||||
argv[1],
|
||||
"-c",
|
||||
};
|
||||
|
||||
auto instance = std::make_unique<clang::CompilerInstance>();
|
||||
|
||||
auto invocation = std::make_shared<clang::CompilerInvocation>();
|
||||
invocation = clang::createInvocation(args, {});
|
||||
invocation->getFrontendOpts();
|
||||
|
||||
auto tmp = llvm::MemoryBuffer::getFile(argv[1]);
|
||||
if(auto error = tmp.getError()) {
|
||||
llvm::errs() << "Failed to get file: " << error.message() << "\n";
|
||||
std::terminate();
|
||||
}
|
||||
llvm::MemoryBuffer* buffer = tmp->release();
|
||||
|
||||
auto VFS = llvm::vfs::getRealFileSystem();
|
||||
auto bounds = clang::ComputePreambleBounds(invocation->getLangOpts(), *buffer, false);
|
||||
|
||||
instance->setInvocation(std::move(invocation));
|
||||
|
||||
instance->createDiagnostics(
|
||||
new clang::TextDiagnosticPrinter(llvm::errs(), new clang::DiagnosticOptions()),
|
||||
true);
|
||||
|
||||
/// NOTICE: if preamble is stored in memory, the code below is necessary
|
||||
if(auto VFSWithRemapping =
|
||||
createVFSFromCompilerInvocation(instance->getInvocation(), instance->getDiagnostics(), VFS))
|
||||
VFS = VFSWithRemapping;
|
||||
instance->createFileManager(VFS);
|
||||
|
||||
if(!instance->createTarget()) {
|
||||
llvm::errs() << "Failed to create target\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
clang::SyntaxOnlyAction action;
|
||||
|
||||
auto& mainInput = instance->getFrontendOpts().Inputs[0];
|
||||
if(!action.BeginSourceFile(*instance, mainInput)) {
|
||||
llvm::errs() << "Failed to begin source file\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
if(auto error = action.Execute()) {
|
||||
llvm::errs() << "Failed to execute action: " << error << "\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
instance->getASTContext().getTranslationUnitDecl()->dump();
|
||||
|
||||
action.EndSourceFile();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
namespace clice {
|
||||
|
||||
inline auto createCompilerInvocation() {}
|
||||
inline CompilerInvocation createCompilerInvocation() {
|
||||
|
||||
}
|
||||
|
||||
inline CompilerInstance createCompilerInstance() {
|
||||
|
||||
}
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace clice::protocol {
|
||||
using Integer = int;
|
||||
using UInteger = unsigned int;
|
||||
using String = std::string;
|
||||
using StringRef = std::string_view;
|
||||
|
||||
template <typename... Ts>
|
||||
struct Combine : Ts... {};
|
||||
@@ -23,6 +24,8 @@ private:
|
||||
public:
|
||||
};
|
||||
|
||||
using DocumentUri = String;
|
||||
|
||||
/// Position in a text document expressed as zero-based line and zero-based character offset.
|
||||
struct Position {
|
||||
/// line position in a document (zero-based).
|
||||
@@ -45,7 +48,7 @@ struct Range {
|
||||
/// An item to transfer a text document from the client to the server.
|
||||
struct TextDocumentItem {
|
||||
/// The text document's URI.
|
||||
URI uri;
|
||||
DocumentUri uri;
|
||||
|
||||
/// The text document's language identifier.
|
||||
String languageId;
|
||||
@@ -61,7 +64,16 @@ struct TextDocumentItem {
|
||||
/// Text documents are identified using a URI.
|
||||
struct TextDocumentIdentifier {
|
||||
/// The text document's URI.
|
||||
URI uri;
|
||||
DocumentUri uri;
|
||||
};
|
||||
|
||||
/// A parameter literal used in requests to pass a text document and a position inside that document.
|
||||
struct TextDocumentPositionParams {
|
||||
/// The text document.
|
||||
TextDocumentIdentifier textDocument;
|
||||
|
||||
/// The position inside the text document.
|
||||
Position position;
|
||||
};
|
||||
|
||||
/// A textual edit applicable to a text document.
|
||||
@@ -140,21 +152,29 @@ struct Diagnostic {
|
||||
// TODO: std::vector<DiagnosticRelatedInformation> relatedInformation;
|
||||
};
|
||||
|
||||
/// A parameter literal used in requests to pass a text document and a position inside that document.
|
||||
struct TextDocumentPositionParams {
|
||||
/// The text document.
|
||||
TextDocumentIdentifier textDocument;
|
||||
/// Represents a reference to a command.
|
||||
struct Command {
|
||||
/// Title of the command, like `save`.
|
||||
String title;
|
||||
|
||||
/// The position inside the text document.
|
||||
Position position;
|
||||
/// The identifier of the actual command handler.
|
||||
String command;
|
||||
|
||||
/// Arguments that the command handler should be invoked with.
|
||||
/// arguments?: LSPAny[];
|
||||
};
|
||||
|
||||
using DocumentUri = String;
|
||||
struct MarkupKind {
|
||||
StringRef m_Value;
|
||||
|
||||
MarkupKind(StringRef value) : m_Value(value) {}
|
||||
|
||||
/// Plain text is supported as a content format
|
||||
constexpr inline static StringRef PlainText = "plaintext";
|
||||
|
||||
// value set ['plaintext', 'markdown']
|
||||
using MarkupKind = String;
|
||||
/// Markdown is supported as a content format
|
||||
constexpr inline static StringRef Markdown = "markdown";
|
||||
};
|
||||
|
||||
struct MarkupContent {
|
||||
/// The type of the Markup
|
||||
|
||||
0
include/Protocol/Document/DidChange.h
Normal file
0
include/Protocol/Document/DidChange.h
Normal file
0
include/Protocol/Document/DidClose.h
Normal file
0
include/Protocol/Document/DidClose.h
Normal file
0
include/Protocol/Document/DidOpen.h
Normal file
0
include/Protocol/Document/DidOpen.h
Normal file
0
include/Protocol/Document/DidSave.h
Normal file
0
include/Protocol/Document/DidSave.h
Normal file
0
include/Protocol/Lifecycle/Exit.h
Normal file
0
include/Protocol/Lifecycle/Exit.h
Normal file
0
include/Protocol/Lifecycle/Initialize.h
Normal file
0
include/Protocol/Lifecycle/Initialize.h
Normal file
0
include/Protocol/Lifecycle/Initialized.h
Normal file
0
include/Protocol/Lifecycle/Initialized.h
Normal file
0
include/Protocol/Lifecycle/Shutdown.h
Normal file
0
include/Protocol/Lifecycle/Shutdown.h
Normal file
93
include/Protocol/README.md
Normal file
93
include/Protocol/README.md
Normal file
@@ -0,0 +1,93 @@
|
||||
This file dictionary mainly describes the [Language Server Protocol Specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/). Every interface in the protocol is defined as corresponding struct.
|
||||
|
||||
For example, [Position](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#position) has the following definition in the protocol:
|
||||
|
||||
```typescript
|
||||
interface Position {
|
||||
line: uinteger;
|
||||
character: uinteger;
|
||||
}
|
||||
```
|
||||
|
||||
then the corresponding representation in C++ is:
|
||||
|
||||
```cpp
|
||||
struct Position {
|
||||
uinteger line;
|
||||
uinteger character;
|
||||
};
|
||||
```
|
||||
|
||||
We use template meta programming to reflect the protocol type so that the serialization and deserialization can be done automatically. The trick is only suitable for type which is aggregate and default constructible and does not have base classes. But there are many types in the protocol which are defined through inheritance. For example, [DeclarationParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#declarationParams) is defined as:
|
||||
|
||||
```typescript
|
||||
export interface DeclarationParams extends TextDocumentPositionParams,
|
||||
WorkDoneProgressParams, PartialResultParams {
|
||||
}
|
||||
```
|
||||
|
||||
We use `Combine` to resolve the problem. `Combine` is defined as:
|
||||
|
||||
```cpp
|
||||
template<typename... Ts>
|
||||
struct Combine : Ts... {};
|
||||
```
|
||||
|
||||
Then `DeclarationParams` can be defined as:
|
||||
|
||||
```cpp
|
||||
using DeclarationParams = Combine<
|
||||
TextDocumentPositionParams,
|
||||
WorkDoneProgressParams,
|
||||
PartialResultParams
|
||||
>;
|
||||
```
|
||||
|
||||
Compared to direct inheritance, this way allows us to get the base class types of `DeclarationParams`. If the interface also has data members, you should define a struct to hold the data members separately and add it to `Combine` list.
|
||||
|
||||
For example, we have [ReferenceParams](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#referenceParams) definition as follow:
|
||||
|
||||
```typescript
|
||||
export interface ReferenceParams extends TextDocumentPositionParams,
|
||||
WorkDoneProgressParams, PartialResultParams {
|
||||
context: ReferenceContext;
|
||||
}
|
||||
```
|
||||
|
||||
Then we can define `ReferenceParams` as:
|
||||
|
||||
```cpp
|
||||
struct ReferenceParamsBody {
|
||||
ReferenceContext context;
|
||||
};
|
||||
|
||||
using ReferenceParams = Combine<
|
||||
TextDocumentPositionParams,
|
||||
WorkDoneProgressParams,
|
||||
PartialResultParams,
|
||||
ReferenceParamsBody
|
||||
>;
|
||||
```
|
||||
|
||||
For number enum in TypeScript, it can define as corresponding `enum` in C++ directly, for string enum, we define it as `struct` with `static` members.
|
||||
|
||||
```typescript
|
||||
export namespace MarkupKind {
|
||||
export const PlainText: 'plaintext' = 'plaintext';
|
||||
export const Markdown: 'markdown' = 'markdown';
|
||||
}
|
||||
export type MarkupKind = 'plaintext' | 'markdown';
|
||||
```
|
||||
|
||||
```cpp
|
||||
struct MarkupKind {
|
||||
std::string_view m_value;
|
||||
|
||||
constexpr MarkupKind(std::string_view value) : m_value(value) {}
|
||||
|
||||
constexpr inline static std::string_view PlainText = "plaintext";
|
||||
constexpr inline static std::string_view Markdown = "markdown";
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
@@ -54,7 +54,9 @@ std::unique_ptr<ParsedAST> ParsedAST::build(std::string_view path,
|
||||
logger::error("Failed to execute action: {0}", llvm::errorToErrorCode(std::move(error)).message());
|
||||
}
|
||||
|
||||
AST->tokens.construct(std::move(collector).consume());
|
||||
|
||||
|
||||
// AST->tokens.construct(std::move(collector).consume());
|
||||
|
||||
return std::unique_ptr<ParsedAST>(AST);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user