nixd
Loading...
Searching...
No Matches
ParseLambda.cpp
Go to the documentation of this file.
1#include "Parser.h"
2
3using namespace nixf;
4using namespace detail;
5
6std::shared_ptr<Formal> Parser::parseFormal() {
7 // formal : ,? ID
8 // | ,? ID '?' expr
9 // | ,? ...
10
11 LexerCursor LCur = lCur();
12 std::shared_ptr<Misc> Comma = nullptr;
13 if (Token Tok = peek(); Tok.kind() == tok_comma) {
14 consume();
15 Comma = std::make_shared<Misc>(Tok.range());
16 }
17 if (Token Tok = peek(); Tok.kind() == tok_id) {
18 consume(); // ID
19 assert(LastToken && "LastToken should be set after consume()");
20 auto ID =
21 std::make_shared<Identifier>(Tok.range(), std::string(Tok.view()));
22 if (peek().kind() != tok_question)
23 return std::make_shared<Formal>(LexerCursorRange{LCur, LastToken->rCur()},
24 std::move(Comma), std::move(ID), nullptr);
25 consume(); // ?
26 std::shared_ptr<Expr> Default = parseExpr();
27 if (!Default)
28 diagNullExpr(Diags, LastToken->rCur(), "default value");
29 return std::make_shared<Formal>(LexerCursorRange{LCur, LastToken->rCur()},
30 std::move(Comma), std::move(ID),
31 std::move(Default));
32 }
33 if (Token Tok = peek(); Tok.kind() == tok_ellipsis) {
34 consume(); // ...
35 assert(LastToken && "LastToken should be set after consume()");
36 std::shared_ptr<Misc> Ellipsis = std::make_shared<Misc>(Tok.range());
37 return std::make_shared<Formal>(LexerCursorRange{LCur, LastToken->rCur()},
38 std::move(Comma), std::move(Ellipsis));
39 }
40
41 if (Comma) {
42 assert(LastToken && "LastToken should be set after consume()");
43 return std::make_shared<Formal>(LexerCursorRange{LCur, LastToken->rCur()},
44 std::move(Comma), /*ID=*/nullptr,
45 /*Default=*/nullptr);
46 }
47 return nullptr;
48}
49
50std::shared_ptr<Formals> Parser::parseFormals() {
51 ExpectResult ER = expect(tok_l_curly);
52 if (!ER.ok())
53 return nullptr;
54 Token TokLCurly = ER.tok();
55 consume(); // {
56 assert(LastToken && "LastToken should be set after consume()");
57 auto SyncRCurly = withSync(tok_r_curly);
58 auto SyncComma = withSync(tok_comma);
59 auto SyncQuestion = withSync(tok_question);
60 auto SyncID = withSync(tok_id);
61 LexerCursor LCur = ER.tok().lCur();
62 std::vector<std::shared_ptr<Formal>> Members;
63 while (true) {
64 if (Token Tok = peek(); Tok.kind() == tok_r_curly)
65 break;
66 std::shared_ptr<Formal> Formal = parseFormal();
67 if (Formal) {
68 Members.emplace_back(std::move(Formal));
69 continue;
70 }
71 if (removeUnexpected())
72 continue;
73 break;
74 }
75 if (ExpectResult ER = expect(tok_r_curly); ER.ok())
76 consume();
77 else
78 ER.diag().note(Note::NK_ToMachThis, TokLCurly.range())
79 << std::string(tok::spelling(tok_l_curly));
80 return Act.onFormals(LexerCursorRange{LCur, LastToken->rCur()},
81 std::move(Members));
82}
83
84std::shared_ptr<LambdaArg> Parser::parseLambdaArg() {
85 LexerCursor LCur = lCur();
86 if (Token TokID = peek(); TokID.kind() == tok_id) {
87 consume(); // ID
88 assert(LastToken && "LastToken should be set after consume()");
89 auto ID =
90 std::make_shared<Identifier>(TokID.range(), std::string(TokID.view()));
91 if (peek().kind() != tok_at)
92 return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()},
93 std::move(ID), nullptr);
94
95 consume(); // @
96 std::shared_ptr<Formals> Formals = parseFormals();
97 if (!Formals) {
98 // extra "@", consider remove it.
99 Diagnostic &D =
100 Diags.emplace_back(Diagnostic::DK_LambdaArgExtraAt, TokID.range());
101 D.fix("remove extra @").edit(TextEdit::mkRemoval(TokID.range()));
102 D.fix("insert dummy formals")
103 .edit(TextEdit::mkInsertion(TokID.rCur(), R"({})"));
104 }
105 return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()},
106 std::move(ID), std::move(Formals));
107 }
108
109 std::shared_ptr<Formals> Formals = parseFormals();
110 if (!Formals)
111 return nullptr;
112 assert(LastToken && "LastToken should be set after valid formals");
113 Token TokAt = peek();
114 if (TokAt.kind() != tok_at)
115 return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()}, nullptr,
116 std::move(Formals));
117 consume(); // @
118 ExpectResult ER = expect(tok_id);
119 if (!ER.ok()) {
120 ER.diag().note(Note::NK_ToMachThis, TokAt.range())
121 << std::string(tok::spelling(tok_at));
122 return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()}, nullptr,
123 std::move(Formals));
124 }
125 consume(); // ID
126 auto ID = std::make_shared<Identifier>(ER.tok().range(),
127 std::string(ER.tok().view()));
128 return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()},
129 std::move(ID), std::move(Formals));
130}
131
132std::shared_ptr<ExprLambda> Parser::parseExprLambda() {
133 // expr_lambda : lambda_arg ':' expr
134 LexerCursor LCur = lCur();
135 std::shared_ptr<LambdaArg> Arg = parseLambdaArg();
136 assert(LastToken && "LastToken should be set after parseLambdaArg");
137 if (!Arg)
138 return nullptr;
139 if (ExpectResult ER = expect(tok_colon); ER.ok())
140 consume();
141
142 std::shared_ptr<Expr> Body = parseExpr();
143 if (!Body)
144 diagNullExpr(Diags, LastToken->rCur(), "lambda body");
145 return std::make_shared<ExprLambda>(LexerCursorRange{LCur, LastToken->rCur()},
146 std::move(Arg), std::move(Body));
147}
Note & note(Note::NoteKind Kind, LexerCursorRange Range)
Definition Diagnostic.h:197
Fix & fix(std::string Message)
Definition Diagnostic.h:203
Fix & edit(TextEdit Edit)
Definition Diagnostic.h:65
Lambda formal arguments.
Definition Lambda.h:58
A point in the source file.
Definition Range.h:57
std::shared_ptr< Formals > parseFormals()
std::shared_ptr< Formal > parseFormal()
std::shared_ptr< Expr > parseExpr()
Definition ParseExpr.cpp:73
std::shared_ptr< ExprLambda > parseExprLambda()
std::shared_ptr< LambdaArg > parseLambdaArg()
std::shared_ptr< LambdaArg > onLambdaArg(LexerCursorRange Range, std::shared_ptr< Identifier > ID, std::shared_ptr< Formals > F)
std::shared_ptr< Formals > onFormals(LexerCursorRange Range, FormalVector FV)
static TextEdit mkRemoval(LexerCursorRange RemovingRange)
Definition Diagnostic.h:39
static TextEdit mkInsertion(LexerCursor P, std::string NewText)
Definition Diagnostic.h:35
A token. With it's kind, and the range in source code.
Definition Token.h:55
LexerCursor lCur() const
Definition Token.h:63
tok::TokenKind kind() const
Definition Token.h:65
LexerCursorRange range() const
Definition Token.h:66
std::string_view view() const
Definition Token.h:67
Diagnostic & diagNullExpr(std::vector< Diagnostic > &Diags, LexerCursor Loc, std::string As)
constexpr std::string_view spelling(TokenKind Kind)
Definition Token.h:13
Parser for the Nix expression language.