nixd
Loading...
Searching...
No Matches
src/Parse/Parser.h
Go to the documentation of this file.
1/// \file
2/// \brief Parser for the Nix expression language.
3#pragma once
4
5#include "Lexer.h"
6
12#include "nixf/Basic/Range.h"
14
15#include <climits>
16#include <deque>
17#include <set>
18#include <stack>
19
20namespace nixf {
21
22namespace detail {
23
24Diagnostic &diagNullExpr(std::vector<Diagnostic> &Diags, LexerCursor Loc,
25 std::string As);
26
27} // namespace detail
28
29using namespace nixf::tok;
30
31class Parser {
32public:
39
40private:
41 std::string_view Src;
42 Lexer Lex;
43 Sema Act;
44 std::vector<Diagnostic> &Diags;
45
46 std::deque<Token> LookAheadBuf;
47 std::optional<Token> LastToken;
48 std::stack<ParserState> State;
49
50 /// \brief Sync tokens for error recovery.
51 ///
52 /// These tokens will be considered as the end of "unknown" node.
53 /// We create "unknown" node for recover from "extra" token error.
54 /// (Also, this node is invisible in the AST)
55 ///
56 /// e.g. { foo....bar = ; }
57 /// ^~~ remove these tokens
58 ///
59 /// Sync tokens will not be consumed as "unknown".
60 std::multiset<TokenKind> SyncTokens;
61
62 class StateRAII {
63 Parser &P;
64
65 public:
66 StateRAII(Parser &P) : P(P) {}
67 ~StateRAII() { P.popState(); }
68 };
69
70 // Note: use `auto` for this type.
71 StateRAII withState(ParserState NewState);
72
73 /// \brief Reset the lexer cursor to the beginning of the first token.
74 ///
75 /// This is used for error recovery & context switching.
76 void resetLookAheadBuf();
77
78 void pushState(ParserState NewState);
79
80 void popState();
81
82 Token peek(std::size_t N = 0);
83
84 /// \brief Consume tokens until the next sync token.
85 /// \returns The consumed range. If no token is consumed, return nullopt.
86 std::optional<LexerCursorRange> consumeAsUnknown();
87
88 class SyncRAII {
89 Parser &P;
90 TokenKind Kind;
91
92 public:
93 SyncRAII(Parser &P, TokenKind Kind) : P(P), Kind(Kind) {
94 P.SyncTokens.emplace(Kind);
95 }
96 ~SyncRAII() { P.SyncTokens.erase(P.SyncTokens.find(Kind)); }
97 };
98
99 SyncRAII withSync(TokenKind Kind);
100
101 class ExpectResult {
102 bool Success;
103 std::optional<Token> Tok;
104 Diagnostic *DiagMissing;
105
106 public:
107 ExpectResult(Token Tok) : Success(true), Tok(Tok), DiagMissing(nullptr) {}
108 ExpectResult(Diagnostic *DiagMissing)
109 : Success(false), DiagMissing(DiagMissing) {}
110
111 [[nodiscard]] bool ok() const { return Success; }
112 [[nodiscard]] Token tok() const {
113 assert(Tok);
114 return *Tok;
115 }
116 [[nodiscard]] Diagnostic &diag() const {
117 assert(DiagMissing);
118 return *DiagMissing;
119 }
120 };
121
122 ExpectResult expect(TokenKind Kind);
123
124 void consume() {
125 if (LookAheadBuf.empty())
126 peek(0);
127 popBuf();
128 }
129
130 Token popBuf() {
131 LastToken = LookAheadBuf.front();
132 LookAheadBuf.pop_front();
133 return *LastToken;
134 }
135
136 bool removeUnexpected() {
137 if (std::optional<LexerCursorRange> UnknownRange = consumeAsUnknown()) {
138 Diagnostic &D =
139 Diags.emplace_back(Diagnostic::DK_UnexpectedText, *UnknownRange);
140 D.fix("remove unexpected text").edit(TextEdit::mkRemoval(*UnknownRange));
142 return true;
143 }
144 return false;
145 }
146
147 LexerCursor lCur() { return peek().lCur(); }
148
149 /// Pratt parser for binary/unary operators.
150 std::shared_ptr<Expr> parseExprOpBP(unsigned BP);
151
152public:
153 Parser(std::string_view Src, std::vector<Diagnostic> &Diags)
154 : Src(Src), Lex(Src, Diags), Act(Src, Diags), Diags(Diags) {
155 pushState(PS_Expr);
156 }
157
158 /// \brief Parse interpolations.
159 ///
160 /// \code
161 /// interpolation : "${" expr "}"
162 /// \endcode
163 std::shared_ptr<Interpolation> parseInterpolation();
164
165 /// \brief Parse paths.
166 ///
167 /// \code
168 /// path : path_fragment (path_fragment)* path_end
169 /// Context PS_Expr PS_Path PS_Path
170 /// \endcode
171 ///
172 /// The first token, path_fragment is lexed in PS_Expr context, then switch in
173 /// "PS_Path" context. The ending token "path_end" shall be poped with context
174 /// switching.
175 std::shared_ptr<Expr> parseExprPath();
176
177 /// \code
178 /// string_part : interpolation
179 /// | STRING_PART
180 /// | STRING_ESCAPE
181 /// \endcode
182 std::shared_ptr<InterpolatedParts> parseStringParts();
183
184 /// \code
185 /// string : " string_part* "
186 /// | '' string_part* ''
187 /// \endcode
188 std::shared_ptr<ExprString> parseString(bool IsIndented);
189
190 /// \code
191 /// '(' expr ')'
192 /// \endcode
193 std::shared_ptr<ExprParen> parseExprParen();
194
195 /// \code
196 /// attrname : ID
197 /// | string
198 /// | interpolation
199 /// \endcode
200 std::shared_ptr<AttrName> parseAttrName();
201
202 /// \code
203 /// attrpath : attrname ('.' attrname)*
204 /// \endcode
205 std::shared_ptr<AttrPath> parseAttrPath();
206
207 /// \code
208 /// binding : attrpath '=' expr ';'
209 /// \endcode
210 std::shared_ptr<Binding> parseBinding();
211
212 /// \code
213 /// inherit : 'inherit' '(' expr ')' inherited_attrs ';'
214 /// | 'inherit' inherited_attrs ';'
215 /// inherited_attrs: attrname*
216 /// \endcode
217 std::shared_ptr<Inherit> parseInherit();
218
219 /// \code
220 /// binds : ( binding | inherit )*
221 /// \endcode
222 std::shared_ptr<Binds> parseBinds();
223
224 /// attrset_expr : REC? '{' binds '}'
225 ///
226 /// Note: peek `tok_kw_rec` or `tok_l_curly` before calling this function.
227 std::shared_ptr<ExprAttrs> parseExprAttrs();
228
229 /// \code
230 /// expr_simple : INT
231 /// | ID
232 /// | FLOAT
233 /// | string
234 /// | indented_string
235 /// | path
236 /// | spath
237 /// | hpath
238 /// | uri
239 /// | '(' expr ')'
240 /// | legacy_let
241 /// | attrset_expr
242 /// | list
243 /// \endcode
244 std::shared_ptr<Expr> parseExprSimple();
245
246 /// \code
247 /// expr_select : expr_simple '.' attrpath
248 /// | expr_simple '.' attrpath 'or' expr_select
249 /// | expr_simple 'or' <-- special "apply", 'or' is argument
250 /// | expr_simple
251 /// \endcode
252 std::shared_ptr<Expr> parseExprSelect();
253
254 /// \code
255 /// expr_app : expr_app expr_select
256 /// | expr_select
257 /// \endcode
258 ///
259 /// Consume at most \p Limit number of `expr_select` as arguments
260 /// e.g. `Fn A1 A2 A3` with Limit = 2 will be parsed as `((Fn A1 A2) A3)`
261 std::shared_ptr<Expr> parseExprApp(int Limit = INT_MAX);
262
263 /// \code
264 /// expr_list : '[' expr_select* ']'
265 /// \endcode
266 std::shared_ptr<ExprList> parseExprList();
267
268 /// \code
269 /// formal : ,? ID
270 /// | ,? ID '?' expr
271 /// | ,? ...
272 /// \endcode
273 std::shared_ptr<Formal> parseFormal();
274
275 /// \code
276 /// formals : '{' formal* '}'
277 /// \endcode
278 std::shared_ptr<Formals> parseFormals();
279
280 /// \code
281 /// lambda_arg : ID
282 /// | ID @ {' formals '}'
283 /// | '{' formals '}'
284 /// | '{' formals '}' @ ID
285 /// \endcode
286 std::shared_ptr<LambdaArg> parseLambdaArg();
287
288 /// \code
289 /// expr_lambda : lambda_arg ':' expr
290 /// \endcode
291 std::shared_ptr<ExprLambda> parseExprLambda();
292
293 std::shared_ptr<Expr> parseExpr();
294
295 /// \brief Parse binary/unary operators.
296 /// \code
297 /// expr_op : '!' expr_op
298 /// | '-' expr_op
299 /// | expr_op BINARY_OP expr_op
300 /// | expr_app
301 ///
302 /// %right ->
303 /// %left ||
304 /// %left &&
305 /// %nonassoc == !=
306 /// %nonassoc < > <= >=
307 /// %right //
308 /// %left NOT
309 /// %left + -
310 /// %left * /
311 /// %right ++
312 /// %nonassoc '?'
313 /// %nonassoc NEGATE
314 /// \endcode
315 std::shared_ptr<Expr> parseExprOp() { return parseExprOpBP(0); }
316
317 /// \code
318 /// expr_if : 'if' expr 'then' expr 'else' expr
319 /// \endcode
320 std::shared_ptr<ExprIf> parseExprIf();
321
322 /// \code
323 /// expr_assert : 'assert' expr ';' expr
324 /// \endcode
325 std::shared_ptr<ExprAssert> parseExprAssert();
326
327 /// \code
328 /// epxr_let : 'let' binds 'in' expr
329 /// \endcode
330 std::shared_ptr<ExprLet> parseExprLet();
331
332 /// \code
333 /// expr_with : 'with' expr ';' expr
334 /// \endcode
335 std::shared_ptr<ExprWith> parseExprWith();
336
337 /// Top-level parsing.
338 std::shared_ptr<Expr> parse();
339};
340
341} // namespace nixf
Lexer declaration. The lexer is a "stateful" lexer and highly tied to parser.
Semantic Actions while building the AST.
Fix & fix(std::string Message)
Definition Diagnostic.h:203
Fix & edit(TextEdit Edit)
Definition Diagnostic.h:65
A point in the source file.
Definition Range.h:57
std::shared_ptr< Formals > parseFormals()
std::shared_ptr< ExprParen > parseExprParen()
std::shared_ptr< Expr > parse()
Top-level parsing.
std::shared_ptr< Formal > parseFormal()
std::shared_ptr< ExprLet > parseExprLet()
std::shared_ptr< Interpolation > parseInterpolation()
Parse interpolations.
std::shared_ptr< ExprAssert > parseExprAssert()
std::shared_ptr< Expr > parseExprOp()
Parse binary/unary operators.
std::shared_ptr< Expr > parseExpr()
Definition ParseExpr.cpp:73
std::shared_ptr< Inherit > parseInherit()
std::shared_ptr< ExprLambda > parseExprLambda()
Parser(std::string_view Src, std::vector< Diagnostic > &Diags)
std::shared_ptr< AttrName > parseAttrName()
Definition ParseAttrs.cpp:6
std::shared_ptr< InterpolatedParts > parseStringParts()
std::shared_ptr< Expr > parseExprApp(int Limit=INT_MAX)
Definition ParseExpr.cpp:52
std::shared_ptr< ExprString > parseString(bool IsIndented)
std::shared_ptr< Expr > parseExprSelect()
Definition ParseExpr.cpp:6
std::shared_ptr< Expr > parseExprPath()
Parse paths.
std::shared_ptr< Expr > parseExprSimple()
std::shared_ptr< ExprWith > parseExprWith()
std::shared_ptr< ExprIf > parseExprIf()
std::shared_ptr< AttrPath > parseAttrPath()
std::shared_ptr< ExprList > parseExprList()
std::shared_ptr< LambdaArg > parseLambdaArg()
std::shared_ptr< ExprAttrs > parseExprAttrs()
std::shared_ptr< Binds > parseBinds()
std::shared_ptr< Binding > parseBinding()
void tag(DiagnosticTag Tag)
Definition Diagnostic.h:96
static TextEdit mkRemoval(LexerCursorRange RemovingRange)
Definition Diagnostic.h:39
A token. With it's kind, and the range in source code.
Definition Token.h:55
LexerCursor lCur() const
Definition Token.h:63
Diagnostic & diagNullExpr(std::vector< Diagnostic > &Diags, LexerCursor Loc, std::string As)