Skip to content

Commit 2c25600

Browse files
Aetherallinclyc
andauthored
libnixf/Parse: parse incomplete attrsets to provide completions (#644)
Small DX adjustments: - Parser distinguishes a little better formals from attrsets - Completion are triggered when discovering options of an attrset ( no need to try and guess the first letter ) --------- Co-authored-by: Yingchi Long <[email protected]>
1 parent 6e58141 commit 2c25600

File tree

2 files changed

+181
-11
lines changed

2 files changed

+181
-11
lines changed

libnixf/src/Parse/ParseExpr.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ std::shared_ptr<Expr> Parser::parseExprApp(int Limit) {
7171
}
7272

7373
std::shared_ptr<Expr> Parser::parseExpr() {
74-
// Look ahead 3 tokens.
74+
// Look ahead 4 tokens.
7575
switch (peek().kind()) {
7676
case tok_id: {
7777
switch (peek(1).kind()) {
@@ -93,8 +93,15 @@ std::shared_ptr<Expr> Parser::parseExpr() {
9393
case tok_comma: // { a ,
9494
case tok_id: // { a b
9595
case tok_ellipsis: // { a ...
96-
case tok_r_curly:
9796
return parseExprLambda();
97+
case tok_r_curly:
98+
switch (peek(3).kind()) {
99+
case tok_colon: // { a } :
100+
case tok_at: // { a } @
101+
return parseExprLambda();
102+
default:
103+
return parseExprAttrs();
104+
}
98105
default:
99106
break;
100107
}

libnixf/test/Parse/ParseAttrs.cpp

Lines changed: 172 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,25 +223,188 @@ TEST(Parser, AttrsBinding) {
223223
}
224224
)"sv;
225225

226+
std::vector<Diagnostic> Diags;
227+
auto AST = nixf::parse(Src, Diags);
228+
ASSERT_TRUE(AST);
229+
ASSERT_EQ(Diags.size(), 0);
230+
231+
ASSERT_EQ(AST->kind(), Node::NK_ExprAttrs);
232+
233+
ASSERT_EQ(AST->range().lCur().line(), 1);
234+
ASSERT_EQ(AST->range().lCur().column(), 0);
235+
ASSERT_EQ(AST->range().rCur().line(), 4);
236+
ASSERT_EQ(AST->range().rCur().column(), 1);
237+
238+
const auto &Attrs = *static_cast<ExprAttrs *>(AST.get());
239+
const auto &Bindings = Attrs.binds()->bindings();
240+
241+
ASSERT_EQ(Bindings.size(), 2);
242+
243+
ASSERT_EQ(Bindings[0]->range().lCur().line(), 2);
244+
ASSERT_EQ(Bindings[0]->range().lCur().column(), 2);
245+
ASSERT_EQ(Bindings[0]->range().rCur().line(), 2);
246+
ASSERT_EQ(Bindings[0]->range().rCur().column(), 8);
247+
248+
ASSERT_EQ(Bindings[1]->range().lCur().line(), 3);
249+
ASSERT_EQ(Bindings[1]->range().lCur().column(), 2);
250+
ASSERT_EQ(Bindings[1]->range().rCur().line(), 3);
251+
ASSERT_EQ(Bindings[1]->range().rCur().column(), 8);
252+
}
253+
254+
TEST(Parser, AttrsBindingWriting) {
255+
auto Src = R"(
256+
{
257+
a
258+
}
259+
)"sv;
260+
261+
std::vector<Diagnostic> Diags;
262+
auto AST = nixf::parse(Src, Diags);
263+
264+
ASSERT_TRUE(AST);
265+
ASSERT_EQ(AST->kind(), Node::NK_ExprAttrs);
266+
267+
const auto &Attrs = *static_cast<ExprAttrs *>(AST.get());
268+
ASSERT_EQ(Attrs.binds()->bindings().size(), 1);
269+
270+
const auto &Bind =
271+
*static_cast<Binding *>(Attrs.binds()->bindings()[0].get());
272+
273+
ASSERT_EQ(Bind.kind(), Node::NK_Binding);
274+
275+
const auto &BindPath = Bind.path();
276+
ASSERT_EQ(BindPath.names().size(), 1);
277+
278+
const auto &Name = *BindPath.names().at(0);
279+
280+
ASSERT_EQ(Name.kind(), Node::NK_Interpolation);
281+
ASSERT_EQ(Name.id()->kind(), Node::NK_Identifier);
282+
ASSERT_EQ(Name.id()->name(), "a");
283+
284+
ASSERT_EQ(Name.range().lCur().line(), 2);
285+
ASSERT_EQ(Name.range().lCur().column(), 2);
286+
ASSERT_EQ(Name.range().rCur().line(), 2);
287+
ASSERT_EQ(Name.range().rCur().column(), 3);
288+
}
289+
290+
TEST(Parser, AttrsBindingWritingDot) {
291+
auto Src = R"(
292+
{
293+
a.
294+
}
295+
)"sv;
296+
297+
std::vector<Diagnostic> Diags;
298+
auto AST = nixf::parse(Src, Diags);
299+
300+
ASSERT_TRUE(AST);
301+
ASSERT_EQ(AST->kind(), Node::NK_ExprAttrs);
302+
303+
const auto &Attrs = *static_cast<ExprAttrs *>(AST.get());
304+
ASSERT_EQ(Attrs.binds()->bindings().size(), 1);
305+
306+
const auto &Bind =
307+
*static_cast<Binding *>(Attrs.binds()->bindings()[0].get());
308+
309+
ASSERT_EQ(Bind.kind(), Node::NK_Binding);
310+
311+
const auto &Path = Bind.path();
312+
ASSERT_EQ(Path.names().size(), 1);
313+
314+
const auto &Name = *Path.names().at(0);
315+
316+
ASSERT_EQ(Name.kind(), Node::NK_Interpolation);
317+
ASSERT_EQ(Name.id()->kind(), Node::NK_Identifier);
318+
ASSERT_EQ(Name.id()->name(), "a");
319+
320+
ASSERT_EQ(Name.range().lCur().line(), 2);
321+
ASSERT_EQ(Name.range().lCur().column(), 2);
322+
ASSERT_EQ(Name.range().rCur().line(), 2);
323+
ASSERT_EQ(Name.range().rCur().column(), 3);
324+
}
325+
326+
TEST(Parser, AttrsNestedInLambda) {
327+
auto Src = R"(
328+
{...}: {
329+
a = {
330+
b = 1;
331+
};
332+
}
333+
)"sv;
334+
335+
std::vector<Diagnostic> Diags;
336+
auto AST = nixf::parse(Src, Diags);
337+
338+
ASSERT_TRUE(AST);
339+
ASSERT_EQ(AST->kind(), Node::NK_ExprLambda);
340+
341+
ASSERT_EQ(AST->range().lCur().line(), 1);
342+
ASSERT_EQ(AST->range().lCur().column(), 0);
343+
ASSERT_EQ(AST->range().rCur().line(), 5);
344+
ASSERT_EQ(AST->range().rCur().column(), 1);
345+
346+
ASSERT_EQ(Diags.size(), 0);
347+
348+
const auto &Attrs =
349+
static_cast<ExprAttrs *>(static_cast<ExprLambda *>(AST.get())->body());
350+
ASSERT_EQ(Attrs->kind(), Node::NK_ExprAttrs);
351+
352+
const auto &Bind =
353+
static_cast<Binding *>(Attrs->binds()->bindings()[0].get());
354+
355+
ASSERT_EQ(Bind->kind(), Node::NK_Binding);
356+
357+
const auto &NestedAttrs = static_cast<ExprAttrs *>(Bind->value().get());
358+
359+
ASSERT_EQ(NestedAttrs->kind(), Node::NK_ExprAttrs);
360+
}
361+
362+
TEST(Parser, AttrsNested) {
363+
auto Src = R"(
364+
{
365+
a = {
366+
b = 1;
367+
};
368+
}
369+
)"sv;
370+
226371
std::vector<Diagnostic> Diags;
227372
auto AST = nixf::parse(Src, Diags);
228373

229374
ASSERT_TRUE(AST);
230375
ASSERT_EQ(AST->kind(), Node::NK_ExprAttrs);
231376
ASSERT_TRUE(AST->range().lCur().isAt(1, 0, 1));
232-
ASSERT_TRUE(AST->range().rCur().isAt(4, 1, 22));
377+
ASSERT_TRUE(AST->range().rCur().isAt(5, 1, 28));
233378

234379
ASSERT_EQ(Diags.size(), 0);
235380

236381
// Check the bindings.
237-
auto &B = *static_cast<ExprAttrs *>(AST.get());
238-
assert(B.binds() && "expected bindings");
239-
ASSERT_EQ(B.binds()->bindings().size(), 2);
240-
ASSERT_TRUE(B.binds()->bindings()[0]->range().lCur().isAt(2, 2, 5));
241-
ASSERT_TRUE(B.binds()->bindings()[0]->range().rCur().isAt(2, 8, 11));
242-
243-
ASSERT_TRUE(B.binds()->bindings()[1]->range().lCur().isAt(3, 2, 14));
244-
ASSERT_TRUE(B.binds()->bindings()[1]->range().rCur().isAt(3, 8, 20));
382+
const auto &B = static_cast<ExprAttrs *>(AST.get())->binds()->bindings();
383+
ASSERT_EQ(B.size(), 1);
384+
385+
const auto &Ba = static_cast<Binding *>(B[0].get());
386+
387+
ASSERT_EQ(Ba->kind(), Node::NK_Binding);
388+
ASSERT_TRUE(Ba->range().lCur().isAt(2, 2, 5));
389+
ASSERT_TRUE(Ba->range().rCur().isAt(4, 4, 26));
390+
391+
ASSERT_EQ(Ba->path().names().at(0)->id()->name(), "a");
392+
ASSERT_EQ(Ba->value()->kind(), Node::NK_ExprAttrs);
393+
394+
const auto &BaRHS =
395+
static_cast<ExprAttrs *>(Ba->value().get())->binds()->bindings();
396+
ASSERT_EQ(BaRHS.size(), 1);
397+
ASSERT_EQ(BaRHS[0]->kind(), Node::NK_Binding);
398+
399+
const auto &BaRHSb = static_cast<Binding *>(BaRHS[0].get());
400+
401+
ASSERT_EQ(BaRHSb->range().lCur().line(), 3);
402+
ASSERT_EQ(BaRHSb->range().lCur().column(), 4);
403+
ASSERT_EQ(BaRHSb->range().rCur().line(), 3);
404+
ASSERT_EQ(BaRHSb->range().rCur().column(), 10);
405+
406+
ASSERT_EQ(BaRHSb->path().names().at(0)->id()->name(), "b");
407+
ASSERT_EQ(BaRHSb->value()->kind(), Node::NK_ExprInt);
245408
}
246409

247410
TEST(Parser, AttrsBindingEarlyExit) {

0 commit comments

Comments
 (0)