some update.

This commit is contained in:
ykiko
2024-07-25 13:00:31 +08:00
parent 0d1a663928
commit 8fe633bc92
14 changed files with 205 additions and 20 deletions

View File

@@ -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();
}

View File

@@ -4,6 +4,12 @@
namespace clice {
inline auto createCompilerInvocation() {}
inline CompilerInvocation createCompilerInvocation() {
}
inline CompilerInstance createCompilerInstance() {
}
} // namespace clice

View File

@@ -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

View File

View File

View File

View File

View File

View File

View File

View File

View 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";
};
```

View File

@@ -1,4 +0,0 @@

View File

@@ -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);
}