Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: nix-community/nixd
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 14b32749beb2f0001244e1e113b95a5309afb0e1
Choose a base ref
..
head repository: nix-community/nixd
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c2c2dabb33f0380a1b0f19636fc1f7331deb7c9d
Choose a head ref
Showing with 184 additions and 27 deletions.
  1. +7 −7 libnixf/include/nixf/Basic/Nodes.h
  2. +33 −16 libnixf/src/Parse/Parser.cpp
  3. +1 −3 libnixf/src/Parse/Parser.h
  4. +143 −1 libnixf/test/Parse/Parser.cpp
14 changes: 7 additions & 7 deletions libnixf/include/nixf/Basic/Nodes.h
Original file line number Diff line number Diff line change
@@ -631,9 +631,7 @@ class Formal : public Node {
Formal(LexerCursorRange Range, std::unique_ptr<Misc> Comma,
std::unique_ptr<Identifier> ID, std::unique_ptr<Expr> Default)
: Node(NK_Formal, Range), Comma(std::move(Comma)), ID(std::move(ID)),
Default(std::move(Default)) {
assert(this->ID && "ID must not be null");
}
Default(std::move(Default)) {}

Formal(LexerCursorRange Range, std::unique_ptr<Misc> Comma,
std::unique_ptr<Misc> Ellipsis)
@@ -649,14 +647,16 @@ class Formal : public Node {

[[nodiscard]] bool isEllipsis() const { return Ellipsis != nullptr; }

[[nodiscard]] Identifier &id() {
assert(ID && "ID must not be null");
return *ID;
}
[[nodiscard]] Identifier *id() const { return ID.get(); }

[[nodiscard]] Misc *comma() const { return Comma.get(); }

[[nodiscard]] Expr *defaultExpr() const { return Default.get(); }

[[nodiscard]] ChildVector children() const override {
if (isEllipsis()) {
return {Ellipsis.get()};
}
return {ID.get(), Default.get()};
}
};
49 changes: 33 additions & 16 deletions libnixf/src/Parse/Parser.cpp
Original file line number Diff line number Diff line change
@@ -622,7 +622,7 @@ std::unique_ptr<Formal> Parser::parseFormal() {
auto ID =
std::make_unique<Identifier>(Tok.range(), std::string(Tok.view()));
if (peek().kind() != tok_question)
return std::make_unique<Formal>(LexerCursorRange{LCur, Tok.rCur()},
return std::make_unique<Formal>(LexerCursorRange{LCur, LastToken->rCur()},
std::move(Comma), std::move(ID), nullptr);
consume(); // ?
std::unique_ptr<Expr> Default = parseExpr();
@@ -634,10 +634,18 @@ std::unique_ptr<Formal> Parser::parseFormal() {
}
if (Token Tok = peek(); Tok.kind() == tok_ellipsis) {
consume(); // ...
assert(LastToken && "LastToken should be set after consume()");
std::unique_ptr<Misc> Ellipsis = std::make_unique<Misc>(Tok.range());
return std::make_unique<Formal>(LexerCursorRange{LCur, Tok.rCur()},
return std::make_unique<Formal>(LexerCursorRange{LCur, LastToken->rCur()},
std::move(Comma), std::move(Ellipsis));
}

if (Comma) {
assert(LastToken && "LastToken should be set after consume()");
return std::make_unique<Formal>(LexerCursorRange{LCur, LastToken->rCur()},
std::move(Comma), /*ID=*/nullptr,
/*Default=*/nullptr);
}
return nullptr;
}

@@ -648,27 +656,39 @@ std::unique_ptr<Formals> Parser::parseFormals() {
Token TokLCurly = ER.tok();
consume(); // {
assert(LastToken && "LastToken should be set after consume()");
auto Sync = withSync(tok_r_curly);
LexerCursor Begin = ER.tok().lCur();
auto SyncRCurly = withSync(tok_r_curly);
auto SyncComma = withSync(tok_comma);
auto SyncQuestion = withSync(tok_question);
auto SyncID = withSync(tok_id);
LexerCursor LCur = ER.tok().lCur();
std::vector<std::unique_ptr<Formal>> Members;
while (true) {
if (Token Tok = peek(); Tok.kind() == tok_r_curly)
break;
std::unique_ptr<Formal> Formal = parseFormal();
if (!Formal)
if (!Formal) {
if (auto Unknown = consumeAsUnknown()) {
// extra text, consider remove it.
Diagnostic &D =
Diags.emplace_back(Diagnostic::DK_UnexpectedText, *Unknown);
D.fix("remove unexpected text").edit(TextEdit::mkRemoval(*Unknown));
continue;
}
break;
}
Members.emplace_back(std::move(Formal));
}
if (ExpectResult ER = expect(tok_r_curly); ER.ok())
consume();
else
ER.diag().note(Note::NK_ToMachThis, TokLCurly.range())
<< std::string(tok::spelling(tok_l_curly));
return std::make_unique<Formals>(LexerCursorRange{Begin, LastToken->rCur()},
return std::make_unique<Formals>(LexerCursorRange{LCur, LastToken->rCur()},
std::move(Members));
}

std::unique_ptr<LambdaArg> Parser::parseLambdaArg() {
LexerCursor LCur = lCur();
Token Tok = peek();

if (Tok.kind() == tok_id) {
@@ -678,7 +698,7 @@ std::unique_ptr<LambdaArg> Parser::parseLambdaArg() {
std::make_unique<Identifier>(Tok.range(), std::string(Tok.view()));
if (peek().kind() != tok_at)
return std::make_unique<LambdaArg>(
LexerCursorRange{Tok.lCur(), Tok.rCur()}, std::move(ID), nullptr);
LexerCursorRange{LCur, LastToken->rCur()}, std::move(ID), nullptr);

consume(); // @
std::unique_ptr<Formals> Formals = parseFormals();
@@ -691,7 +711,7 @@ std::unique_ptr<LambdaArg> Parser::parseLambdaArg() {
.edit(TextEdit::mkInsertion(Tok.rCur(), R"({})"));
}
return std::make_unique<LambdaArg>(
LexerCursorRange{Tok.lCur(), LastToken->rCur()}, std::move(ID),
LexerCursorRange{LCur, LastToken->rCur()}, std::move(ID),
std::move(Formals));
}

@@ -702,29 +722,26 @@ std::unique_ptr<LambdaArg> Parser::parseLambdaArg() {
Tok = peek();
if (Tok.kind() != tok_at)
return std::make_unique<LambdaArg>(
LexerCursorRange{Tok.lCur(), LastToken->rCur()}, nullptr,
std::move(Formals));
LexerCursorRange{LCur, LastToken->rCur()}, nullptr, std::move(Formals));
consume(); // @
ExpectResult ER = expect(tok_id);
if (!ER.ok()) {
ER.diag().note(Note::NK_ToMachThis, Tok.range())
<< std::string(tok::spelling(tok_at));
return std::make_unique<LambdaArg>(
LexerCursorRange{Tok.lCur(), LastToken->rCur()}, nullptr,
std::move(Formals));
LexerCursorRange{LCur, LastToken->rCur()}, nullptr, std::move(Formals));
}
consume(); // ID
auto ID = std::make_unique<Identifier>(ER.tok().range(),
std::string(ER.tok().view()));
return std::make_unique<LambdaArg>(
LexerCursorRange{Tok.lCur(), ER.tok().rCur()}, std::move(ID),
std::move(Formals));
return std::make_unique<LambdaArg>(LexerCursorRange{LCur, LastToken->rCur()},
std::move(ID), std::move(Formals));
}

std::unique_ptr<ExprLambda> Parser::parseExprLambda() {
// expr_lambda : lambda_arg ':' expr
std::unique_ptr<LambdaArg> Arg = parseLambdaArg();
LexerCursor LCur = lCur();
std::unique_ptr<LambdaArg> Arg = parseLambdaArg();
assert(LastToken && "LastToken should be set after parseLambdaArg");
if (!Arg)
return nullptr;
4 changes: 1 addition & 3 deletions libnixf/src/Parse/Parser.h
Original file line number Diff line number Diff line change
@@ -86,9 +86,7 @@ class Parser {
return *LastToken;
}

LexerCursor lCur() {
return LastToken ? LastToken->range().rCur() : peek().lCur();
}
LexerCursor lCur() { return peek().lCur(); }

public:
Parser(std::string_view Src, std::vector<Diagnostic> &Diags)
144 changes: 143 additions & 1 deletion libnixf/test/Parse/Parser.cpp
Original file line number Diff line number Diff line change
@@ -1063,7 +1063,105 @@ TEST(Parser, ParseAttrName_ExprRange) {
ASSERT_TRUE(AST->range().rCur().isAt(0, 5, 5));
}

TEST(Parser, ParseLambdaArg) {
TEST(Parser, ParseFormal_ID) {
auto Src = R"(a)"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);

auto AST = P.parseFormal();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 0);

ASSERT_EQ(AST->kind(), Node::NK_Formal);
ASSERT_TRUE(AST->range().lCur().isAt(0, 0, 0));
ASSERT_TRUE(AST->range().rCur().isAt(0, 1, 1));
}

TEST(Parser, ParseFormal_CommaID) {
auto Src = R"(, a)"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);

auto AST = P.parseFormal();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 0);

ASSERT_EQ(AST->kind(), Node::NK_Formal);
ASSERT_TRUE(AST->range().lCur().isAt(0, 0, 0));
ASSERT_TRUE(AST->range().rCur().isAt(0, 3, 3));
}

TEST(Parser, ParseFormal_ExprMissing) {
auto Src = R"(, a ? )"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);

auto AST = P.parseFormal();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 1);

ASSERT_EQ(AST->kind(), Node::NK_Formal);
ASSERT_TRUE(AST->range().lCur().isAt(0, 0, 0));
ASSERT_TRUE(AST->range().rCur().isAt(0, 5, 5));
}

TEST(Parser, ParseFormal_ExprOK) {
auto Src = R"(, a ? 1)"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);

auto AST = P.parseFormal();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 0);

ASSERT_EQ(AST->kind(), Node::NK_Formal);
ASSERT_TRUE(AST->range().lCur().isAt(0, 0, 0));
ASSERT_TRUE(AST->range().rCur().isAt(0, 7, 7));
}

TEST(Parser, ParseFormal_Ellipsis) {
auto Src = R"(, ...)"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);

auto AST = P.parseFormal();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 0);

ASSERT_EQ(AST->kind(), Node::NK_Formal);
ASSERT_TRUE(AST->range().lCur().isAt(0, 0, 0));
ASSERT_TRUE(AST->range().rCur().isAt(0, 5, 5));
}

TEST(Parser, ParseFormals) {
auto Src = R"({ a, b, c })"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);

auto AST = P.parseFormals();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 0);

ASSERT_EQ(AST->kind(), Node::NK_Formals);

auto *F = static_cast<Formals *>(AST.get());
ASSERT_EQ(F->members().size(), 3);
ASSERT_TRUE(F->range().rCur().isAt(0, 11, 11));
}

TEST(Parser, ParseLambdaArg_Formal) {
auto Src = R"({ a, b, ... })"sv;

std::vector<Diagnostic> Diags;
@@ -1074,4 +1172,48 @@ TEST(Parser, ParseLambdaArg) {
ASSERT_EQ(Diags.size(), 0);
}

TEST(Parser, ParseLambdaArgID_Suffix) {
auto Src = R"({ a, b, ... } @ ID)"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);
auto AST = P.parseLambdaArg();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 0);
}

TEST(Parser, ParseLambdaArgID_Prefix) {
auto Src = R"(ID @ { a, b, ... })"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);
auto AST = P.parseLambdaArg();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 0);
}

TEST(Parser, ParseLambdaArg_ID) {
auto Src = R"(ID)"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);
auto AST = P.parseLambdaArg();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 0);
}

TEST(Parser, ParseExprLambda) {
auto Src = R"({ a, b, ... }: a)"sv;

std::vector<Diagnostic> Diags;
Parser P(Src, Diags);
auto AST = P.parseExprLambda();

ASSERT_TRUE(AST);
ASSERT_EQ(Diags.size(), 0);
}

} // namespace