Skip to content

Commit

Permalink
nixd/Syntax: basic diagnostic support
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Sep 18, 2023
1 parent 1a2290c commit 70cc30a
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 26 deletions.
33 changes: 33 additions & 0 deletions nixd/include/nixd/Syntax/Diagnostic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/// Nixd diagnostic types. Provide structured diagnostic with location, FixIt
/// hints, annotation, and notes
#pragma once

#include "nixd/Syntax/Range.h"

namespace nixd::syntax {

// The note.
struct Note {
nixd::RangeIdx Range;

std::string Msg;
};

struct Edit {
nixd::RangeIdx Range;

std::string NewText;
};

struct Diagnostic {
nixd::RangeIdx Range;

std::string Msg;

enum DiagKind { Warning, Error } Kind;

std::vector<Note> Notes;
std::vector<Edit> Edits;
};

} // namespace nixd::syntax
3 changes: 3 additions & 0 deletions nixd/include/nixd/Syntax/Parser/Require.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "nixd/Expr/Expr.h"
#include "nixd/Syntax/Diagnostic.h"
#include "nixd/Syntax/Nodes.h"

#include <cstddef>
Expand All @@ -24,6 +25,8 @@ struct ParseData {
nix::PosTable::Origin Origin;

Context<Node> Nodes;

std::vector<Diagnostic> Diags;
};

// Note: copied from
Expand Down
43 changes: 21 additions & 22 deletions nixd/lib/Syntax/Lexer/Lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -60,32 +60,30 @@ or { return OR_KW; }
{ID} { yylval->ID = {yytext, (size_t) yyleng}; return ID; }
{INT} { errno = 0;
try {
yylval->N = boost::lexical_cast<int64_t>(yytext);
yylval->N = boost::lexical_cast<int64_t>(yytext);
} catch (const boost::bad_lexical_cast &) {
// TODO: emit the error
/*
data->error.emplace_back(nix::ErrorInfo{
.msg = hintfmt("invalid integer '%1%'", yytext),
.errPos = data->state.positions[CUR_POS],
});
*/
yyterminate();
auto Range = mkRange(*yylloc, *Data);
Diagnostic Diag;
Diag.Msg = llvm::formatv("invalid integer {0}", yytext);
Diag.Kind = Diagnostic::Error;
Diag.Range = Range;
Data->Diags.emplace_back(std::move(Diag));
yyterminate();
}
return INT;
}
{FLOAT} {
errno = 0;
yylval->NF = strtod(yytext, 0);
// TODO: emit the error
/*
if (errno != 0) {
data->error.emplace_back(nix::ErrorInfo{
.msg = hintfmt("invalid float '%1%'", yytext),
.errPos = data->state.positions[CUR_POS],
});
yyterminate();
auto Range = mkRange(*yylloc, *Data);
Diagnostic Diag;
Diag.Msg = llvm::formatv("invalid float {0}", yytext);
Diag.Kind = Diagnostic::Error;
Diag.Range = Range;
Data->Diags.emplace_back(std::move(Diag));
yyterminate();
}
*/
return FLOAT;
}

Expand Down Expand Up @@ -211,11 +209,12 @@ or { return OR_KW; }

<INPATH_SLASH>{ANY} |
<INPATH_SLASH><<EOF>> {
/* data->error.emplace_back(nix::ErrorInfo{
.msg = hintfmt("path has a trailing slash"),
.errPos = data->state.positions[CUR_POS],
});
*/
auto Range = mkRange(*yylloc, *Data);
Diagnostic Diag;
Diag.Msg = llvm::formatv("path has a trailing slash");
Diag.Kind = Diagnostic::Error;
Diag.Range = Range;
Data->Diags.emplace_back(std::move(Diag));
yyterminate();
}

Expand Down
14 changes: 14 additions & 0 deletions nixd/lib/Syntax/Lexer/Prologue.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "Parser.tab.h"

#include "nixd/Support/Position.h"
#include "nixd/Syntax/Diagnostic.h"
#include "nixd/Syntax/Nodes.h"
#include "nixd/Syntax/Parser/Require.h"

Expand All @@ -9,6 +10,8 @@

#include <boost/lexical_cast.hpp>

using nixd::syntax::Diagnostic;

#ifdef __clang__
#pragma clang diagnostic ignored "-Wunneeded-internal-declaration"
#endif
Expand All @@ -21,6 +24,17 @@ static void initLoc(YYLTYPE *loc) {
loc->first_column = loc->last_column = 1;
}

static nixd::RangeIdx mkRange(YYLTYPE YL, nix::PosTable &T,
const nix::PosTable::Origin &Origin) {
auto Begin = T.add(Origin, YL.first_line, YL.first_column);
auto End = T.add(Origin, YL.last_line, YL.last_column);
return {Begin, End};
}

static nixd::RangeIdx mkRange(YYLTYPE YL, nixd::syntax::ParseData &Data) {
return mkRange(YL, Data.State.Positions, Data.Origin);
}

static void adjustLoc(YYLTYPE *loc, const char *s, size_t len) {
prev_yylloc = *loc;

Expand Down
16 changes: 13 additions & 3 deletions nixd/lib/Syntax/Parser/Prologue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

#include "Lexer.tab.h"

#include "nixd/Syntax/Diagnostic.h"
#include "nixd/Syntax/Nodes.h"
#include "nixd/Syntax/Parser/Require.h"

#include "llvm/Support/FormatVariadic.h"

using namespace nixd::syntax;

YY_DECL;

void yyerror(YYLTYPE *loc, yyscan_t scanner, nixd::syntax::ParseData *data,
const char *error) {}

/// Convert a yacc location (yylloc) to nix::PosIdx
/// Store in the pos table
static nixd::RangeIdx mkRange(YYLTYPE YL, nix::PosTable &T,
Expand All @@ -25,6 +25,16 @@ static nixd::RangeIdx mkRange(YYLTYPE YL, nixd::syntax::ParseData &Data) {
return mkRange(YL, Data.State.Positions, Data.Origin);
}

void yyerror(YYLTYPE *YL, yyscan_t Scanner, nixd::syntax::ParseData *Data,
const char *Error) {
auto Range = mkRange(*YL, *Data);
Diagnostic Diag;
Diag.Msg = llvm::formatv("{0}", Error);
Diag.Kind = Diagnostic::Error;
Diag.Range = Range;
Data->Diags.emplace_back(std::move(Diag));
}

template <class T>
T *decorateNode(T *Node, YYLTYPE YL, nixd::syntax::ParseData &Data) {
Data.Nodes.record(Node);
Expand Down
2 changes: 1 addition & 1 deletion nixd/test/Syntax/Basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ TEST(NixdSyntax, Case1) {
.Origin = nix::Pos::Origin(nix::Pos::none_tag())});
Data->Result = nullptr;

char Test[] = "let x = 1; y = 2; in x\n\0\0";
char Test[] = "{ a = 1; \n\0\0";
parse(Test, strlen(Test) + 2, Data.get());
}

Expand Down

0 comments on commit 70cc30a

Please sign in to comment.