Skip to content

Commit

Permalink
nixd/Basic: diagnostic declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Oct 16, 2023
1 parent 64a3034 commit a71dfc0
Show file tree
Hide file tree
Showing 22 changed files with 365 additions and 196 deletions.
99 changes: 99 additions & 0 deletions nixd/include/nixd/Basic/Diagnostic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/// Diagnostic.h, diagnostic types and definitions
///
/// Diagnostics are structures with a main message,
/// and optionally some additional information (body).
///
/// For diagnostics with a body,
/// they may need a special overrided function to format the message.
///
#pragma once

#include "Range.h"
#include <optional>
#include <string>

namespace nixd {

/// The super class for all diagnostics.
/// concret diagnostic types are defined in Diagnostic*.inc
struct Diagnostic {

/// Location of this diagnostic
RangeIdx Range;

Diagnostic(RangeIdx Range) : Range(Range) {}

/// Each diagnostic contains a severity field,
/// should be "Fatal", "Error" or "Warning"
/// this will affect the eval process.
///
/// "Fatal" -- shouldn't eval the code, e.g. parsing error.
/// "Error" -- trigger an error in nix, but we can eval the code.
/// "Warning" -- just a warning.
/// "Note" -- some additional information about the error.
enum Severity { DS_Fatal, DS_Error, DS_Warning, DS_Note };

/// Internal diagnostic kind
enum Kind {
#define DIAG_ALL(SNAME, CNAME, SEVERITY, MESSAGE) DK_##CNAME,
#include "DiagnosticMerge.inc"
#undef DIAG_ALL
};

[[nodiscard]] virtual Kind kind() const = 0;

[[nodiscard]] virtual Severity severity() const = 0;

/// Format a printable diagnostic
[[nodiscard]] virtual std::string_view format() const = 0;

/// Short name, switch name.
/// There might be a human readable short name that controls the diagnostic
/// For example, one may pass -Wno-dup-formal to suppress duplicated formals.
/// A special case for parsing errors, generated from bison
/// have the sname "bison"
[[nodiscard]] virtual const char *sname() const = 0;

virtual ~Diagnostic() = default;
};

struct NotableDiagnostic : Diagnostic {
NotableDiagnostic(RangeIdx Range) : Diagnostic(Range) {}
using NotesTy = std::vector<std::unique_ptr<Diagnostic>>;
NotesTy Notes;
NotesTy &notes() { return Notes; }
};

#define DIAG_SIMPLE(SNAME, CNAME, SEVERITY, MESSAGE) \
struct Diag##CNAME : Diagnostic { \
Diag##CNAME(RangeIdx Range) : Diagnostic(Range) {} \
std::string_view format() const override { return MESSAGE; } \
const char *sname() const override { return SNAME; } \
Severity severity() const override { return DS_##SEVERITY; } \
Kind kind() const override { return DK_##CNAME; } \
};
#include "DiagnosticKinds.inc"
#undef DIAG_SIMPLE

#define DIAG_NOTE(SNAME, CNAME, SEVERITY, MESSAGE) \
struct Diag##CNAME : NotableDiagnostic { \
Diag##CNAME(RangeIdx Range) : NotableDiagnostic(Range) {} \
std::string_view format() const override { return MESSAGE; } \
const char *sname() const override { return SNAME; } \
Severity severity() const override { return DS_##SEVERITY; } \
Kind kind() const override { return DK_##CNAME; } \
};
#include "DiagnosticKinds.inc"
#undef DIAG_NOTE

#define DIAG_BODY(SNAME, CNAME, SEVERITY, MESSAGE, BODY) \
struct Diag##CNAME : Diagnostic BODY;
#include "DiagnosticKinds.inc"
#undef DIAG_BODY

#define DIAG_NOTE_BODY(SNAME, CNAME, SEVERITY, MESSAGE, BODY) \
struct Diag##CNAME : NotableDiagnostic BODY;
#include "DiagnosticKinds.inc"
#undef DIAG_NOTE_BODY

} // namespace nixd
101 changes: 101 additions & 0 deletions nixd/include/nixd/Basic/DiagnosticKinds.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/// DiagnosticKinds.inc, diagnostic declarations

// provides: DIAG_SIMPLE(SNAME, CNAME, SEVERITY, MESSAGE)
// provides: DIAG_BODY(SNAME, CNAME, SEVERITY, MESSAGE, BODY)
// provides: DIAG_NOTE(SNAME, CNAME, SEVERITY, MESSAGE)
// provides: DIAG_NOTE_BODY(SNAME, CNAME, SEVERITY, MESSAGE, BODY)

//=============================================================================/
// DIAG_SIMPLE(SName, ClassName, Severity, Message)
// "simple" means they have no additional body
//=============================================================================/

#ifdef DIAG_SIMPLE
DIAG_SIMPLE("note-prev", PrevDeclared, Note, "previously declared here")
DIAG_SIMPLE("let-dynamic", LetDynamic, Error,
"dynamic attributes are not allowed in let ... in ... expression")
DIAG_SIMPLE("inherit-dynamic", InheritDynamic, Error,
"dynamic attributes are not allowed in inherit")
DIAG_SIMPLE("empty-inherit", EmptyInherit, Warning, "empty inherit expression")
DIAG_SIMPLE("or-identifier", OrIdentifier, Warning,
"keyword `or` used as an identifier")
DIAG_SIMPLE("deprecated-url-literal", DeprecatedURL, Warning,
"URL literal is deprecated")
DIAG_SIMPLE("deprecated-let", DeprecatedLet, Warning,
"using deprecated `let' syntactic sugar `let {..., body = ...}' -> "
"(rec {..., body = ...}).body'")
DIAG_SIMPLE("path-trailing-slash", PathTrailingSlash, Fatal,
"path has a trailing slash")
#endif // DIAG_SIMPLE

//=============================================================================/
// DIAG_NOTE(SName, ClassName, Severity, Message)
// "simple", but with additional note support
//=============================================================================/
#ifdef DIAG_NOTE
DIAG_NOTE("dup-formal", DuplicatedFormal, Error,
"duplicated function formal declaration")
DIAG_NOTE("dup-formal-arg", DuplicatedFormalToArg, Error,
"function argument duplicated to a function formal")
DIAG_NOTE("merge-diff-rec", MergeDiffRec, Warning,
"merging two attributes with different `rec` modifiers, the latter "
"will be implicitly ignored")
#endif // DIAG_NOTE

#define COMMON_METHOD \
Severity severity() const override; \
Kind kind() const override; \
std::string_view format() const override; \
const char *sname() const override; \
static constexpr const char *message();

//=============================================================================/
// DIAG_BODY(SName, ClassName, Severity, Message, Body)
// diagnostics with special body
//=============================================================================/
#ifdef DIAG_BODY
DIAG_BODY("bison", BisonParse, Fatal, "{0}", {
DiagBisonParse(RangeIdx Range, std::string Str);
std::string Str;
COMMON_METHOD
})
DIAG_BODY("merge-diff-rec-this-rec", ThisRecursive, Note,
"this attribute set is {0}recursive", {
DiagThisRecursive(RangeIdx Range, bool Recursive);
std::string Str;
COMMON_METHOD
})
DIAG_BODY("merge-diff-rec-consider", RecConsider, Note,
"while this attribute set is marked as {0}recursive, it "
"will be considered as {1}recursive",
{
DiagRecConsider(RangeIdx Range, bool MarkedRecursive);
std::string Str;
COMMON_METHOD
})
DIAG_BODY("invalid-float", InvalidFloat, Note, "invalid float {0}", {
DiagInvalidFloat(RangeIdx Range, std::string_view Content);
std::string Str;
COMMON_METHOD
})
DIAG_BODY("invalid-integer", InvalidInteger, Note, "invalid integer {0}", {
DiagInvalidInteger(RangeIdx Range, std::string_view Content);
std::string Str;
COMMON_METHOD
})
#endif // DIAG_BODY

//=============================================================================/
// DIAG_NOTE_BODY(SName, ClassName, Severity, Message, Body)
// diagnostics with special body, but with additional note support
//=============================================================================/
#ifdef DIAG_NOTE_BODY
DIAG_NOTE_BODY("dup-formal-arg", DuplicatedAttr, Error, "duplicated attr `{0}`",
{
DiagDuplicatedAttr(RangeIdx Range, std::string AttrName);
std::string Str;
COMMON_METHOD
})
#endif // DIAG_NOTE_BODY

#undef COMMON_METHOD
23 changes: 23 additions & 0 deletions nixd/include/nixd/Basic/DiagnosticMerge.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// DiagnosticMerge.inc, merge all declarations

// provides: DIAG_ALL(SNAME, CNAME, SEVERITY, MESSAGE)

#ifdef DIAG_ALL

#define DIAG_SIMPLE(SNAME, CNAME, SEVERITY, MESSAGE) \
DIAG_ALL(SNAME, CNAME, SEVERITY, MESSAGE)
#define DIAG_BODY(SNAME, CNAME, SEVERITY, MESSAGE, BODY) \
DIAG_ALL(SNAME, CNAME, SEVERITY, MESSAGE)
#define DIAG_NOTE_BODY(SNAME, CNAME, SEVERITY, MESSAGE, BODY) \
DIAG_ALL(SNAME, CNAME, SEVERITY, MESSAGE)
#define DIAG_NOTE(SNAME, CNAME, SEVERITY, MESSAGE) \
DIAG_ALL(SNAME, CNAME, SEVERITY, MESSAGE)

#include "DiagnosticKinds.inc"

#undef DIAG_NOTE
#undef DIAG_NOTE_BODY
#undef DIAG_BODY
#undef DIAG_SIMPLE

#endif
File renamed without changes.
4 changes: 2 additions & 2 deletions nixd/include/nixd/Sema/Lowering.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "nixd/Basic/Diagnostic.h"
#include "nixd/Sema/EvalContext.h"
#include "nixd/Syntax/Diagnostic.h"
#include "nixd/Syntax/Nodes.h"

#include <nix/input-accessor.hh>
Expand Down Expand Up @@ -54,7 +54,7 @@ class ExprAttrsBuilder {
struct Lowering {
nix::SymbolTable &STable;
nix::PosTable &PTable;
std::vector<syntax::Diagnostic> &Diags;
std::vector<std::unique_ptr<Diagnostic>> &Diags;
EvalContext &Ctx;
const nix::SourcePath &BasePath;

Expand Down
2 changes: 1 addition & 1 deletion nixd/include/nixd/Support/Position.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "nixd/Basic/Range.h"
#include "nixd/Nix/PosAdapter.h"
#include "nixd/Syntax/Range.h"

#include "lspserver/Protocol.h"

Expand Down
33 changes: 0 additions & 33 deletions nixd/include/nixd/Syntax/Diagnostic.h

This file was deleted.

2 changes: 1 addition & 1 deletion nixd/include/nixd/Syntax/Nodes.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// FIXME: comment for this file.
#pragma once

#include "Range.h"
#include "nixd/Basic/Range.h"

namespace nixd::syntax {

Expand Down
4 changes: 2 additions & 2 deletions nixd/include/nixd/Syntax/Parser/Require.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "nixd/Basic/Diagnostic.h"
#include "nixd/Support/GCPool.h"
#include "nixd/Syntax/Diagnostic.h"
#include "nixd/Syntax/Nodes.h"

#include <cstddef>
Expand All @@ -26,7 +26,7 @@ struct ParseData {

nixd::GCPool<Node> Nodes;

std::vector<Diagnostic> Diags;
std::vector<std::unique_ptr<Diagnostic>> Diags;
};

// Note: copied from
Expand Down
52 changes: 52 additions & 0 deletions nixd/lib/Basic/Diagnostic.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "nixd/Basic/Diagnostic.h"
#include "nixd/Basic/Range.h"

#include "llvm/Support/FormatVariadic.h"

namespace nixd {

#define DIAG_BODY(SNAME, CNAME, SEVERITY, MESSAGE, BODY) \
const char *Diag##CNAME::sname() const { return SNAME; } \
Diagnostic::Severity Diag##CNAME::severity() const { return DS_##SEVERITY; } \
Diagnostic::Kind Diag##CNAME::kind() const { return DK_##CNAME; } \
constexpr const char *Diag##CNAME::message() { return MESSAGE; } \
std::string_view Diag##CNAME::format() const { return Str; }
#define DIAG_NOTE_BODY(SNAME, CNAME, SEVERITY, MESSAGE, BODY) \
DIAG_BODY(SNAME, CNAME, SEVERITY, MESSAGE, BODY)
#include "nixd/Basic/DiagnosticKinds.inc"
#undef DIAG_BODY
#undef DIAG_NOTE_BODY

DiagBisonParse::DiagBisonParse(RangeIdx Range, std::string Str)
: Diagnostic(Range), Str(std::move(Str)) {}

DiagDuplicatedAttr::DiagDuplicatedAttr(RangeIdx Range, std::string AttrName)
: NotableDiagnostic(Range) {
Str = llvm::formatv(message(), AttrName);
}

static const char *getPrefix(bool P) { return P ? "" : "non-"; }

DiagThisRecursive::DiagThisRecursive(RangeIdx Range, bool Recursive)
: Diagnostic(Range) {
Str = llvm::formatv(message(), getPrefix(Recursive));
}

DiagRecConsider::DiagRecConsider(RangeIdx Range, bool MarkedRecursive)
: Diagnostic(Range) {
Str = llvm::formatv(message(), getPrefix(MarkedRecursive),
getPrefix(!MarkedRecursive));
}

DiagInvalidInteger::DiagInvalidInteger(RangeIdx Range, std::string_view Content)
: Diagnostic(Range) {
Str = llvm::formatv(message(), Content);
}

DiagInvalidFloat::DiagInvalidFloat(RangeIdx Range,
const std::string_view Content)
: Diagnostic(Range) {
Str = llvm::formatv(message(), Content);
}

} // namespace nixd
13 changes: 13 additions & 0 deletions nixd/lib/Basic/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
libnixdBasicDeps = [ nix_all, llvm ]
libnixdBasic = library('nixdBasic'
, [ 'Diagnostic.cpp'
]
, include_directories: nixd_inc
, dependencies: libnixdBasicDeps
, install: true
)

nixdBasic = declare_dependency( include_directories: nixd_inc
, dependencies: libnixdBasicDeps
, link_with: libnixdBasic
)
Loading

0 comments on commit a71dfc0

Please sign in to comment.