Skip to content

Commit

Permalink
nixd-next: switch to nixd-next (#327)
Browse files Browse the repository at this point in the history
This is the final implementation for #283, and it is also tracked by it.

Fixes: #283
  • Loading branch information
inclyc committed Feb 12, 2024
2 parents e6dedde + 2d0c8a0 commit 299c4a1
Show file tree
Hide file tree
Showing 191 changed files with 5,076 additions and 12,994 deletions.
1 change: 1 addition & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Checks: >
performance-*,
portability-*,
readability-*,
-readability-use-anyofallof,
-misc-const-correctness,
-misc-unused-parameters,
-misc-non-private-member-variables-in-classes,
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- uses: cachix/install-nix-action@v22
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- run: nix develop --command meson setup build/ --buildtype=${{ matrix.buildtype }} -Db_sanitize=${{ matrix.sanitizer }} -Db_ndebug=${{ matrix.ndebug }}
- run: nix develop --command meson setup build/ -Dwerror=true --buildtype=${{ matrix.buildtype }} -Db_sanitize=${{ matrix.sanitizer }} -Db_ndebug=${{ matrix.ndebug }}
- run: nix develop --command meson compile -C build
- run: nix develop --command meson test -C build
- uses: actions/upload-artifact@v3
Expand All @@ -46,7 +46,7 @@ jobs:
- uses: cachix/install-nix-action@v22
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- run: nix develop .#llvm --command env CXX=clang++ meson setup build/ --buildtype=${{ matrix.buildtype }} -Db_sanitize=${{ matrix.sanitizer }} -Db_ndebug=${{ matrix.ndebug }}
- run: nix develop .#llvm --command env CXX=clang++ meson setup build/ -Dwerror=true --buildtype=${{ matrix.buildtype }} -Db_sanitize=${{ matrix.sanitizer }} -Db_ndebug=${{ matrix.ndebug }}
- run: nix develop .#llvm --command meson compile -C build
- run: nix develop .#llvm --command meson test -C build
- uses: actions/upload-artifact@v3
Expand Down
2 changes: 1 addition & 1 deletion Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -2642,7 +2642,7 @@ INCLUDED_BY_GRAPH = NO
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.

CALL_GRAPH = YES
CALL_GRAPH = NO

# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
# dependency graph for every global function or class method.
Expand Down
47 changes: 6 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
</p>
</div>

# WIP Note 🚧

This branch (`nixd-next`) is still WIP! Please see https://github.com/nix-community/nixd/issues/283 for the migration plan.

The [main](https://github.com/nix-community/nixd/tree/main) branch contains stable nixd codes.

## About

This is a Nix language server that directly uses (i.e., is linked with) the official Nix library (https://github.com/NixOS/nix).
Expand Down Expand Up @@ -82,44 +88,3 @@ We have tested some working & reproducible [editor environments](/nixd/docs/edit
- [Configuration Examples](nixd/docs/examples)
- [Developers' Manual](nixd/docs/dev.md) (internal design, contributing):
- Project matrix room: https://matrix.to/#/#nixd:matrix.org

## Project Structure

```
.
├── default.nix
├── flake.lock
├── flake.nix
├── LICENSE
├── lspserver # The C++ library for writing LSP servers.
├── meson.build
├── nixd # Modularized nixd components, test suite, and tools (binary)
│ ├── docs # Documentation
│ ├── include # General header files
│ ├── lib
│ │ ├── AST # AST library for nix expressions, static analysis (rename, completion, location, range) & evaluation bindings.
│ │ ├── Expr # Expressions library (single AST nodes) with name lookups, locations, ...
│ │ ├── meson.build
│ │ ├── Nix # Extension to NixOS/nix
│ │ ├── Parser # Extension to the parser from NixOS/nix. with ranges support & error handling.
│ │ ├── Server # The nixd server library with controller (the process interacting with clients) and multiple workers (option, eval).
│ │ └── Support
│ ├── meson.build
│ ├── test # Library tests. (rarely used)
│ └── tools
│ ├── meson.build
│ ├── nix-ast-dump # Dump nix AST from the offical parser (NixOS/nix)
│ │ ├── meson.build
│ │ ├── nix-ast-dump.cpp
│ │ └── test
│ ├── nixd # The nixd binary (entry point)
│ │ ├── meson.build
│ │ ├── nixd.cpp
│ │ └── test # The regression tests.
│ └── nixd-ast-dump # Dump the AST nodes parsed from the extended parser, check leaks & memory safety.
│ ├── meson.build
│ ├── nixd-ast-dump.cpp
│ └── test
└── README.md
```
2 changes: 1 addition & 1 deletion default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ stdenv.mkDerivation {
# Disable nixd regression tests, because it uses some features provided by
# nix, and does not correctly work in the sandbox
meson test --print-errorlogs server regression/nix-ast-dump
meson test --print-errorlogs unit/libnixf/Basic unit/libnixf/Parse unit/libnixt regression/nixd
runHook postCheck
'';

Expand Down
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
export NIX_DEBUG_INFO_DIRS=${nix.debug}/lib/debug
export NIX_SRC=${nix.src}
'';
hardeningDisable = [ "fortify" ];
};
in
{
Expand Down
56 changes: 37 additions & 19 deletions libnixf/include/nixf/Basic/Diagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,20 @@ namespace nixf {
/// 1. Insertions: special `OldRange` that `Begin` == `End`.
/// 2. Removals: empty `NewText`.
class TextEdit {
RangeTy OldRange;
LexerCursorRange OldRange;
std::string NewText;

public:
TextEdit(RangeTy OldRange, std::string NewText)
TextEdit(LexerCursorRange OldRange, std::string NewText)
: OldRange(OldRange), NewText(std::move(NewText)) {
assert(OldRange.begin() != OldRange.end() || !this->NewText.empty());
assert(OldRange.lCur() != OldRange.rCur() || !this->NewText.empty());
}

static TextEdit mkInsertion(Point P, std::string NewText) {
static TextEdit mkInsertion(LexerCursor P, std::string NewText) {
return {{P, P}, std::move(NewText)};
}

static TextEdit mkRemoval(RangeTy RemovingRange) {
static TextEdit mkRemoval(LexerCursorRange RemovingRange) {
return {RemovingRange, ""};
}

Expand All @@ -48,10 +48,10 @@ class TextEdit {
[[nodiscard]] bool isRemoval() const { return NewText.empty(); }

[[nodiscard]] bool isInsertion() const {
return OldRange.begin() == OldRange.end();
return OldRange.lCur() == OldRange.rCur();
}

[[nodiscard]] RangeTy oldRange() const { return OldRange; }
[[nodiscard]] LexerCursorRange oldRange() const { return OldRange; }
[[nodiscard]] std::string_view newText() const { return NewText; }
};

Expand All @@ -72,6 +72,11 @@ class Fix {
[[nodiscard]] const std::string &message() const { return Message; }
};

enum class DiagnosticTag {
Faded,
Striked,
};

class PartialDiagnostic {
public:
[[nodiscard]] virtual const char *message() const = 0;
Expand All @@ -87,10 +92,24 @@ class PartialDiagnostic {

[[nodiscard]] const std::vector<std::string> &args() const { return Args; }

std::vector<std::string> &args() { return Args; }

void tag(DiagnosticTag Tag) { Tags.push_back(Tag); }

[[nodiscard]] const std::vector<DiagnosticTag> &tags() const { return Tags; }

[[nodiscard]] LexerCursorRange range() const { return Range; }

protected:
PartialDiagnostic() = default;

PartialDiagnostic(LexerCursorRange Range) : Range(Range) {}

private:
std::vector<DiagnosticTag> Tags;
std::vector<std::string> Args;
/// Location of this diagnostic
RangeTy Range;
LexerCursorRange Range;
};

class Note : public PartialDiagnostic {
Expand All @@ -102,24 +121,26 @@ class Note : public PartialDiagnostic {
#undef DIAG_NOTE
};

Note(NoteKind Kind, RangeTy Range) : Kind(Kind), Range(Range) {}
Note(NoteKind Kind, LexerCursorRange Range)
: PartialDiagnostic(Range), Kind(Kind) {}

template <class T> PartialDiagnostic &operator<<(const T &Var) {
Args.push_back(Var);
args().push_back(Var);
return *this;
}

[[nodiscard]] static const char *sname(NoteKind Kind);

[[nodiscard]] virtual const char *sname() const { return sname(kind()); }

NoteKind kind() const { return Kind; }

[[nodiscard]] static const char *message(NoteKind Kind);

[[nodiscard]] const char *message() const override { return message(kind()); }

RangeTy range() const { return Range; }

private:
NoteKind Kind;
RangeTy Range;
};

/// The super class for all diagnostics.
Expand All @@ -143,7 +164,8 @@ class Diagnostic : public PartialDiagnostic {
#undef DIAG
};

Diagnostic(DiagnosticKind Kind, RangeTy Range) : Kind(Kind), Range(Range) {}
Diagnostic(DiagnosticKind Kind, LexerCursorRange Range)
: PartialDiagnostic(Range), Kind(Kind) {}

[[nodiscard]] DiagnosticKind kind() const { return Kind; };

Expand All @@ -162,7 +184,7 @@ class Diagnostic : public PartialDiagnostic {

[[nodiscard]] virtual const char *sname() const { return sname(kind()); }

Note &note(Note::NoteKind Kind, RangeTy Range) {
Note &note(Note::NoteKind Kind, LexerCursorRange Range) {
return Notes.emplace_back(Kind, Range);
}

Expand All @@ -174,12 +196,8 @@ class Diagnostic : public PartialDiagnostic {

[[nodiscard]] const std::vector<Fix> &fixes() const { return Fixes; }

[[nodiscard]] RangeTy range() const { return Range; }

private:
DiagnosticKind Kind;
/// Location of this diagnostic
RangeTy Range;

std::vector<Note> Notes;
std::vector<Fix> Fixes;
Expand Down
24 changes: 15 additions & 9 deletions libnixf/include/nixf/Basic/DiagnosticKinds.inc
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ DIAG("lex-float-no-exp", FloatNoExp, Fatal,
DIAG("lex-float-leading-zero", FloatLeadingZero, Warning,
"float begins with extra zeros `{}` is nixf extension")
DIAG("parse-expected", Expected, Error, "expected {}")
DIAG("parse-attrpath-extra-dot", AttrPathExtraDot, Error, "extra `.` at the end of attrpath")
DIAG("parse-select-extra-dot", SelectExtraDot, Error, "extra `.` after expression, but missing attrpath")
DIAG("parse-unexpected-between", UnexpectedBetween, Error, "unexpected {} between {} and {}")
DIAG("parse-unexpected", UnexpectedText, Error, "unexpected text {}")
DIAG("parse-unexpected", UnexpectedText, Error, "unexpected text")
DIAG("parse-missing-sep-formals", MissingSepFormals, Error, "missing seperator `,` between two lambda formals")
DIAG("parse-lambda-arg-extra-at", LambdaArgExtraAt, Error, "extra `@` for lambda arg")
DIAG("let-dynamic", LetDynamic, Error,
"dynamic attributes are not allowed in let ... in ... expression")
DIAG("inherit-dynamic", InheritDynamic, Error,
"dynamic attributes are not allowed in inherit")
DIAG("empty-inherit", EmptyInherit, Warning, "empty inherit expression")
DIAG("or-identifier", OrIdentifier, Warning,
"keyword `or` used as an identifier")
Expand All @@ -26,16 +27,21 @@ DIAG("deprecated-let", DeprecatedLet, Warning,
"(rec {{..., body = ...}}).body'")
DIAG("path-trailing-slash", PathTrailingSlash, Fatal,
"path has a trailing slash")
DIAG("dup-formal", DuplicatedFormal, Error,
"duplicated function formal declaration")
DIAG("dup-formal-arg", DuplicatedFormalToArg, Error,
"function argument duplicated to a function formal")
DIAG("merge-diff-rec", MergeDiffRec, Warning,
"merging two attributes with different `rec` modifiers, the latter "
"will be implicitly ignored")
DIAG("bison", BisonParse, Fatal, "{}")
DIAG("invalid-float", InvalidFloat, Fatal, "invalid float {}")
DIAG("invalid-integer", InvalidInteger, Fatal, "invalid integer {}")
DIAG("dup-formal-arg", DuplicatedAttr, Error, "duplicated attr `{}`")

DIAG("sema-duplicated-attrname", DuplicatedAttrName, Error, "duplicated attrname `{}`")
DIAG("sema-dynamic-inherit", DynamicInherit, Error,
"dynamic attributes are not allowed in inherit")
DIAG("sema-empty-formal", EmptyFormal, Error, "empty formal")
DIAG("sema-formal-missing-comma", FormalMissingComma, Error, "missing `,` for lambda formal")
DIAG("sema-formal-extra-ellipsis", FormalExtraEllipsis, Error, "extra `...` for lambda formal")
DIAG("sema-misplaced-ellipsis", FormalMisplacedEllipsis, Error, "misplaced `...` for lambda formal")
DIAG("sema-dup-formal", DuplicatedFormal, Error,
"duplicated function formal")
DIAG("sema-dup-formal-arg", DuplicatedFormalToArg, Error,
"function argument duplicated to a function formal")
#endif // DIAG
48 changes: 48 additions & 0 deletions libnixf/include/nixf/Basic/NodeKinds.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/// provides NODE(NAME) EXPR(NAME)

#ifdef NODE

/// ${ expr }
NODE(Interpolation)
NODE(InterpolableParts)

/// \brief Misc node used for parentheses keywords etc.
/// \see Misc
NODE(Misc)
NODE(Identifer)
NODE(AttrName)
NODE(AttrPath)
NODE(Binding)
NODE(Inherit)
NODE(Binds)
NODE(LambdaArg)
NODE(Formals)
NODE(Formal)
NODE(Op)

#endif // NODE



#ifdef EXPR

EXPR(ExprInt)
EXPR(ExprFloat)
EXPR(ExprVar)
EXPR(ExprString)
EXPR(ExprPath)
EXPR(ExprParen)
EXPR(ExprAttrs)
EXPR(ExprSelect)
EXPR(ExprCall)
EXPR(ExprList)
EXPR(ExprLambda)
EXPR(ExprBinOp)
EXPR(ExprUnaryOp)
EXPR(ExprOpHasAttr)
EXPR(ExprIf)
EXPR(ExprAssert)
EXPR(ExprLet)
EXPR(ExprWith)

#endif // EXPR
16 changes: 16 additions & 0 deletions libnixf/include/nixf/Basic/Nodes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// \file
/// \brief AST nodes.
///
/// Declares the AST nodes used by the parser, the nodes may be used in latter
/// stages, for example semantic analysis.
/// It is expected that they may share some nodes, so they are reference
/// counted.

#pragma once

#include "Nodes/Attrs.h"
#include "Nodes/Basic.h"
#include "Nodes/Expr.h"
#include "Nodes/Lambda.h"
#include "Nodes/Op.h"
#include "Nodes/Simple.h"
Loading

0 comments on commit 299c4a1

Please sign in to comment.